UberGamerMonkey.com

Adventures in TypeScript 02

2016-11-02

Today's part of the adventure, we will be going over in creating the ball that terrorizes the bricks in the game. From the last adventure (Adventures in TypeScript 01), we created a basic HTML page that houses the canvas, and started the main guts of the game with a nice little game loop.

You can see the final outcome of the Breakout clone here. As well as see all the code in my GitHub repo.

Game.ts - Adding more guts

Before we want to add the nice little ball, let's think about how we want to implement it. Each entity in the game will need to be updated, draw, and have a position. So why not create an interface that houses all the basics that each object will need to implement? That sounds like a marvelous idea.

// base interface for our entities that we want to draw on the screen
// and handle in the game.
interface iEntity {
    draw(): void;
    update(): void;
    x: number;
    y: number;
    velX: number;
    velY: number;
}

I went ahead and added velocity as well, because most will want to move on the screen. You can name this whatever you like, but I usually like to start off my interface with an 'i', and then later on for classes, I like to start them off with a 'c'. With this interface, we are saying any class that implements this will have a draw function, update function, x and y position, as well as x and y velocity.

Now let's start working on the actual implementation for the ball class. Since we know it will implement the iEntity interface, we can start off by creating a base shell of the class.

class cBall implements iEntity {
    public x: number = 0;
    public y: number = 0;
    public velX: number = 0;
    public velY: number = 0;

    public draw = (): void => {

    }

    public update = (): void => {

    }
}

Nice and sweet. Now if you think about it, the ball should have more properties, like the radius and color. Let's go ahead and add that to the class, as well as create a nice constructor to set everything up.

public radius: number = 0;
public color: string = "white";

constructor(x: number, y: number, radius: number, color: string = "white")
{
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
}

Now that we have the more specific details of the ball, let's go ahead and try to draw it on the canvas. To do so, we will fill out the draw function in the cBall class.

public draw = (): void => {
    // draw a nice circle!
    ctx.save();
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2);
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.closePath();
}

Let's set up a variable for our ball, and initialize it. Then we can modify the gameLoop function to update and draw the ball.

var ball: cBall = new cBall(240, 290, 5);

function gameLoop()
{
    // lets keep the game loop going!
    requestAnimationFrame(gameLoop);

    // fill to black!
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    ball.update();
    ball.draw();
}

If you compile and run it, you should see a nice little white ball in the canvas. It isn't moving yet because we haven't given it a velocity and we haven't filled out the update function. Let's go ahead and make this ball move!

public update = (): void => {
        // update the balls position
        this.x += this.velX;
        this.y += this.velY;

        // did we hit the left or right bounds?
        // if so, lets bounce back the opposite direction.
        if(this.x > canvas.width - this.radius || this.x < this.radius) {
            this.velX = -this.velX;
        }

        // did we hit the ceiling or floor?
        // if so, let's bounce back.
        if(this.y < this.radius || this.y > canvas.height - this.radius) {
            this.velY = -this.velY;
        }
}

We are adding the velocity for x and y to the position to move the ball. Next we want to make sure we keep it in bounds of the canvas, else it will just fly off the canvas and never return. So we check to see if the position of the ball is within bounds of the canvas (+- the radius of the ball so it doesn't go partially off screen before bouncing back). Now if you run this you should still see the ball on the canvas, yet it still isn't moving. To get the ball to move, we need to set the velocity x and y properties. Inside the window.onload event, before we make the call to the gameLoop, let's set the velocity of the ball.

ball.velX = 3;
ball.velY = 3;

Now if you compile and run, you should see the ball bounce around and around. Here is what game.ts should look like so far.

var canvas: HTMLCanvasElement;
var ctx: CanvasRenderingContext2D;

// base interface for our entities that we want to draw on the screen
// and handle in the game.
interface iEntity {
    draw(): void;
    update(): void;
    x: number;
    y: number;
    velX: number;
    velY: number;
}

// class for the ball entity
class cBall implements iEntity {
    public x: number = 0;
    public y: number = 0;
    public velX: number = 0;
    public velY: number = 0;
    public radius: number = 0;
    public color: string = "white";

    constructor(x: number, y: number, radius: number, color: string = "white")
    {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
    }

    public draw = (): void => {
        // draw a nice circle!
        ctx.save();
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2);
        ctx.fillStyle = this.color;
        ctx.fill();
        ctx.closePath();
    }

    public update = (): void => {
        // update the balls position
        this.x += this.velX;
        this.y += this.velY;

        // did we hit the left or right bounds?
        // if so, lets bounce back the opposite direction.
        if(this.x > canvas.width - this.radius || this.x < this.radius) {
            this.velX = -this.velX;
        }

        // did we hit the ceiling or floor?
        // if so, let's bounce back.
        if(this.y < this.radius || this.y > canvas.height - this.radius) {
            this.velY = -this.velY;
        }
    }
}

var ball: cBall = new cBall(240, 290, 5);

function gameLoop()
{
    // lets keep the game loop going!
    requestAnimationFrame(gameLoop);

    // fill to black!
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    ball.update();
    ball.draw();
}

window.onload = () => {
    // grab our canvas, and get a 2d context
    canvas = <HTMLCanvasElement>document.getElementById('gameCanvas');
    ctx = canvas.getContext("2d");

    ball.velX = 3;
    ball.velY = 3;

    // run the game!
    gameLoop();
}

In the next tutorial, I will go over on creating the paddle so we can smack the ball around.

About Me

I write code for a living. I also enjoy games (making and playing), music (listening and producing), and a few other things.

Tags

© 2022 UberGamerMonkey.com. All rights reserved