August 16

React Native: A full new application, Nature Tracker!

Hi again! Been a while since last time, but I promise you it has been worth it! So I knew that last time I said I would take a look at PHP and Laravel next, but turns out I lied… a little.

I did finish the PHP course on SoloLearn!

But my dad came to me with a pretty good app idea that I wanted to make for his birthday! The idea is an app where you can easily keep track of various stuff you find out in the nature. We both sat down and designed the app, and I got to work as soon as I got home!

After spending around 8 workdays on it, I ended up with this:

The app works like this: You have a big map (provided by Google Maps and react-native-maps) you can drag around or search for a specific location, and place markers on. To place a marker, you simply have to drag and drop one of the markers from the left side. Like this:

Now the user just need to put in a description of the marker (if they want to), and a marker is created!

If the user now taps the marker, it will show the marker name, description, how far away the marker is (it’s also updating the distance in real time!), the ability to delete it and also buttons to open Google Maps for plotting a route towards it!

The user can press the “Marks” button at the bottom to open a modal that shows a list of all the markers. The user can then press one of the markers to be brought to it on the map:

The settings screen allows the user to switch between English and Norwegian language, and adjust the icon sizes.

And that’s it! If you want to try out the app then it’s available on Google Play now!

There’s still some features that could be implemented, stuff that could be optimized, but overall I’m pretty happy with what I’ve accomplished in the 8 days I worked on the app. The challenges I’ve had with this app was learning how to deal with react-native-maps and Google Maps, localization and focusing more on performance based coding (using async functions, and just better code overall).

Thanks for reading!

August 2

React Native: ToDo App

So the time as finally come… To make a React Native app! This app will just be a “port” of my previous ToDo app, which means it will take advantage of the database (MySQL) and API (Node.js + Express) that I made previously. Let’s begin! Note: I’ve made some big refactor changes since the React.js, but the app’s logic still functions the same.

While React.js is considered a JavaScript library for making websites, React Native is seen as a framework for building native apps for both Android and iOS. React Native works a lot like React.js, but it has some differences. First order of business was to learn more about those differences. I scouted on YouTube to find some tutorial videos to watch. I found The Net Ninja React Native tutorial series and binged watched a lot of them. After a while I felt confident with making my ToDo app.

Two of the biggest differences between React and React Native is that React Native doesn’t use CSS, but something called styles and “StyleSheets” to mimic CSS. The other one is that React Native uses different tags than React. Example, instead of “div”, you have “View”. You also just can’t type out text to be rendered. You have to use the “Text” tag.

Now let’s really begin! This is how the final app looks like:

Since the app has a lot of similarities to the React app, I won’t be covering the parts that are the same. Just know that we have functions to communicate with an API. All of the code can be viewed through the GitHub page.

The only thing different in the App.js file is how the render function and a StyleSheet object in the bottom of the file, instead of a CSS file:


...

  render() {
    return (
      // Body container
      <View style={styles.body} >
        <StatusBar style="auto" />
        <Header />

        {/* Main  */}
        <ScrollView style={styles.wrapper} contentContainerStyle={{ paddingBottom: 80 }} showsVerticalScrollIndicator={false} >

          {/* Shows all todos from state.todos */}
          {this.state.todos.map(toDo => {
            return <ToDo key={toDo.id} id={toDo.id} desc={toDo.desc} completed={toDo.completed} setAsCompleted={this.setAsCompleted} remove={this.removeToDo} />
          })}

        </ScrollView>

        {/* Menu and button that allows user to add new ToDos */}
        <AddToDo addToDo={this.addToDo} />

        <Footer />

      </View>
    );
  }
}

const styles = StyleSheet.create({

  body: {
    flex: 1,
    backgroundColor: '#ccc',

  },

  wrapper: {
    width: '95%',
    height: 100,

    marginLeft: 'auto',
    marginRight: 'auto',

    marginTop: 'auto',
    marginBottom: 5,

  },
});

Here you can see that I use “View” tags instead of “div”. The main difference is that in React Native we can use a ScrollView for our list of ToDos. Every object we place in React Native is set in a kind off “fixed position”, but with ScrollView we can have a scrollable space, like this:

The styling syntax is also really similar to CSS. The main difference is that here we use “camelCase” notation instead of using hyphens. Styles also have a fewer properties and values to use, but they usually do the job very well. It’s also worth nothing that we can only choose “flex” or “none” values in the “display” property, unlike CSS which has many values to choose between. However, flex is extremely strong and… well, flexible.

Since we don’t have access to CSS we have to do animations a different way too. Here’s how I did it for my “widen animation” for the ToDo component:

First I create the animation object in my state and also an interpolate var. This transform the value from 0-1 to 0%-100%, so I can use it for the CSS styling.


    state = {
        widenAnim: new Animated.Value(0),
    };

    interpolateWidth = this.state.widenAnim.interpolate({inputRange:[0,1],outputRange:['0%','100%']});

Next I create a function for starting the animation and call it when the component mounts:


    widen = () => {
        Animated.spring(this.state.widenAnim, {
            toValue: 1,
            useNativeDriver: false
        }).start();
    };

    componentDidMount() {
        this.widen();
    }

The spring function creates a spring-like animation. It has a lot of different properties we can change, but that wasn’t needed for what I wanted.

Last piece of the puzzle is to connect our animation to our render function. To make the entire component be effected by the animation I have to wrap it all up in a “Animated.View” tag, and make a style which is connected to the animation values. This is how the render function ended up like:


render() {

        // Destructure props
        const { id, desc, completed } = this.props;

        // Decides if the text should be shown with a lined-through effect
        let descStyle = completed ? [styles.component_todo_desc, styles.lined_through] : styles.component_todo_desc;

        return (
            <Animated.View style={{ opacity: this.state.fadeInAnim, width: this.interpolateWidth }}>
                <TouchableOpacity style={styles.component_todo} onPressIn={() => this.props.setAsCompleted(id)}>
                    {/* Main component ToDo div */}
                    <View style={{ flexDirection: "row", }}>
                        {/* Checkmark */}
                        <View style={styles.component_todo_checkmark_box} />
                        {completed ? <Text style={styles.component_todo_checkmark_check}>&#10003;</Text> : <Text />}

                        {/* Show desc text */}
                        <Text style={descStyle}>{desc}</Text>
                    </View>

                    {/* Delete button */}
                    <TouchableOpacity style={styles.component_todo_delete_button} onPressIn={() => this.props.remove(id)}>
                        <Entypo name="cross" size={48} color='rgb(90, 0, 0)' style={{textAlign:'center'}} />
                    </TouchableOpacity>

                </TouchableOpacity>
            </Animated.View>
        )
    }

Also, to create a touchable component we need to use the tag “TouchableOpacity” instead of Button.

I also made a fade in animation to go along with the widen animation. This is how it ended up like:

And that’s it! A port of the React ToDo app over to React Native, using MySQL as a database and Node.js + Express as an API. My goal for the summer was to create a full stack React Native application, and even though I’m happy about the app there’s still a lot more I need to go through (like React Navigation, etc…), but that will have to be for another time!

Currently I’m looking at trying to create an API using PHP and the Laravel framework instead, so stay tuned for that!

Category: Blog | LEAVE A COMMENT
July 26

Full Stack: ToDo App with MySQL, Node.js, Express and React

So I had two goals for this summer, Build a full stack app and make a React Native app. Using a stack of MySQL, Node.js, Express and React I managed to build a full stack ToDo app! In this blog post I’ll show you how I did it!

The whole app works like this: I have a MySQL database where I store all my ToDos. Using Node.js and Express (a web application framework) I made a REST API that will allow my React front end to communicate with the MySQL database. And, of course, React as the front end.

Here’s how the React front end app ended up looking!

So, for the SQL server I could use either MySQL or MongoDB. I decided to use MySQL since I already have a lot of experience with it through school. MySQL is maintained by Oracle, and is both open-sourced and free to use! MySQL runs in the background of your computer and you can give it commands through the CMD to manage your database, but I strongly recommend downloading MySQL Workbench so you can get a nice GUI to use instead. I won’t go into depth about how I made my database here.

The ToDo table from MySQL Workbench

Now, for the API I decided to use Node.js and Express. They are also both free to use and very popular. For those that don’t know, Node.js is JavaScript runtime built using Chrome’s V8 JavaScript Engine. Basically, JavaScript usually only runs through a browser, but with Node.js we can run it without one. Express is a web app framework for Node.js. It makes creating APIs so much easier.

So first up is the entry point “server.js” file:

// Init
const express = require('express');
const bodyParser = require("body-parser");
const cors = require('cors');

// Set up a const for express and a port
const app = express();
const port = 3000;

// Init connection to database
const db = require('./db');

// Middleware
app.use(cors());
app.use(bodyParser.json());

// Routers
const todoRouter = require('./routes/todo.route');

// Use routers
app.use('/todo', todoRouter);

// Start listening/server
app.listen(port, () => console.log(`ToDo API listening on port ${port}...`));

First I import express itself, body-parser (used for taking the body information from a POST and making it accessible for the API) and CORS (which is used for being able to skip the Same-origin policy, which means we can connect with remote hosts to the API). Next is setting up express and a port to use with it. After that I set up something called “Middleware”. They are basically functions that gets called when the API receive a request and can manipulate the request object from the user and the response object from the API. We have to set both cors and body-parser as middleware for them to work. Next, I set up “routers” for my todos. I need to research routers a little more, but they let me organize my routes into a different file.

For connecting the API to my database I have a file called “db.config.js” which handles the settings:

module.exports = {
  HOST: "localhost",
  USER: "root",
  PASSWORD: "PASSWORD",
  DB: "tododb"
};

And then a “db.js” for connecting to the database:

const mysql = require("mysql");
const dbConfig = require("./config/db.config.js");

// Create a connection to the database
const connection = mysql.createConnection({
  host: dbConfig.HOST,
  user: dbConfig.USER,
  password: dbConfig.PASSWORD,
  database: dbConfig.DB
});

// open the MySQL connection
connection.connect(error => {
  if (error) throw error;
  console.log("Successfully connected to the database!...");
});

module.exports = connection;

Here I just create a connection using a MySQL library for Node.js, and export it so that the route files can use it.

Last up is the route file for ToDo. This is the code that’s gonna handle the HTTP request and responses for the ToDos. I’m not gonna show the entire file since it’s quite big, but all of the functions looks quite the same. It can be viewed through the GitHub page.

const express = require('express'),
    router = express.Router(),
    db = require('../db');

// Get one ToDo
router.get('/:todoId', function (req, res) {
    let sql = `SELECT * FROM todo WHERE id = ${req.params.todoId}`;

    db.query(sql, function (err, data, fields) {
        if (err) return res.status(400).send(err);

        if(Object.keys(data).length === 0) return res.status(404).send(`404: ToDo with id: ${req.params.todoId} not found.`);

        res.json({
            data,
            message: "ToDo retrieved successfully"
        })
    });
});

First, I’m importing express, the router and the db (database connection). I can now add functions that handles “Get”, “POST”, “Put” and “Delete” requests for my ToDos. In the code above I handle a Get request for getting a single specific ToDo from the database. Using “db” I can send a query to my database and use it in the callback function. From the callback function I can check if it’s empty (and in case return a HTTP status code 404: Not found) or send the data it found as a JSON object back to the React client.

And that’s it for the back-end. My API isn’t the best right now, but I’m planning to add JWT security and rewrite it so that it uses the information from the body of an HTTP request.

Now for the front-end. I’ve covered making React apps some times now, so for this blog post I’m only gonna focus on what’s related to the full-stack part.

First, in my constructor I add a var for my API Url:


  constructor(props) {
    super(props)

    this.apiURL = "http://localhost:3000";

    this.state = {
      todos: []
    }
  }
Then when my App starts I run a function called "getTodos" which sends a HTTP request to my API and (hopefully) receives some ToDos back, and sets the state:


// When the app starts, get todos from the database and set it to the state
  componentDidMount() {
    this.getTodos();
  }

  getTodos() {
    fetch(`${this.apiURL}/todo`)
      .then(res => res.json())
      .then((data) => {

        let todos = data.data;

        // Convert 'completed' from 0's to bools
        for (let i = 0; i < todos.length; i++) {
          todos[i].completed = (todos[i].completed === 0) ? false : true;
        }

        // Set todos in the state
        this.setState({ todos })
      })
      .catch(console.log)
  }

Since MySQL doesn't support straight up boolean values, I use 0's and 1's as false and true. That's why I convert the "completed" value from those 0's and 1's to bool's.

Now for adding a new ToDo:


  // Adds a new ToDo
  addToDo = desc => {
    fetch(`${this.apiURL}/todo?desc="${desc}"&completed=0`, { "method": "POST" })
      .then(res => res.json())
      .then((data) => {

        //Refresh ToDos
        this.getTodos();

      })
      .catch(console.log)

  }

I send a POST request with the new ToDos description in the query and a completed value of zero. The id is being set server side, so my client app doesn't need to set it itself. In the callback function I could receive the id back and just add a new ToDo object to my array, but I decided to take the lazy way and just refresh all ToDos from my database.

The delete and update (setAsComplete) functions are quite similiar:


// Marks a ToDo as completed
  setAsCompleted = id => {
    // Get the selected todo
    let editedToDo = this.state.todos.find(todo => todo.id === id);

    // Flip the completed value and return it as a number
    editedToDo.completed = editedToDo.completed ? 0 : 1;

    fetch(`${this.apiURL}/todo?id=${editedToDo.id}&desc="${editedToDo.desc}"&completed=${editedToDo.completed}`, { "method": "PUT" })
      .then(res => res.json())
      .then((data) => {

        //Refresh ToDos
        this.getTodos();

      })
      .catch(console.log)
  }

  // Removes ToDo
  removeToDo = id => {
    fetch(`${this.apiURL}/todo/${id}`, { "method": "DELETE" })
      .then(res => res.json())
      .then((data) => {

        //Refresh ToDos
        this.getTodos();

      })
      .catch(console.log)
  }

And that's it! A full working full-stack ToDo application!

This image has an empty alt attribute; its file name is image-8.png

My next plan is to port over my client React app to React Native, so stay tuned for that!

July 20

Periodic Table with React

Hi again! So when I was working on my calculator I realized I needed more practice with CSS, especially grids. While researching I came across this blog post, where they make a Periodic Table with React. I felt inspired to do the same. It would be a nice way to practice on my CSS skills! Apologies for the short blog post, since I’m on a little time crunch here!

I planned my app to work like this: It would show all of the elements like the Periodic Table, and if you hover over one them it will show an info screen at the bottom. The data would be imported through a JSON file which was created by “Bowserinator” and can be downloaded from his GitHub page. This is how to final product looks like:

Making the React components themselves was an easy task. I first created an “Element” component that got it’s element number as a prop, and then loads the corresponding element data from the JSON file.


export class Element extends Component {

    constructor(props) {
        super(props)

        //Make sure it's not the '57-71' or '89-103'
        if (!props.notElement) {

            //Get the right element data from the JSON file
            let element = dataFile.elements.filter(e =>
                e.number === props.nr
            );

            //Set the data
            this.state = {
                element: element[0]
            }
        }
    }


    render() {
        if (!this.props.notElement) {
            // Show element
            const { element } = this.state;

            return (
                <div className={`component-element element-${element.number} ${element.category}`} onMouseOver={() => this.props.handler(element)}>
                    <div className="number">{element.number}</div>
                    <div className="symbol">{element.symbol}</div>
                </div>
            )
        } else {
            // Show '57-71' or '89-103'
            return (
                <div className={`component-element short${this.props.nr}`}>
                    <div className="number">{this.props.nr}</div>
                </div>
            )
        }
    }
}

To make the periodic table layout I created a CSS class like this:


  .table-elements {
    display: grid;
    grid-template-columns: repeat(17, auto) 1fr;
  }

First I need to set the display to be grid, and then I create a grid with 18 columns.

Since I’m going to have my Periodic Table with the middle elements by itself under (like most periodic tables do), I had to create an additional grid with 14 rows:


  .table-elements-extra {
    display: grid;
    grid-template-columns: repeat(14, auto) 1fr;

    padding-top: 5%;

    margin-left: auto;
    margin-right: auto;

    width: 80%;
  }

Using margin-left and margin-right I can center the additional grid.

To make sure the elements get positioned correctly I made some CSS classes that set the grid’s column starting point:


.element-2 {
    grid-column-start: 18;
}

.element-5, .element-13 {
    grid-column-start: 13;
}

The number corresponds to the element number. Since I have:


<div className={component-element element-${element.number} ${element.category}}

in my Element component, it automatically applies the correct CSS class to the elements with the number. I also use category for setting the elements background color.

In my App component I create several list’s with just numbers in them:


  constructor(props) {
    super(props)

    this.createElements();

    this.state = {
      selectedElement: null
    }
  }

  createElements() {
    this.elements_1To56 = [];
    this.elements_57To71 = [];
    this.elements_72To88 = [];
    this.elements_89To103 = [];
    this.elements_104To118 = [];

    for (let i = 1; i <= 56; i++) this.elements_1To56.push(i);
    for (let i = 57; i <= 71; i++) this.elements_57To71.push(i);
    for (let i = 72; i <= 88; i++) this.elements_72To88.push(i);
    for (let i = 89; i <= 103; i++) this.elements_89To103.push(i);
    for (let i = 104; i <= 118; i++) this.elements_104To118.push(i);
  }

The reason I do several lists is because I have to divide the table into multiple parts. This makes it easier to create the table.

To render them I have to use the map function to iterate through the lists:


render() {

    return (
      <div className="wrapper">

        <h1>Periodic Table</h1>

        <div className="table-elements">

          {/* Elements 1 - 56 */}
          {this.elements_1To56.map((element, index) => {
            return <Element handler={this.setActiveElement} key={element} nr={element} />
          })}

          <Element nr="57-71" notElement />

          {/* Elements 57 - 71 */}
          {this.elements_72To88.map((element, index) => {
            return <Element handler={this.setActiveElement} key={element} nr={element} />
          })}

          <Element nr="89-103" notElement />

          {/* Elements 104 - 118 */}
          {this.elements_104To118.map((element, index) => {
            return <Element handler={this.setActiveElement} key={element} nr={element} />
          })}

        </div>

        <div className="table-elements-extra" >
          {/* Elements 57 - 71 */}
          {this.elements_57To71.map((element, index) => {
            return <Element handler={this.setActiveElement} key={element} nr={element} />
          })}

          {/* Elements 89 - 103 */}
          {this.elements_89To103.map((element, index) => {
            return <Element handler={this.setActiveElement} key={element} nr={element} />
          })}
        </div>

It looks a little ugly, but it’s a lot better than having 118 lines for each element.

Last, I want to have a Info bar at the bottom that shows info about the element that’s currently being hovered over. The component takes an Element object, that has the data from the JSON file, as a prop.


export class InfoBar extends Component {
    render() {
        if (this.props.element !== null) {
            const { element } = this.props;

            return (
                <div className="info-bar">

                    <div className="element-short-info-container">
                        {/* Show element box */}
                        <div className={`component-element big ${element.category}`}>
                            <div className="number-big">{element.number}</div>
                            <div className="symbol-big">{element.symbol}</div>
                        </div>

                        <div className="element-mass">Mass: {element.atomic_mass}u</div>
                        <div className="element-electron">Category: {element.category}</div>
                    </div>

                    {/* Element name */}
                    <div className="element-info-container">
                        <div className="element-name">{element.name}</div>
                        <div className="element-desc">{element.summary}</div>
                    </div>
                </div>
            )
        } else {
            return <div> </div>
        }
    }
}

The last thing to do is add a hover handler for our elements in our App component that I will pass down to the elements as a prop:


  setActiveElement = element => {
    this.setState({
      selectedElement: element
    })
  }

And it’s done!

I’m really happy about how the project ended up. I got to practice the things I needed and learned a lot more about CSS and styling. I can already feel that I’m getting a lot more confident with React as well, since the project only took so little time to make. Most of it went into learning CSS.

Here’s the link to the GitHub page! I’m also gonna research how I can upload live demos from my demos!

Thanks for reading!

Category: ReactJS | LEAVE A COMMENT
July 16

Calculator with React Pt. 2:

So, I’ve made some huge changes since part 1. Since I’ve redesigned how the calculator looks and how it works, I’ve decided to just make a blog post about the finished calculator and how it works. Code is available on Github.

So first I needed to make it look better. Even though I think we all can appreciate that good ol’ Windows 98 look, it needed to be better. So this is how it looked before:

Animated GIF

And this is how it looks now! Even got a division button!

I won’t go into depth about how I made it look like that, but the CSS files are available on the GitHub page!

So let me show you how I made this!

First I make a state in my main App:


export default class App extends React.Component {

  constructor(props) {
    super(props)

    this.state = {

      isNumber1: true,
      number1: "0",
      operator: "",
      number2: "0"

    }
  }

I’m going to use the “isNumber1” bool to check if the user is inputting on the first or second number. “number1” and “number2” is for holding our input numbers and operator is for deciding what operation we are gonna do.

The “Button” component I created in part 1 is still mostly the same. I only added support for orange color and made the render function return only the button, so the the CSS grid would work with my buttons. I use the CSS grid to layout my buttons. Here’s the “Button” component:

Full code for Button component

import React, { Component } from 'react'
import propTypes from 'prop-types'
import './Button.css';

class Button extends Component {

    constructor(props) {
        super(props);

        this.buttonValue = props.buttonValue;

        //Set Button styling
        let p = props;

        this.className = "component-button";

        //Wide or small
        if (p.wide) {
            this.className += " wide"
        } else if (p.small) {
            this.className += " small";
        }

        //Colors
        // eslint-disable-next-line default-case
        switch (p.color) {
            case "blue":
                this.className += " blue";
                break;

            case "red":
                this.className += " red";
                break;

            case "orange":
                this.className += " orange";
                break;

        }

    }

    render() {
        return <button className={this.className} onClick={() => this.props.clickHandler(this.buttonValue)} >{this.buttonValue}</button>

    }
}

// Prop types
Button.propTypes = {
    wide: propTypes.bool,
    color: propTypes.string
}


export default Button

[collapse]

In part 1 I made a main clickHandler that I passed to every Button component, and it just decided what other handler to call depending on the button value it recieved. But I figured, why do that? I can just pass the correct clickHandler as a prop to the different Button components. That way it’s both cleaner, easier and I get rid of an entirely useless function.

I also changed how I added numbers to the calculator. Before I would multiply the current number with 10 and add whatever button value that was pressed, but since this is JavaScipt (a loosely typed language) I can just treat the number as a string until I need to do any calculation with it! Because of that, I can just add the button value as a string to the number. Easy! I also refactored how I check which number to add it to, by using a ternary operator and a new trick I found for the “setState” function.


  addNumber = number => {

    // Decide which number should be changed
    let changeNumber = this.state.isNumber1 ? "number1" : "number2";

    let newNumber = 0;

    // Check if a zero should be replaced by a number
    if (this.state.isNumber1) {
      newNumber = (this.state.number1 === "0") ? number.toString() : this.state.number1 + number.toString();
    } else {
      newNumber = (this.state.number2 === "0") ? number.toString() : this.state.number2 + number.toString();
    }

    // Change number
    this.setState({
      [changeNumber]: newNumber,
    });

  }

As you can see, I also check if the number is only a zero, and if it should be replaced by a number.

Next up, the click handlers for the operator buttons and AC. These are simply just setting the state of the App.


// Set the operator
  setOperator = operator => {
    this.setState({
      operator,
      isNumber1: false
    });
  }

  // AC Button - All Clear
  allClear = () => {
    this.setState({
      isNumber1: true,
      number1: "0",
      operator: "",
      number2: "0"
    });
  }

For adding the ability to add a decimal I can mainly do the same thing I did for adding a number, just add a “.” behind the number. I also make sure to check if there’s any periods in the number beforehand, and then in-case exiting the function.


  // Adds a "." to the number
  addDecimal = number => {

    // Decide which number to change
    let changeNumber = this.state.isNumber1 ? "number1" : "number2";

    // If the number already contains a '.' then just exit the function
    if (this.state.isNumber1) {
      if (this.state.number1.includes('.')) return;
    } else {
      if (this.state.number2.includes('.')) return;
    }

    // Get the new number to set
    let newNumber = this.state.isNumber1 ? this.state.number1 + "." : this.state.number2 + ".";

    // Set the number
    this.setState({
      [changeNumber]: newNumber
    });
  }

To make the Backspace click handler, I use substring (remember, I treat numbers as string) to get a new string without it last’s char.


  removeLast = () => {
    let number = this.state.isNumber1 ? this.state.number1 : this.state.number2;
    let changeNumber = this.state.isNumber1 ? "number1" : "number2";

    //Make a new number without the last char/number
    number = number.substring(0, number.length - 1);

    //Update the state
    this.setState({
      [changeNumber]: number
    });

  }

The equal button click handler is quite simple:


  //Solves the equation
  equals = () => {
    let operator = this.state.operator;

    let number1 = Number(this.state.number1);
    let number2 = Number(this.state.number2);
    let answer = 0;

    if (operator === "+") {
      answer = number1 + number2;
    } else if (operator === "-") {
      answer = number1 - number2;
    } else if (operator === "x") {
      answer = number1 * number2;
    } else if (operator === "/") {
      answer = number1 / number2;
    }

    this.setState({
      isNumber1: true,
      number1: answer.toString(),
      operator: "",
      number2: "0"
    });

  }

All the click handler’s are done. Now we need a number screen to show what’s happening. For this, I made a “NumberScreen” component which takes in the two numbers and the operator as a prop, and show’s it in the render function.


class NumberScreen extends Component {
    render() {
        //Destructering
        const { number1, operator, number2 } = this.props;

        //if number2 doesn't contain anything other than zero, don't show it
        let displayValue = (number2 === "0") ? number1 + operator : number1 + operator + number2;

        return (
            <div>
                <input className="number-screen" disabled value={displayValue} />
            </div>
        )
    }
}

Last, we just need to put the pieces together in our App’s render function:


render() {
    return (
      <div className="calculator">

        <p className="logo-text">My React Calculator</p>
        {/* Number Screen */}
        <NumberScreen number1={this.state.number1} operator={this.state.operator} number2={this.state.number2} />

        <div className="calculator-buttons">
          {/* Row 5 */}
          <Button buttonValue="AC" clickHandler={this.allClear} wide color="red" />
          <Button buttonValue="←" clickHandler={this.removeLast} color="red" />
          <Button buttonValue="/" clickHandler={this.setOperator} color="orange" />

          {/* Row 4 */}
          <Button buttonValue="7" clickHandler={this.addNumber} />
          <Button buttonValue="8" clickHandler={this.addNumber} />
          <Button buttonValue="9" clickHandler={this.addNumber} />
          <Button buttonValue="x" clickHandler={this.setOperator} color="orange" />

          {/* Row 3 */}
          <Button buttonValue="4" clickHandler={this.addNumber} />
          <Button buttonValue="5" clickHandler={this.addNumber} />
          <Button buttonValue="6" clickHandler={this.addNumber} />
          <Button buttonValue="-" clickHandler={this.setOperator} color="orange" />

          {/* Row 2 */}
          <Button buttonValue="1" clickHandler={this.addNumber} />
          <Button buttonValue="2" clickHandler={this.addNumber} />
          <Button buttonValue="3" clickHandler={this.addNumber} />
          <Button buttonValue="+" clickHandler={this.setOperator} color="orange" />

          {/* Row 1 */}
          <Button buttonValue="0" wide clickHandler={this.addNumber} />
          <Button buttonValue="," clickHandler={this.addDecimal} />
          <Button buttonValue="=" clickHandler={this.equals} color="blue" />

        </div>
      </div>
    );
  }

As I said earlier, it would be better to have the buttons in it’s own component for organizing and just better programming, but it works for this little project.

And that’s it! I’m really happy about how this project turned out, but I do have some regrets. The biggest one being how I’m deciding what number to add to. I think I could have come up with a better way to deal with that, but that will have to be for another time!

Thanks for reading!

GitHub Link

Category: ReactJS | LEAVE A COMMENT
July 13

Sudoku Solver with React

Hi again! So I was on a cabin trip this weekend, and after solving countless amount of Sudoku I thought: “Hey, I could port over one of my old Sudoku Solver projects to React!”. I made one previous in C#, but the interface was just a terminal (“Ew…” I know). With React being made for creating UIs this proved to be a perfect project!

Usually I create the blog post while I’m making the projects, but this time I made the application first. So I won’t be going so in-depth in this blog post on how to make it, but the code will however, as always, be available!

So this is how the “Sudoku Solver” looks like:

Just enter the unsolved Sudoku into the cells, hit the “Solve” button… and voila!

This is how I made it:


class App extends Component {

  constructor(props) {
    super(props)

    //Set our sudoku size
    this.width = 9;
    this.height = 9;

    this.state = {
      board: this.createBoard(this.width, this.height),     //Our sudoku board
      invalidSudoku: false                                  //If the sudoku in the board is valid
    }

  }

First making it so that the “App” has a state with two variables. One for the board (2D Array) and one for if the input Sudoku is valid (bool). “createBoard” just returns a 2D Array (an array with arrays) with 0’s.

Next I made a handler for when one of the numbers in a “Cell” (where the user can put in a number) changes:


  //Changes the value in the state board
  changeValue = (i, j, num) => {

    //Create a copy of our current board
    let newBoard = this.state.board;
    newBoard[i][j] = num;

    //Update our state with the new board
    this.setState({
      board: newBoard,
      invalidSudoku: false                  //Since the sudoku changed we can set invalid to be false
    }, () => {
      this.setState({ state: this.state }); //Force a re-render after it's done with setting the state
    });
  }

Here I take three vars. “i” and “j” to know which spot we are changing, and the “num” put in. When you change the state in React, you have to use the “setState” method, so that React knows that it has to re-render the component. “setState” is done async ,so to show the state change immediately after the change is done we have to use the “setState’s” second parameter to give it a callback function. Setting another “setState” in the callback function will force it to re-render the component after the previous state has been updated. An inefficient (since it re-renders twice now), but good enough trick for this project.

Now if the user clicks the “Submit” button I run this function through the clickHandler:


  solve = () => {

    //Create a solvedBoard from the Solver class. It either returns as an 2D-array or bool
    let solvedBoard = new Solver(this.state.board);

    //If it's an array then it should be a valid solution. Set it as the current board
    if (Array.isArray(solvedBoard)) {
      this.setState({
        board: solvedBoard,
      }, () => {
        this.setState({ state: this.state }); //Force re-render
      });
    }else{
      //If it's not a valid array, then it's not a valid sudoku.
      this.setState({
        invalidSudoku: true                   //Set it as an invalid sudoku          
      }, () => {
        this.setState({ state: this.state }); //Force re-render
      });
    }
  }

I haven’t shown the Solver yet (I will do that after the React stuff), but know that in the constructor it either returns false if it didn’t find a solution or the sudoku is invalid, or a board if it succeeds. If it succeeds then we update the state with the solved board, and force a re-render!

The App’s render function looks like this:


  render() {
    return (
      <div className="App">

        <h1>Sudoko Solver</h1>

        {/* Show a table that shakes if it's an invalid sudoku. Using date as an key so that it shakes every time it re-renders*/}
        <table className={this.state.invalidSudoku ? "shake" : ""} key={new Date()}> 
          <tbody>
            {
              // Loop through the board and render a Cell for every number
              this.state.board.map((row, i) => (
                <tr key={i * 9}>
                  {row.map((cell, j) => <td key={(i * 9) + j + 1}> <Cell changeValue={this.changeValue} i={i} j={j} value={this.state.board[i][j]} /> </td>)}
                </tr>
              ))
            }
          </tbody>
        </table>

        <button className="button-submit" onClick={() => this.solve()}>Solve!</button>

        {/* Render an error message if the sudoku is not valid */}
        {this.state.invalidSudoku ? <h4 key={new Date() + 1} className="text-error">Not a valid sudoku!</h4> : ''}

      </div>
    );
  }

I render the Sudoku board using a table with some CSS (also in the bottom of the post). For every number in the board, I render a Cell component to show and handle the number being changed. I also pass along the clickHandler function “changeValue” to the Cell components. Afterwards I show a “Solve” button and an error message if the Sudoku is not valid.

The “Cell” component looks like this:


import React, { Component } from 'react'
import './Cell.css'

class BtnNumber extends Component {

    changeValue = (event) => {
        //Prevents user from entering a non-number
        if (!Number(event.target.value) && event.target.value !== "") return;

        //Changes the board value
        this.props.changeValue(this.props.i, this.props.j, Number(event.target.value));

    }

    render() {
        return (
            <div>
                {/* Renders the cell. Shows 0 as nothing */}
                <input className='component-btn-number' value={(this.props.value === 0) ? ' ' : this.props.value} onChange={event => this.changeValue(event)} />
            </div>
        )
    }
}

export default BtnNumber

I use an “input” element as a way to both show the number and receive input from the user. I only show a number as long as it’s not zero since empty fields in the Sudoku board is set to be 0. In the “changeValue” I make sure the input can only be a number by simply not setting the value unless it’s a number.

Now for the Solver. To solve an Sudoku I use the “Backtracking algorithm”. Basically what happens is that the app starts in the top-left and tries every number, making sure that it’s valid, until it reaches the bottom-right. The trick about a backtracking algorithm is that if it reaches a dead end, it will track back to a previous state and try a different number.

File:Sudoku solved by bactracking.gif
A visual representation on how backtracking works. Credits to Wikipedia for the gif

We can achieve this by using a “recursive method”. A recursive method is a method that calls itself! I started making my own implementation for the backtracking method, but after some time I decided to reuse the code from my old C# project, since I wanted this project to be about learning about React, not algorithms. The code originally comes from the website https://www.geeksforgeeks.org/sudoku-backtracking-7/ and is made by 29AjayKumar. I won’t go in-depth about the solver, but know that the “solve” function and half of the “isValid” function was made by 29AjayKumar!



class solver {

    constructor(board) {
        this.board = board;

        if (this.isValidSudoku(this.board)) {                       //Check first if the sudoku is valid
            if (this.solve(this.board, this.board.length)) {        //Start the solving process.
                return this.board;                                  //If "solve" returns true, then return the solved board
            } else {
                return false;                                       //Else return false
            }
        }else{
            return false;                                           //If it's not a valid sudoku, return false
        }
    }

    //Original code by 29AjayKumar. Found on https://www.geeksforgeeks.org/sudoku-backtracking-7/
    solve(board, n) {

        let row = -1;
        let col = -1;
        let isEmpty = true;

        //Checks if there's any empty spot left
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < n; j++) {
                if (this.board[i][j] === 0) {
                    row = i;
                    col = j;

                    isEmpty = false;
                    break;
                }
            }
            if (!isEmpty) {
                break;
            }
        }

        // no empty space left 
        if (isEmpty) {
            return true;
        }

        // else for each-row backtrack 
        for (let num = 1; num <= n; num++) {
            if (this.isValid(board, row, col, num)) {
                this.board[row][col] = num;
                if (this.solve(board, n)) {
                    return true;
                }
                else {
                    // replace it
                    this.board[row][col] = 0;
                }
            }
        }

        return false;
    }

    isValid(board, col, row, num) {
        //Check rows
        for (let i = 0; i < board.length; i++) {
            if (i !== col) { //Dont check own number
                if (board[i][row] === num) return false;
            }
        }

        //Check Y Axis
        for (let i = 0; i < board.length; i++) {
            if (i !== row) { //Dont check own number
                if (board[col][i] === num) return false;
            }
        }

        //Check box. Also by 29AjayKumar
        let sqrt = Number(Math.sqrt(board.length));
        let boxRowStart = col - col % sqrt;
        let boxColStart = row - row % sqrt;

        for (let i = boxRowStart; i < boxRowStart + sqrt; i++) {
            for (let j = boxColStart; j < boxColStart + sqrt; j++) {
                if (i !== col &#038;&#038; j !== row) {
                    if (board[i][j] === num) {
                        return false;
                    }
                }
            }
        }
        
        return true; //Else it must be valid
    }

    isValidSudoku(board) {
        for (let i = 0; i < board.length; i++) {
            for (let j = 0; j < board.length; j++) {
                if (board[i][j] !== 0 &#038;&#038; !this.isValid(board, i, j, board[i][j])) return false;
            }
        }

        return true;
    }

}



export default solver;


And that’s it! I’m really happy about how this project went! I learned more about how to deal with states and props, and just React in general.

Link to the project Github: https://github.com/atle517/React-SudokuSolver

Category: ReactJS | LEAVE A COMMENT
July 9

Calculator with React Pt. 1: Buttons!

So these last past days I’ve been watching a lot of React videos from Codevolution, and I also completed the React + Redux course in the SoloLearn app!

Yet another certificate for my collection!

In my opinion, the best way to learn is to be practical with what you are trying to learn. So I figured I would try to build a simple calculator app with React using what I’ve learned so far!

So in React we use something called “Components”. They are the building blocks of a React app. Components kinda work like functions or a classes in JavaScript, but they can accept input through something called “props”, and they each have their own “state”. Components returns HTML content through a render function. Usually we wanna split code into as many components as possible. That way our code is easier to read and also reusable.

Now our main file to work in is gonna be “src/App.js”. In “App.js” there’s some demo content which comes with React, but we can just remove that. Now we are left with:


import React, { createElement } from 'react';
import './App.css';

export default class App extends React.Component {

  render() {
    return (
      <div className="App">
      </div>
    );
  }
}

First thing we are gonna is to make a Button component! We can choose between a functional component or a class component. Since I haven’t learned about hooks yet, I’m gonna choose class component since I need to be able to set the state. For our props we want to take in what type the button should be, be able to determine if the button should be regular sized or wide, and if it needs a special color. Our constructor ends up looking like this:


    constructor(props) {
        super(props);

        this.buttonValue = props.buttonValue;

        //Set Button styling
        let p = props;

        if (p.wide && p.color === "red") {
            this.className = "component-button wide red";
        } else if (p.wide) {
            this.className = "component-button wide";
        } else if (p.color === "blue") {
            this.className = "component-button blue";
        } else {
            this.className = "component-button";
        }

    }

The props are being automatically sent by React, so all we need to do is to make a constructor which takes props and send them in the super function. We can use some if statements with the props and a variable, “className”, to change which CSS class the button should use for rendering.

Now, for our render function. The render function will be automatically called by React when the component is first created or when it notices that the components props or state has changed. This is actually one of the main features that makes React awesome and very performance effective! Instead of having to refresh the entire DOM (Document Object Model), React creates a Virtual DOM and re-renders only the necessary parts!

Now let me show my buttons render function:


    render() {
        return (
            <div>
                <button className={this.className} onClick={() => this.props.clickHandler(this.buttonValue)}>{this.buttonValue}</button>
            </div>
        )
    }

As we can see it looks like we are returning some HTML content, but there’s also some curly braces with JavaScript in them? This is actually the JSX syntax. With JSX we can write both HTML and JavaScript together! To use variables we just have to write a them inside curly braces. What’s happening in the background is that the JSX code is being transpiled into JavaScript. The code is being transformed into JavaScript using Reacts createElement function. So this means that you can just use the createElement function instead of JSX, but I reeeeeally don’t recommend that. Also note that React uses “className” instead of “class”!

For our clickHandler we are actually using a function that we are gonna create in the “App.js” file. The reason for this is that it’s the easiest way to communicate between a “child” component (the button) and a “parent” component (the “App”). Since we are using JavaScript we can just pass down the function to the child using props, and then set it in the render function! Pretty cool!

I’ve set up some CSS files for our App component and our Button component. I’m not gonna in depth about them, but just know to use CSS with React you have to import the files.

App.css

body {
  background-color: #d6d6d6;
}
[collapse]
Button.css

.component-button {
    width: 25%;
    height: 50px;
    font-family: "Calibri";
    font-size: 1.75rem;
    float:left;
    outline:none;
    
}   

.component-button.wide {
    width: 50%;
}

/* Red button */
.component-button.red {
    background-color: #ff5d5d;
}

.component-button.red:hover {
    background-color: #ff4949;
}

.component-button.red:active {
    background-color: #ff5d5d;
}

/* Blue button */
.component-button.blue {
    background-color: #5d93ff;
}

.component-button.blue:hover {
    background-color: #4a85fc;
}

.component-button.blue:active {
    background-color: #5d93ff;
}
[collapse]

Now, let’s see the buttons! In our “App.js” we import the Button component and then create them in our render function:


import React, { createElement } from 'react';
import './App.css';
import Button from './components/Button';

export default class App extends React.Component {

  clickHandler = buttonValue => {
    //ClickHandler for Button
  }

  render() {
    return (
      <div className="App">
        {/* Row 5 */}
        <Button buttonValue="CE" wide color="red" />
        <Button buttonValue="←" wide />

        {/* Row 4 */}
        <Button buttonValue="7" clickHandler={this.clickHandler} />
        <Button buttonValue="8" clickHandler={this.clickHandler} />
        <Button buttonValue="9" clickHandler={this.clickHandler} />
        <Button buttonValue="x" />

        {/* Row 3 */}
        <Button buttonValue="4" clickHandler={this.clickHandler} />
        <Button buttonValue="5" clickHandler={this.clickHandler} />
        <Button buttonValue="6" clickHandler={this.clickHandler} />
        <Button buttonValue="-" />

        {/* Row 2 */}
        <Button buttonValue="1" clickHandler={this.clickHandler} />
        <Button buttonValue="2" clickHandler={this.clickHandler} />
        <Button buttonValue="3" clickHandler={this.clickHandler} />
        <Button buttonValue="+" />

        {/* Row 1 */}
        <Button buttonValue="0" wide clickHandler={this.clickHandler} />
        <Button buttonValue="," />
        <Button buttonValue="=" color="blue" />
      </div>
    );
  }
}

And now we have a nice calculator layout with some buttons to press!

Animated GIF

And that’s it for this time! I noticed afterwards that the division operator is missing, but I’ll fix that next time!

Category: ReactJS | LEAVE A COMMENT
July 4

Hello, React World!

So I previously said that making a React Native app within the summer is over is my goal. I started with refreshing some of my JavaScript since I know how vital it is when it comes to React. Although I didn’t quite finish my little asteroids game, I feel like I reached my goal. And we are also already in July so it’s time to move on! For learning ReactJS I’m using Codevolution‘s ReactJS tutorial. It seems really good so far!

So, my goal is to create a React Native app, but the tutorials I found all recommended to learn ReactJS first, so that’s what I’m gonna do. For those that don’t know, ReactJS is an open-source JavaScript library created and maintained by FaceBook themself. It’s designed to specifically create User-Interfaces.

Obviously the first thing I have to do is to create a Hello World application! To create a React project I needed to first have Node.js installed. Next, I needed a code editor. I choose VS Code. I also installed a extension called “ES7 React/Redux/GraphQL/React-Native snippets” to get some nice shortcuts.

Now, to create a React project you just need to run “npx create-react-app hello-world” in VS Code’s terminal. Easy! To make our Hello World application, we just need to go into “src/App.js” and edit the code to this:

 
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Hello, React World!
        </p>
        <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
          Learn React
        </a>
      </header>
    </div>
  );
}

To run it, we just need to run “npm start” in our VS Code Terminal. This opens a browser window with our app. It also auto-refreshes the site anytime we make changes to our app.

And we are done!

Category: ReactJS | LEAVE A COMMENT
June 29

Asteroids Pt. 2: Shooting some asteroids

Last time I implemented the player flying around, but now it’s time for letting the player shoot.

First thing I do is create a own class for Bullet objects which takes a position and rotation as an argument:

class Bullet{
  
  constructor(pos, rotation){<
    this.pos = createVector(pos.x, pos.y);
    
    this.dir = p5.Vector.fromAngle(rotation - PI / 2).normalize();
  }
  
  tick(){

  }
  
  render(){

  }
  
}

And in my "sketch.js" I'll add a array to hold my bullets, loop through them to tick and render them, and add a way to create them in the keyPressed function when pressing space, sending my players position and rotation as arguments:

var bullets = [];

function draw() {
  ...

  for(let i = 0; i < bullets.length; i++) bullets[i].render();
  
}

function tick() {
  ...

  for(let i = 0; i < bullets.length; i++) bullets[i].tick();
  
}

function keyPressed() {
  ...

  //Spacebar
  if(keyCode == 32){
    bullets.push(new Bullet(ship.pos, ship.rotation));
  }
}

By taking the position and rotation from the player, I can create the bullet right on top of the player and give it the same direction of the player. I also added the tick and render functions:

class Bullet{
  
  constructor(pos, rotation){
    this.pos = createVector(pos.x, pos.y); //Create a new position based on player position
    
    ////Creates a direction vector based off on players rotation. Offset it by Pi/2 to match the ship
    this.dir = p5.Vector.fromAngle(rotation - PI / 2).normalize();
    
    this.speed = 15;  //Bullet speed
    this.size = 3;    //Bullet size
    
    //Creates a velocity vector by multiplying dir vector with the speed
    this.vel = this.dir.mult(this.speed);  
    
  }
  
  tick(){
    this.pos.add(this.vel); //Moves the bullets pos by the velocity
  }
  
  render(){
    ellipse(this.pos.x, this.pos.y, this.size); //Renders the bullet
  }
  
}

After watching some footage of the original game, I saw that the bullets also goes from one side of the screen to the other. I added the feature by simply copy-pasting the previous made code from "ship.js":

  tick(){
    this.pos.add(this.vel); //Moves the bullets pos by the velocity
    
    //Keeps the bullet inside the canvas
    if(this.pos.x > width + this.size / 2){
      this.pos.x = 0;
    }else if(this.pos.x < 0 - this.size / 2){
      this.pos.x = width;
    }
    
    if(this.pos.y > height){
      this.pos.y = 0
    }else if(this.pos.y < 0){
      this.pos.y = height;
    }
    
  }

However, I need to remove the bullet after it has traveled a certain distance. To do that I created a variable to keep track of the distance traveled, and mark it for removal:

  constructor(pos, rotation){
    ...

    this.dist = 0; //Distance traveled
    this.maxDist = width; //Max distance before removal
    this.remove = false;
  }

  tick(){
    ...

    this.dist += abs(this.vel.x) + abs(this.vel.y); //Records the distance travelled
    
    if(this.dist >= this.maxDist) this.remove = true; //If traveled above the limit, mark for removal
    
   ...
    
  }

The reason I mark it for removal instead of directly removing it on the spot, is because in the tick function I'm still looping through all the bullets. Removing something from a array/list while using it, usually leads to problems with the index number.

Now, to remove the bullets all I have to do is loop through the bullet array backwards (to avoid problems with the index number when you remove an object) and remove those marked in my "sketch.js":

function tick() {
  ...

  //Bullets tick
  for (let i = 0; i < bullets.length; i++) bullets[i].tick();
  
  for (let i = bullets.length - 1; i >= 0; i--) {
    if (bullets[i].remove) bullets.splice(i, 1);
  }

}

And the player can now shoot bullets!

Animated GIF

Now we need something to shoot! For rendering and rotating the asteroids I used some of the same code I made for the player:

class Asteroid {
  constructor(x, y, size) {
    this.pos = createVector(x, y);

    this.size = size;

    this.radius = 15;

    this.angularSpeed = random(0.01, 0.03);
    this.rotation = random(0, 2 * PI);
    this.rotation = 0;
  }

  tick() {
    this.rotation += this.angularSpeed;
  }

  render() {

    push(); //Makes so that translate and rotate functions only apply to this object

    translate(this.pos.x, this.pos.y); //Moves the (0, 0) point to given coords
    rotate(this.rotation); //Rotates the object in radians

    noFill(); //Draw shapes without fill
    stroke(255); //Set the stroke color to white

    let r = this.radius;
    let ox = -6, oy = -17;   //Offsets the asteroid
    
    line(-r * 1.5 + ox, r / 2 + oy, -r / 2 + ox, -r / 2 + oy);
    line(-r / 2 + ox, -r / 2 + oy, r / 2 + ox, r / 4 + oy);
    line(r / 2 + ox, r / 4 + oy, r * 2 + ox, 0 + oy);
    line(r * 2 + ox, 0 + oy, r * 1.75 + ox, r + oy);
    line(r * 1.75 + ox, r + oy, r * 2 + ox, r * 2 + oy);
    line(r * 2 + ox, r * 2 + oy, r / 2 + ox, r * 3 + oy);
    line(r / 2 + ox, r * 3 + oy, -r + ox, r * 2.5 + oy);
    line(-r + ox, r * 2.5 + oy, -r * 1.5 + ox, r / 2 + oy);

    pop(); //Makes so that translate and rotate functions only apply to this object

  }

}

I render multiple line segments to make it look like the asteroids in the game. I decided to render it using a radius variable, since I need to have different sized asteroids. The idea worked perfectly, though I noticed a problem where the asteroids x and y coordinates were not centered around where I actually draw the asteroid. That creates a big problem since I rotate the asteroid around that point. To fix that I created an "ox" and an "oy" variable to offset where I could just offset the rendered asteroid.

I create an array of asteroids and loop through them to both tick and render them, and voila!

Animated GIF

The last thing to do now is making the bullets explode the asteroids. I first need to find a way to do hit detection. I decided to just create some rectangles for the bullets and asteroids since it's the most efficient method. The hitboxes won't align properly with what's rendering the screen though.

P5.js doesn't have any build in support for hitbox detection so I need to create that myself. First thing I do is create "rectangles" for my asteroids and bullets:

Asteroids
  tick() {
    ...

    //Hitbox
    this.rectLeftSide = createVector(this.pos.x - this.radius * 1.5, this.pos.y - this.radius * 1.5);
    this.rectRightSide = createVector(this.pos.x + this.radius * 1.5, this.pos.y + this.radius * 1.5);
  }
Bullets
  tick(){
    ...

    //Hitbox
    
    //Only create right side since I already have left side as "pos"
    this.rectRightSide = createVector(this.pos.x + this.size, this.pos.y + this.size);
    
  }

Creating a vector every single tick is not really good performance wise, but for this simple little game it will be fine. I don't really create a rectangle in these objects, but rather keep track off where the top-left side and bottom right-side of a rectangle would be.

Now I need a function to check if two "rectangles" are intersecting. Funnily enough, the fastest way to check if two rectangles are intersecting is to check if they are not intersecting at all:

function intersects(r1x1, r1y1, r1x2, r1y2, r2x1, r2y1, r2x2, r2y2){
  return !(r1x1 > r2x2 || r2x1 > r1x2 || r1y1 > r2y2 || r2y1 > r1y2);
}

I can now make a nested loop to check if a bullet and an asteroid is collided, and remove them both:


function tick() {
  ...
  
  //Hitbox detection
  for (let i = 0; i < bullets.length; i++){
    for (let j = 0; j < asteroids.length; j++){
      
      var b = bullets[i];
      var a = asteroids[j];
      
      if(intersects(b.pos.x, b.pos.y, b.rectRightSide.x, b.rectRightSide.y,
                    a.rectLeftSide.x, a.rectLeftSide.y, a.rectRightSide.x, a.rectRightSide.y)){
         
        a.remove = true;
        b.remove = true;
      }
      
    }
  }

}
Animated GIF

Next time I need to make the asteroid split up instead of just being removed, spawn asteroids and make them move!

Full code for "sketch.js"
var ship;
var bullets = [];
var asteroids = [];

function setup() {
  createCanvas(800, 640);

  ship = new Ship(width / 2, height / 2, 12);
  
  asteroids.push(new Asteroid(width / 2, height / 4, 1));
  
}

function draw() {
  background(0);

  tick();

  ship.render();
  for (let i = 0; i < bullets.length; i++) bullets[i].render();
  for (let i = 0; i < asteroids.length; i++) asteroids[i].render();

}

function tick() {
  ship.tick();

  //Bullets tick
  for (let i = 0; i < bullets.length; i++) bullets[i].tick();
  
  for (let i = bullets.length - 1; i >= 0; i--) {
    if (bullets[i].remove) bullets.splice(i, 1);
  }
  
  //Asteroids tick
  for (let i = 0; i < asteroids.length; i++) asteroids[i].tick();
  
  for (let i = asteroids.length - 1; i >= 0; i--) {
    if (asteroids[i].remove) asteroids.splice(i, 1);
  }
  
  //Hitbox detection
  for (let i = 0; i < bullets.length; i++){
    for (let j = 0; j < asteroids.length; j++){
      
      var b = bullets[i];
      var a = asteroids[j];
      
      if(intersects(b.pos.x, b.pos.y, b.rectRightSide.x, b.rectRightSide.y,
                    a.rectLeftSide.x, a.rectLeftSide.y, a.rectRightSide.x,                                   a.rectRightSide.y)){
         
        a.remove = true;
        b.remove = true;
        
      }
      
    }
  }

}

function keyPressed() {
  if (keyCode == UP_ARROW) ship.setAcceleration(0.1);

  if (keyCode == LEFT_ARROW) {
    ship.rotate(-0.075);
  } else if (keyCode == RIGHT_ARROW) {
    ship.rotate(0.075);
  }

  //Spacebar
  if (keyCode == 32) {
    bullets.push(new Bullet(ship.pos, ship.rotation));
  }

}

function keyReleased() {
  if (keyCode == UP_ARROW) ship.setAcceleration(0);

  if (keyCode == LEFT_ARROW) {
    ship.rotate(0);
  }

  if (keyCode == RIGHT_ARROW) {
    ship.rotate(0);
  }

}

function intersects(r1x1, r1y1, r1x2, r1y2, r2x1, r2y1, r2x2, r2y2){
  return !(r1x1 > r2x2 || r2x1 > r1x2 || r1y1 > r2y2 || r2y1 > r1y2);
}

[collapse]
Full code for "ship.js"
class Ship {

  constructor(x, y, size) {
    this.pos = createVector(x, y);
    this.size = size;

    this.acc = createVector(0, 0);
    this.vel = createVector(0, 0);

    this.rotation = 0;
    this.angularSpeed = 0;
    this.dir = createVector(0, 0);

    this.addedAcc = 0;
    this.friction = 0.015;
    this.maxVel = 10;
  }

  tick() {

    //Movement
    this.movement();

    this.rotation += this.angularSpeed;

  }

  movement() {
    
    //Acceleration
    this.acc = p5.Vector.fromAngle(this.rotation - PI / 2).normalize().mult(this.addedAcc);
    
    //Velocity
    this.vel.add(this.acc);
    
    //Prevents Ship from going too fast
    if(this.vel.x > this.maxVel) this.vel.x = this.maxVel;
    if(this.vel.y > this.maxVel) this.vel.y = this.maxVel;
    if(this.vel.x < -this.maxVel) this.vel.x = -this.maxVel;
    if(this.vel.y < -this.maxVel) this.vel.y = -this.maxVel;
    
    //Moves the ship according to the velocity
    this.pos.add(this.vel);
    
    //Friction
    let frictionVec = createVector(this.vel.x, this.vel.y);
    
    if(this.vel.x != 0 || this.vel.y != 0) this.vel.add(frictionVec.normalize().mult(-this.friction));
    
    //Keeps the ship inside the canvas
    if(this.pos.x > width + this.size / 2){
      this.pos.x = 0;
    }else if(this.pos.x < 0 - this.size / 2){
      this.pos.x = width;
    }
    
    if(this.pos.y > height){
      this.pos.y = 0
    }else if(this.pos.y < 0){
      this.pos.y = height;
    }

  }

  render() {

    push();  //Makes so that translate and rotate functions only apply to this object

    translate(this.pos.x, this.pos.y);    //Moves the (0, 0) point to given coords
    rotate(this.rotation);                //Rotates the object in radians

    noFill();      //Draw shapes without fill
    stroke(255);   //Set the stroke color to white

    triangle(-this.size, this.size, 0, -this.size * 1.5, this.size, this.size) //Draws a triangle

    pop();  //Makes so that translate and rotate functions only apply to this object

  }

  setAcceleration(acc) {
    this.addedAcc = acc;
  }

  rotate(angularSpeed) {
    this.angularSpeed = angularSpeed;
  }

}
[collapse]
Full code for "bullet.js"
class Bullet{
  
  constructor(pos, rotation){
    this.pos = createVector(pos.x, pos.y); //Create a new position based on player position
    
    ////Creates a direction vector based off on players rotation. Offset it by Pi/2 to match the ship
    this.dir = p5.Vector.fromAngle(rotation - PI / 2).normalize();
    
    this.speed = 15;  //Bullet speed
    this.size = 3;    //Bullet size
    
    //Creates a velocity vector by multiplying dir vector with the speed
    this.vel = this.dir.mult(this.speed);  
    
    this.dist = 0; //Distance traveled
    this.maxDist = width; //Max distance before removal
    this.remove = false;
    
    this.rectRightSide = createVector(pos.x + this.size, pos.y + this.size);
    
  }
  
  tick(){
    this.pos.add(this.vel); //Moves the bullets pos by the velocity
    
    this.dist += abs(this.vel.x) + abs(this.vel.y); //Records the distance travelled
    
    if(this.dist >= this.maxDist) this.remove = true; //If traveled above the limit, mark for removal
    
    //Keeps the bullet inside the canvas
    if(this.pos.x > width + this.size / 2){
      this.pos.x = 0;
    }else if(this.pos.x < 0 - this.size / 2){
      this.pos.x = width;
    }
    
    if(this.pos.y > height){
      this.pos.y = 0
    }else if(this.pos.y < 0){
      this.pos.y = height;
    }
    
    //Hitbox
    
    //Only create right side since I already have left side as "pos"
    this.rectRightSide = createVector(this.pos.x + this.size, this.pos.y + this.size);
    
  }
  
  render(){
    fill(255);
    stroke(255);
    
    ellipse(this.pos.x, this.pos.y, this.size); //Renders the bullet
    
  }
  
}
[collapse]
Full code for "asteroid.js"
class Asteroid {
  constructor(x, y, size) {
    this.pos = createVector(x, y);

    this.size = size;

    this.radius = 15;

    this.angularSpeed = random(0.01, 0.03);
    this.rotation = random(0, 2 * PI);
    this.rotation = 0;
    
    this.rectLeftSide = createVector(this.pos.x - this.radius * 1.5, this.pos.y - this.radius * 1.5);
    this.rectRightSide = createVector(this.radius * 3, this.radius * 3);
    
  }

  tick() {
    this.rotation += this.angularSpeed;
    
    //Hitbox
    this.rectLeftSide = createVector(this.pos.x - this.radius * 1.5, this.pos.y - this.radius * 1.5);
    this.rectRightSide = createVector(this.pos.x + this.radius * 1.5, this.pos.y + this.radius * 1.5);
  }

  render() {

    push(); //Makes so that translate and rotate functions only apply to this object

    translate(this.pos.x, this.pos.y); //Moves the (0, 0) point to given coords
    rotate(this.rotation); //Rotates the object in radians

    noFill(); //Draw shapes without fill
    stroke(255); //Set the stroke color to white

    let r = this.radius;
    let ox = -6, oy = -17;   //Offsets the asteroid
    
    line(-r * 1.5 + ox, r / 2 + oy, -r / 2 + ox, -r / 2 + oy);
    line(-r / 2 + ox, -r / 2 + oy, r / 2 + ox, r / 4 + oy);
    line(r / 2 + ox, r / 4 + oy, r * 2 + ox, 0 + oy);
    line(r * 2 + ox, 0 + oy, r * 1.75 + ox, r + oy);
    line(r * 1.75 + ox, r + oy, r * 2 + ox, r * 2 + oy);
    line(r * 2 + ox, r * 2 + oy, r / 2 + ox, r * 3 + oy);
    line(r / 2 + ox, r * 3 + oy, -r + ox, r * 2.5 + oy);
    line(-r + ox, r * 2.5 + oy, -r * 1.5 + ox, r / 2 + oy);
    
    pop(); //Makes so that translate and rotate functions only apply to this object
    
  }

}
[collapse]
June 21

Asteroids Pt. 1: Refreshing my basic JavaScript skills

So my current goals is to hopefully have a full React Native app done by the end of this summer. As soon as I started looking into tutorials I realized that the best start might not be going straight into React Native, but improve on my JavaScript. For those that don’t know, HTML is used for creating a web page, CSS is used to control the style and layout of your page, while JavaScript is used to make a page more interactive.

While we learned about HTML and CSS in my advanced programming class, we didn’t really learn much about JavaScript. Luckily I found this app for my phone called SoloLearn. It’s a cool app (that I’m not affiliated with by the way) that let’s you go through different courses for programming languages, has forums, quizzes against other people and coding challenges. I went through the HTML, CSS and JavaScript courses a few weeks ago, and it was a pretty good experience.

The beautiful certificate I received for completing the JavaScript course.

Sadly, I didn’t really use what I had recently learned, so I have to freshen up on my JavaScript again now. Since I’ve been watching a lot of TheCodingTrain recently I was inspired to learn how to use JavaScript with p5.js. Quoted straight from their website: “p5.js is a JavaScript library for creative coding, with a focus on making coding accessible and inclusive for artists, designers, educators, beginners, and anyone else!”. I decided that my first project should be making Asteroids in JavaScript using p5.js! Maybe not that surprising considering my background with game development.

Asteroids is an arcade game created by Lyle Rains, Ed Logg, and Dominic Walsh, and was released in 1979. In the game you control a small little ship. The goal is to dodge and destroy asteroids and saucers before they destroy you.

Asteroids. Picture taken from Wikipedia.

So, finally time to start some coding! Now for those that don’t know, the only thing JavaScript has in common with Java, is it’s name. While Java has strict rules on how to instantiate variables and how to create functions/methods, JavaScript is a lot more “flexible”. You don’t have to specify data types when creating variables in JavaScript. You may also just change the variables data type whenever you feel like it.

The following code is completely valid in JavaScript, while Java would throw errors over it:

var data;

data = 1;
data = "string";

Now when we first create a p5.js project we get a “sketch.js” file which looks like this:

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}

In the setup() function we set up our canvas, which is what p5.js will draw our stuff on, and whatever other objects we might wanna set up in the start. The draw function is continously called so this is where we will make a update()/tick() function and render our objects.

Time to make the player! JavaScript has a few different ways to create objects, but coming from C# and Java, I decided to try JavaScripts “new” class for creating my player object called Ship:

class Ship {
  constructor(x, y, size) {
    this.pos = createVector(x, y);
    this.size = size;

    this.rotation = 0;
  }
}

In JavaScript you don’t give the constructor the class name, but rather just call it “constructor”. Also you can’t do a normal class variable in JavaScript classes. Only solution I found around this was to instantiate variables in the constructor. There might be another way though, but I’ll have to take a look at that later.

Next up, I need to render the ship. It was a small challenge learning how to do rotations in p5.js, but I eventually figured it out:

  render() {

    push();  //Makes so that translate and rotate functions only apply to this object

    translate(this.pos.x, this.pos.y);    //Moves the (0, 0) point to given coords
    rotate(this.rotation);                //Rotates the object in radians

    noFill();      //Draw shapes without fill
    stroke(255);   //Set the stroke color to white

    triangle(-this.size, this.size, 0, -this.size * 1.5, this.size, this.size) //Draws a triangle

    pop();  //Makes so that translate and rotate functions only apply to this object

  }

The push() and pop() functions let’s us manipulate the origin point and rotation of the ship without it affecting the rest of the objects. The rotate() function let’s us rotate something around the origin point of the canvas in p5.js, and combining it with the translate() function (which moves the origin point) I can make the ship rotate around itself!

Quickly adding some controls for rotation in the sketch,js file using p5.js’s built in event handler:

function keyPressed() {
  if (keyCode == LEFT_ARROW) {
    ship.rotate(-0.075);
  } else if (keyCode == RIGHT_ARROW) {
    ship.rotate(0.075);
  }

}

function keyReleased() {
  if (keyCode == LEFT_ARROW) {
    ship.rotate(0);
  }
  
  if (keyCode == RIGHT_ARROW) {
    ship.rotate(0);
  }
  
}

And adding this to the Ship class (NOTE: The ships tick() and render() functions are being called in the “sketch.js” file):

rotate(angularSpeed) {
    this.angularSpeed = angularSpeed;
}

tick() {
    this.rotation += this.angularSpeed;
}

And the ship can now rotate! Yay!

Animated GIF

Next I should make it so I can move the ship. For this I wanna make three vectors. One for position, one for velocity and one for acceleration. When the player press the Up Arrow, the ship should get some acceleration in the direction the ship is pointing. Then I will add that acceleration to the velocity vector, which we will add to the position vector. I’ll make a movement() function and add it to the tick() function for the Ship class:

movement() {
    
    //Acceleration
    this.acc = p5.Vector.fromAngle(this.rotation - PI / 2).normalize().mult(this.addedAcc);
    
    //Velocity
    this.vel.add(this.acc);
    
    //Prevents Ship from going too fast
    if(this.vel.x > this.maxVel) this.vel.x = this.maxVel;
    if(this.vel.y > this.maxVel) this.vel.y = this.maxVel;
    if(this.vel.x < -this.maxVel) this.vel.x = -this.maxVel;
    if(this.vel.y < -this.maxVel) this.vel.y = -this.maxVel;
    
    //Moves the ship according to the velocity
    this.pos.add(this.vel);
}

So I created the three vectors and an additional variable, "maxVel" for limiting the ships' speed in the Ship constructor. The most complicated part about this code is how I determine the acceleration. I first use p5.js' built in Vector function to create a vector from our ships angle. Since I want the ship to start with pointing up, but the angle initially would point right, I offset the rotation with Pi / 2 (which is 90 degrees in radians). Then since I just need the direction I take the normalized vector (a vector which makes the max length of the components 1) and multiply it with an "addedVec". The "addedVec" is set to a number when the player presses the Up Arrow, and set back to 0 when the key is released:

setAcceleration(acc) {
    this.addedAcc = acc;
}

Now the ship can move!

Animated GIF

Last two things I will do for now to make it more like the original game is adding friction to the ship... which is flying in space... and making it so that if the ships flies off one side, it pops up on the other side.

Making the ship go to the other side if it flies off one side is quite simple. I added this to the movement() function:

//Keeps the ship inside the canvas
    if(this.pos.x > width + this.size / 2){
      this.pos.x = 0;
    }else if(this.pos.x < 0 - this.size / 2){
      this.pos.x = width;
    }
    
    if(this.pos.y > height){
      this.pos.y = 0
    }else if(this.pos.y < 0){
      this.pos.y = height;
    }

Adding friction wasn't quite that bad either:

//Friction
let frictionVec = createVector(this.vel.x, this.vel.y);
    
if(this.vel.x != 0 || this.vel.y != 0) this.vel.add(frictionVec.normalize().mult(-this.friction));

Here I create a copy of the velocity vector and if the velocity is not 0, I add a certain percentage of the velocity in the negative direction. Also put into the movement() function.

Animated GIF

And that's it for this time! Next time I'll add a shooting mechanic to the ship and also some asteroids to shoot!

Full code for "sketch.js"
var ship;

function setup() {
  createCanvas(800, 640);

  ship = new Ship(width / 2, height / 2, 12);

}

function draw() {
  background(0);

  tick();

  ship.render();
}

function tick() {
  ship.tick();
}

function keyPressed() {
  if (keyCode == UP_ARROW) ship.setAcceleration(0.1);

  if (keyCode == LEFT_ARROW) {
    ship.rotate(-0.075);
  } else if (keyCode == RIGHT_ARROW) {
    ship.rotate(0.075);
  }

}

function keyReleased() {
  if (keyCode == UP_ARROW) ship.setAcceleration(0);
  
  if (keyCode == LEFT_ARROW) {
    ship.rotate(0);
  }
  
  if (keyCode == RIGHT_ARROW) {
    ship.rotate(0);
  }
  
}
[collapse]
Full code for "ship.js"
class Ship {

  constructor(x, y, size) {
    this.pos = createVector(x, y);
    this.size = size;

    this.acc = createVector(0, 0);
    this.vel = createVector(0, 0);

    this.rotation = 0;
    this.angularSpeed = 0;
    this.dir = createVector(0, 0);

    this.addedAcc = 0;
    this.friction = 0.015;
    this.maxVel = 10;
  }

  tick() {

    //Movement
    this.movement();

    this.rotation += this.angularSpeed;

  }

  movement() {
    
    //Acceleration
    this.acc = p5.Vector.fromAngle(this.rotation - PI / 2).normalize().mult(this.addedAcc);
    
    //Velocity
    this.vel.add(this.acc);
    
    //Prevents Ship from going too fast
    if(this.vel.x > this.maxVel) this.vel.x = this.maxVel;
    if(this.vel.y > this.maxVel) this.vel.y = this.maxVel;
    if(this.vel.x < -this.maxVel) this.vel.x = -this.maxVel;
    if(this.vel.y < -this.maxVel) this.vel.y = -this.maxVel;
    
    //Moves the ship according to the velocity
    this.pos.add(this.vel);
    
    //Friction
    let frictionVec = createVector(this.vel.x, this.vel.y);
    
    if(this.vel.x != 0 || this.vel.y != 0) this.vel.add(frictionVec.normalize().mult(-this.friction));
    
    //Keeps the ship inside the canvas
    if(this.pos.x > width + this.size / 2){
      this.pos.x = 0;
    }else if(this.pos.x < 0 - this.size / 2){
      this.pos.x = width;
    }
    
    if(this.pos.y > height){
      this.pos.y = 0
    }else if(this.pos.y < 0){
      this.pos.y = height;
    }

  }

  render() {

    push();  //Makes so that translate and rotate functions only apply to this object

    translate(this.pos.x, this.pos.y);    //Moves the (0, 0) point to given coords
    rotate(this.rotation);                //Rotates the object in radians

    noFill();      //Draw shapes without fill
    stroke(255);   //Set the stroke color to white

    triangle(-this.size, this.size, 0, -this.size * 1.5, this.size, this.size) //Draws a triangle

    pop();  //Makes so that translate and rotate functions only apply to this object

  }

  setAcceleration(acc) {
    this.addedAcc = acc;
  }

  rotate(angularSpeed) {
    this.angularSpeed = angularSpeed;
  }

}
[collapse]