JavaScript from scratch! Part 2
Tags: tutorial, javascript
Published: 2021-01-25 16:36:43

Hey! Welcome back. I hope you're not tired yet, because we are just starting our SPEEDRUN ~~It was a joke, there is no speedrun~~.

So what we are going to build today? Nothing. Hah, you fell for it! We are going to build a simple snake game! What are you going to learn exactly? Here is some stuff:

* Window API ([setTimeout]() for example
* Events
* Canvas manipulation
* Functions
* Dom manipulation
* Some other stuff but I'm lazy to write more

#Setting up our project!
To set up a project, just make a directory. In that directory make two files: `index.html`, `script.js`. `index.html` file is for basic HTML with all the magic provided by the JavaScript file.

#index.html
Just copy this bad boy below into your index.html file and open it using your browser.
```html
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="script.js"></script>
        <title>Snek</title>
    </head>
    <body>
        <canvas id="snake-game" style="width: 600px; height: 300px; border: 2px black solid;"></canvas>
    </body>
</html>
```

Ready? So let's keep moving!

#Thinkering with javascript

Before we start let's revise what we are going to build, and make a simple checklist. There it goes then:

1. Variables for config (snake data, fruit data)
2. Interval running for canvas rendering
  0. Snake
  1. Moving
  2. Fruit generation
  3. Eating a fruit
  4. Tail expansion
3. Game end, current score

Let's start with variables... There will be one to rule them all
```js
let data = {
    user: {
        x: 0,
        y: 0,
        direction: 2
    },
    state: 0
}
```

So what we are doing here is that we make a variable called `data`, then we are using the `=` operator to assign value to data and here we go. The value here is JavaScript Object Notation (JSON). This thing is very useful for making grouped variables. The basic structure is `{key: value, key1: value1}` and so on. State key is a property for holding current game state like running, off, lost. `user` is itself a nested JSON. To access any of that you can use dot notation, like so:

```js
data.user.direction // 2
```

There some built-in variables like document, window, or console. The document variable is a global variable that corresponds to the current page, a console is your developer console. Let's get our canvas object so we can use it.

```js
// Add after data variable
const canvas = document.getElementById("snake-game");
```

This lets you get a reference to the canvas object. Notice `("snake-game")`, this calls a function with one argument. We will talk about it a little bit later, but it's a built-in function just so we can use it freely. We use const so we won't override it easily, like assigning a number to it.

```js
//After canvas declaration
const ctx = canvas.getContext('2d');
```

It uses [this](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext). As you can see it returns an element of type [CanvasRenderingContext2D](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D). On this object we should call methods to draw things to a canvas.

#Defining a function
Just to make our code cleaner we can create a function to draw a snake for us. But wait, what are we use these functions for? For example, instead of writing the same code, we can call these magic functions. You can read more about it [here](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions).

```js
function drawSnake() {
    //Code to draw the actual snake
}

//Call the function after declaration
drawSnake();
```

So what we should do here? We should get the current player position. Then draw it according to some measurements. So, what are we waiting for? ~~I'm waiting for some sandwich, how about you?~~

```js
//Inside drawSnake function
let x = data.user.x;
let y = data.user.y;

//Changing pen color
ctx.fillStyle = 'green';
//Drawing a 10x10 pixels square at x,y position
ctx.fillRect(x * 10, y * 10, 10, 10);
```

Save the file. Open your web browser and run the `index.html` file, and check your developer console if there are any warnings. And so? There is something there? Of course, there is! ~~And it's not that bad.~~ But first why is happening this error and nothing is drawn to a canvas? It's because we're getting an element before rendering a page so let's wait for a page load. ~~Using JavaScript of course.~~

Let's change our function a little to something like this:
```js
function drawSnake(ctx) {
    let x = data.user.x;
    let y = data.user.y;

    //Changing pen color
    ctx.fillStyle = 'green';
    //Drawing a 10x10 pixels square at x,y position
    ctx.fillRect(x * 10, y * 10, 10, 10);
}
```

Also, remove these two global variables called `canvas` and `ctx` you can also remove this one lonely drawSnake function call. Add this little code:

```js
window.onload = function() {
    const canvas = document.getElementById("snake-game");
    const ctx = canvas.getContext('2d');

    drawSnake(ctx)
}
```

So what it actually does? Let me explain. We access `onload` property of the global object `window` then override it with an anonymous function. ~~It's just a function without a name.~~ It executes this code when the page is loaded. Since we no longer have a global variable you can just pass an argument to a function. So far we've got something like this code below.

```js
//script.js
let data = {
    user: {
        x: 0,
        y: 0,
        direction: 2
    },
    state: 0
}

window.onload = function() {
    const canvas = document.getElementById("snake-game");
    const ctx = canvas.getContext('2d');

    drawSnake(ctx);
}

function drawSnake(ctx) {
    let x = data.user.x;
    let y = data.user.y;

    //Changing pen color
    ctx.fillStyle = 'green';
    //Drawing a 10x10 pixels square at x,y position
    ctx.fillRect(x * 10, y * 10, 10, 10);
}
```

Woah, we did it... But it doesn't move at all. Let's add code to do it! Here goes another function:

```js
//At the end
function moveSnake() {
    switch (data.user.direction) {
        case 0:
            data.user.x--;
            break;
        case 1:
            data.user.y++;
            break;
        case 2:
            data.user.x++;
            break;
        case 3:
            data.user.y--;
            break;
    }
}
```

But wait, what is this weird thing called switch? It's a shorthand for a long if else statement. We'll talk about it later I promise. After `switch` keyword you pass an argument that cases will be matched against. So for example, if a direction is equal to 2, the snake will move left. That's because `variable++` is a shorthand for `variable = variable + 1`. ~~It's called incrementation.~~ `--` is subtracting 1 from the variable. But wait, there is also a keyword called break. It's there because we don't want the cases to fall through. You can read about switch and cases [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch).

```js
//in window.onload anonymous function instead of drawSnake(ctx);
setInterval(function() {
    drawSnake(ctx);
    moveSnake();
}, 500)
```

But wait, instead of one square we see a green strip. Okay, okay. We forgot to clear it up, let's fix it right away! Add this line above drawSnake() call.

```js
ctx.clearRect(0, 0, canvas.width, canvas.height);
```

We are done! You can see it's moving quite fast. One square every 500 ms. And that's all for this post... Stay tuned for more and see you soon!