(Note: I'm moving my posts from my time at Flatiron School from my Github to this platform. This blog entry was first posted on March 18, 2020)
For my JavaScript/Rails Single Page Application (SPA) project I made a game called Invasion!, about my dog dreaming of battling squirrels in space. The game was made with JavaScript, HTML, and CSS and a backend Rails API to store and fetch player’s names and scores.
For the most part I utilized object orientated design. All of the game objects and sprites (images) are broken into classes. For example, the player, enemies, and bullets are all objects that inherit from GameObject
. Each GameObject
has update()
and draw()
methods. Anything pertaining to displaying sprites or text goes in draw
, and anything that manipulates these things goes into update
.
Example of game objects inheriting from a GameObject class:
class GameObject {
static all = [];
constructor() {
GameObject.all.push(this);
}
update() {
this.checkForCollision();
}
draw(ctx) {
const { sourceX, sourceY, sourceWidth, sourceHeight, x, y, width, height, image } = this.spriteObj;
ctx.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, x, y, width, height);
}
// other methods to check for and handle
// collisions, out of bounds, etc ...
}
class Player extends GameObject {
constructor() {
super();
// other properties initialized here
}
update() {
super.update();
if (this.collided) {
ExplosionObject.createExplosion(this);
}
this.move();
// etc...
}
// no need for a draw method since nothing changes from
// the GameObject class
}
Upon initialization, each GameObject
is stored in a static variable array called all
. This way I was able to handle looping through updates and draws for every existing object at once.
class Game {
// constructor, other methods, etc...
update() {
// spawn enemies...
GameObject.all.forEach(obj => obj.update());
if (this.player.isHit) this.gameOver();
}
draw() {
this.ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
if (this.mode === "play") {
GameObject.all.forEach(obj => obj.draw(this.ctx));
}
}
}
Sprites were separated into their own classes, depending on whether they were animated or not. My regular sprite class, SpriteObject
consisted simply of a constructor that took in the source location on the spritesheet and size for the sprite, the (x,y) location and sizes I wanted, and created a new Image()
. The AnimatedSpriteObject
, which inherits from SpriteObject
, is a lot more complicated. Aside from the properties already mentioned, I needed to know how many rows, columns, and frames an animation had.
A sprite object does not inherit from GameObject
because the thing the sprite is an image/animation of does. For example, if an enemy squirrel ship appears on screen, a new enemy()
is created (which inherits from GameObject
. When it is created a new SpriteObject()
is created for the enemy and stored as this.spriteObj
on the enemy instance.
class Enemy extends GameObject {
constructor(spawnX, speed = 1) {
super();
this.spriteObj = new SpriteObject(Enemy.initObj(spawnX));
this.speed = speed;
}
}
static initObj(spawnX) {
return {
sourceX: 0,
sourceY: 176,
sourceWidth: 218,
sourceHeight: 169,
x: spawnX,
y: -170,
width: 218 / 2,
height: 169 / 2
}
}
Oh, I should mention that I used requestAnimationFrame
to handle the game looping. requestAnimationFrame
updates the browser roughly 60 times a second. It works similarly to setInterval
but performs better for game purposes.
In order to animate, I had to create a delay value and keep track of how many 'ticks' went by. Each 'tick' is a frame per second (fps). If I didn't use a delay then the images would pretty much loop at rapid speed and you would never accurately see the animation. I set my delay to 3; this way it would only update to the next image every 3fps. Then I reset the tickCount to 0 to start over for the next frame.
Animating the sprites turned out to be the most challenging part of this whole project. I spent a lot of time googling and watching YouTube videos before I could get it working properly. If you're interested in knowing more about game development using JavaScript I found this channel to be pretty helpful: PothOnProgramming.
If you'd like to check out Invasion! you can do so here: github
Top comments (6)
What a cute game! The screenshot showing Penny and the squirrels in spaceships make me smile. Have you submitted this game to any app stores?
Thank you! It's just something small for my Flatiron School project, but I should definitely consider fleshing it out into something more. :)
I think it would be great as a web app! Maybe try working through the KaiOS developer portal to figure out how to adapt it. I've interviewed a few KaiOS app developers and several have had a great experience working with KaiOS and releasing simple but fun games. You'd have a better shot of getting some user engagement if you released in their KaiStore versus the competitive native app stores.
If you want to check it out: developer.kaiostech.com/
cool thanks, I'll check it out!
nice
Thank you!