Make Coding Fun! 🎉

Developing a game in the browser

Marco Cecconi

@sklivvz

☝️ that was a hint to follow me on Twitter ☝️

The Main Loop ➰

Developing a game in the browser

/*

How to write on a CANVAS normally

*/

var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = "30px Arial";

ctx.fillText("Hello World", 10, 50);
/*

How to draw on a CANVAS (Game Programming Sytle)

*/

function draw() {
    var ctx = document.getElementById('canvas').getContext('2d');
    ctx.font = "30px Arial";

    var ticks = (new Date()).getTime();

    ctx.clearRect(0, 0, 640, 480); // clear canvas

    ctx.fillText("Hello World "+ticks%100, 10, 50);
    
    window.requestAnimationFrame(draw);
}    
        
draw();

Hello World!

Clear

Redraw

~30ms

Credits

Linh Pham - right curved arrow

Sprites and Assets 👻

Developing a game in the browser

/*

A simple animation

*/

// init
var x = 10;
var y = 50;

function draw() {
    var ctx = document.getElementById('canvas').getContext('2d');
    ctx.font = "30px Arial";

    var ticks = (new Date()).getTime();

    // update
    x=(x+5)%640;
    y=(y+5)%480;

    // draw
    ctx.clearRect(0, 0, 640, 480); // clear canvas
    ctx.fillText("Hello World "+ticks%100, x, y);
    
    window.requestAnimationFrame(draw);
}    

draw();
/*

Sprite

*/

class Sprite {
    constructor() {
        // init
        this._x=10;
        this._y=50;
    }

    update(ticks) {
        // update
        this._x=(this._x+5)%640;
        this._y=(this._y+5)%480;
    }

    // data for draw
    get x() { return this._x; }
    get y() { return this._y; }
}
/*

Loop with sprite

*/

// init
var hello = new Sprite();

function draw() {
    var ctx = document.getElementById('canvas').getContext('2d');
    ctx.font = "30px Arial";

    var ticks = (new Date()).getTime();

    // update
    hello.update(ticks);

    // draw
    ctx.clearRect(0, 0, 640, 480); // clear canvas
    ctx.fillText("Hello World "+ticks%100, hello.x, hello.y);
    
    window.requestAnimationFrame(draw);
}    

draw();
/* Sprite with Asset */

class Sprite {
    constructor(asset) {
        this._x=10;
        this._y=50;
        this._asset = asset;
    }

    update(ticks) {
        this._x=(this._x+5)%640;
        this._y=(this._y+5)%480;
    }

    draw(ctx, ticks) {
        this._asset.draw(ctx, this, ticks);
    }

    get x() { return this._x; }
    get y() { return this._y; }
}

class Asset {
    draw(ctx, sprite, ticks) {
       ctx.fillText("Hello World "+ticks%100, sprite.x, sprite.y);
    }
}

Keyboard Input ⌨️

Developing a game in the browser

/* Hooking up the keyboard */

class Keyboard {
    constructor() {
        this._keys = new Set();
        const k = this._keys;
        document.addEventListener('keydown', function(evt) { 
            k.add(evt.code) 
        });
        document.addEventListener('keyup', function(evt) { 
            k.delete(evt.code) 
        });
    }

    has(k) {
        return this._keys.has(k);
    }
}
/* Making Mario jump */

class Sprite {
    constructor(asset) {
        this._x=10;
        this._y=160;
        this._asset = asset;
        this._jump = 0;
        this._jumpPattern = [0, 5, 11, 15, 20, 24, 28, 32, 35, 38, 40, 42, 44, 45, 46, 47, 
                            48, 48, 47, 46, 45, 44, 42, 40, 38, 35, 32, 28, 24, 20, 15, 10, 5];
    }

    update(ticks, keyboard) {
        if(this._jump>0) 
            this._jump--;
        if(this._jump==0 && keyboard.has('KeyJ')) 
            this._jump = this._jumpPattern.length-1;
        this._x=(this._x+5)%640;
    }

    draw(ctx, ticks) {
        this._asset.draw(ctx, this, ticks);
    }

    get x() { return this._x; }
    get y() { return this._y - this._jumpPattern[this._jump]; }
}

Hit detection 💥

Developing a game in the browser

class DeadMario {
    // A sprite that just falls down off the screen
    // Uses the normal Mario asset
}

class Barrel {
    constructor(asset) {
        this._x=640;
        this._y=170;
        this._asset = asset;
    }

    update(ticks, keyboard) {
        this._x=(this._x-3);
        if (this._x<=0) this._x=640;
    }

    draw(ctx, ticks) {
        this._asset.draw(ctx, this, ticks);
    }

    get x() { return this._x; }
    get y() { return this._y; }

    // All sprites export height and width
    get h() { return 30; }
    get w() { return 36; }
}


class BarrelAsset {
    // draws a barrel using "barrel.png"
}
// returns true if point (px, py) is in rect (rx, ry, rw, rh)

function pointInRect(px, py, rx, ry, rw, rh) {
    return rx<=px && (rx+rw>=px) && ry>=py && (ry-rh<=py);
} 

rx, ry

rx, ry-rh

rx+rw, ry

rx+rw, ry-rh

px, py

// returns if any vertex of sprite 1 is inside the rect of sprite 2
// i.e. if there is any overlap

function collision(sprite1, sprite2) {
    const x1 = sprite1.x;
    const y1 = sprite1.y;
    const w1 = sprite1.w;
    const h1 = sprite1.h;
    const x2 = sprite2.x;
    const y2 = sprite2.y;
    const w2 = sprite2.w;
    const h2 = sprite2.h;
    return pointInRect(x1,y1,x2,y2,w2,h2) || pointInRect(x1+w1,y1,x2,y2,w2,h2) ||
           pointInRect(x1,y1-h1,x2,y2,w2,h2) || pointInRect(x1+w1,y1-h1,x2,y2,w2,h2);
} 

sprite 2

sprite 1

Music and Sound 🎵

Developing a game in the browser

/*

    Sound effects are trivial

*/

audio = new Audio('coin.mp3');
audio.play();

Scenes 🎭

Developing a game in the browser

Developing a game in the browser

https://is.gd/blasteroids

Developing a game in the browser

  • ➰ Main Loop
  • 👻 Sprites and Assets
  • ⌨️ Keyboard
  • 💥 Hit Detection
  • 🎵 Music and Sound
  • 🎭 Scenes

Questions? 🎮

Marco Cecconi

@sklivvz

☝️ that was a hint to follow me on Twitter ☝️

Repo: https://github.com/sklivvz/game-programming

Make Coding Fun! 🎉

By Marco Cecconi

Make Coding Fun! 🎉

In which the basics of how to write a 2D game in the browser are covered

  • 680