Copyright Derek O'Reilly, Dundalk Institute of Technology (DkIT), Dundalk, Co. Louth, Ireland.
The aim of this game is to use the arrow keys to direct the monster to the bullseye.
This game shows:
Play game
/* Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. */ /* There should always be a javaScript file with the same name as the html file. */ /* This file always holds the playGame function(). */ /* It also holds game specific code, which will be different for each game */ /******************** Declare game specific global data and functions *****************/ /* images must be declared as global, so that they will load before the game starts */ let obstaclesImage = new Image(); obstaclesImage.src = "images/obstacles.png"; let monsterImage = new Image(); monsterImage.src = "images/monster.png"; let bullseyeImage = new Image(); bullseyeImage.src = "images/bullseye.png"; let starsImage = new Image(); starsImage.src = "images/stars.png"; /* Direction that the skeleton is walking */ /* Note that this matches the row in the gameObject image for the given direction */ const UP = 0; const LEFT = 1; const DOWN = 2; const RIGHT = 3; const STOPPED = 4; const START = 5; /* The various gameObjects */ /* These are the positions that each gameObject is held in the gameObjects[] array */ const BACKGROUND = 0; const OBSTACLES = 1; const BULLSEYE = 2; const MONSTER = 3; const WIN_MESSAGE = 4; /******************* END OF Declare game specific data and functions *****************/ /* Always have a playGame() function */ /* However, the content of this function will be different for each game */ function playGame() { /* We need to initialise the game objects outside of the Game class */ /* This function does this initialisation. */ /* This function will: */ /* 1. create the various game game gameObjects */ /* 2. store the game gameObjects in an array */ /* 3. create a new Game to display the game gameObjects */ /* 4. start the Game */ /* Create the various gameObjects for this game. */ /* This is game specific code. It will be different for each game, as each game will have it own gameObjects */ gameObjects[BACKGROUND] = new StaticImage(starsImage, 0, 0, canvas.width, canvas.height); gameObjects[OBSTACLES] = new StaticImage(obstaclesImage, 0, 0, canvas.width, canvas.height); gameObjects[BULLSEYE] = new Bullseye(bullseyeImage, canvas.width - 50, canvas.height - 50, 50, 50); gameObjects[MONSTER] = new Monster(monsterImage); /* END OF game specific code. */ /* Always create a game that uses the gameObject array */ let game = new MonsterCanvasGame(obstaclesImage); /* Always play the game */ game.start(); /* If they are needed, then include any game-specific mouse and keyboard listners */ document.addEventListener('keydown', function (e) { if (e.keyCode === 37) // left { gameObjects[MONSTER].setDirection(LEFT); } else if (e.keyCode === 38) // up { gameObjects[MONSTER].setDirection(UP); } else if (e.keyCode === 39) // right { gameObjects[MONSTER].setDirection(RIGHT); } else if (e.keyCode === 40) // down { gameObjects[MONSTER].setDirection(DOWN); } else if (e.keyCode === 32) // space { gameObjects[MONSTER].setDirection(START); } }); document.addEventListener('keyup', function (e) { gameObjects[MONSTER].setDirection(STOPPED); }); }
The game displays a monster, a background, a bullseye and obstacles.
gameObjects[BACKGROUND] = new StaticImage(starsImage, 0, 0, canvas.width, canvas.height); gameObjects[OBSTACLES] = new StaticImage(obstaclesImage, 0, 0, canvas.width, canvas.height); gameObjects[BULLSEYE] = new Bullseye(bullseyeImage, canvas.width - 50, canvas.height - 50, 50, 50); gameObjects[MONSTER] = new Monster(monsterImage);
The arrow keys are used to control the direction that the monster moves.
document.addEventListener('keydown', function (e) { if (e.keyCode === 37) // left { gameObjects[MONSTER].setDirection(LEFT); } else if (e.keyCode === 38) // up { gameObjects[MONSTER].setDirection(UP); } else if (e.keyCode === 39) // right { gameObjects[MONSTER].setDirection(RIGHT); } else if (e.keyCode === 40) // down { gameObjects[MONSTER].setDirection(DOWN); } else if (e.keyCode === 32) // space { gameObjects[MONSTER].setDirection(START); } });
The monster stops moving when the arrow keys are released.
document.addEventListener('keyup', function (e) { gameObjects[MONSTER].setDirection(STOPPED); });
/* Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. */ /* A CanvasGame that implements collision detection. */ /* The game allows the user to walk a skeleton around a maze. */ /* If the skeleton is guided to the maze exit, then a win message appears. */ class MonsterCanvasGame extends CanvasGame { constructor(obstaclesImage) { super(); /* this.monsterObstalesCtx will be used for collision detection */ let monsterObstalesOffscreenCanvas = document.createElement('canvas'); monsterObstalesOffscreenCanvas.width = canvas.width; monsterObstalesOffscreenCanvas.height = canvas.height; this.monsterObstalesCtx = monsterObstalesOffscreenCanvas.getContext('2d'); this.monsterObstalesCtx.drawImage(obstaclesImage, 0, 0, canvas.width, canvas.height); this.screenShakeInterval = null; this.screenIsRotatingToTheLeft = false; this.NUMBER_OF_SCREEN_SHAKES_INTERATIONS = 10; this.numberOfScreenShakes = 0; } collisionDetection() { if (!this.monsterObstalesCtx) { return; } let imageData = this.monsterObstalesCtx.getImageData(gameObjects[MONSTER].getX(), gameObjects[MONSTER].getY(), 1, 1); let dataTop = imageData.data; imageData = this.monsterObstalesCtx.getImageData(gameObjects[MONSTER].getX() + gameObjects[MONSTER].getWidth() * 0.8, gameObjects[MONSTER].getY(), 1, 1); let dataRight = imageData.data; imageData = this.monsterObstalesCtx.getImageData(gameObjects[MONSTER].getX(), gameObjects[MONSTER].getY() + gameObjects[MONSTER].getHeight() * 0.8, 1, 1); let dataBottom = imageData.data; imageData = this.monsterObstalesCtx.getImageData(gameObjects[MONSTER].getX() + gameObjects[MONSTER].getWidth() * 0.8, gameObjects[MONSTER].getY() + gameObjects[MONSTER].getHeight() * 0.8, 1, 1); let dataLeft = imageData.data; if ((dataTop[3] !== 0) || (dataRight[3] !== 0) || (dataBottom[3] !== 0) || (dataLeft[3] !== 0)) { if (gameObjects[MONSTER].getDirection() === UP) { gameObjects[MONSTER].setDirection(DOWN); gameObjects[MONSTER].setY(gameObjects[MONSTER].getY() + 5); } else if (gameObjects[MONSTER].getDirection() === DOWN) { gameObjects[MONSTER].setDirection(UP); gameObjects[MONSTER].setY(gameObjects[MONSTER].getY() - 5); } else if (gameObjects[MONSTER].getDirection() === LEFT) { gameObjects[MONSTER].setDirection(RIGHT); } else if (gameObjects[MONSTER].getDirection() === RIGHT) { gameObjects[MONSTER].setDirection(LEFT); } if (this.screenShakeInterval === null) { this.screenShakeInterval = setInterval(this.shakeScreen.bind(this), 10); } } else if (gameObjects[BULLSEYE].pointIsInsideBullseyeRectangle(gameObjects[MONSTER].getX() + gameObjects[MONSTER].getWidth() * 0.5, gameObjects[MONSTER].getY() + gameObjects[MONSTER].getHeight() * 0.5)) { /* Player has won */ for (let i = 0; i < gameObjects.length; i++) /* stop all gameObjects from animating */ { gameObjects[i].stop(); } gameObjects[WIN_MESSAGE] = new StaticText("Well Done!", 20, 280, "Times Roman", 100, "red"); gameObjects[WIN_MESSAGE].start(); /* render win message */ } } render() { ctx.save(); if (this.screenShakeInterval !== null) // hit an obstacle { if (this.screenIsRotatingToTheLeft) { ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate(Math.radians(1)); ctx.translate(-canvas.width / 2, -canvas.height / 2); } else { ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate(Math.radians(-1)); ctx.translate(-canvas.width / 2, -canvas.height / 2); } } super.render(); ctx.restore(); } shakeScreen() { if (this.screenIsRotatingToTheLeft) { this.screenIsRotatingToTheLeft = false; } else // screen is rotating to the right { this.screenIsRotatingToTheLeft = true; } this.numberOfScreenShakes++; if (this.numberOfScreenShakes >= this.NUMBER_OF_SCREEN_SHAKES_INTERATIONS) { this.numberOfScreenShakes = 0; clearInterval(this.screenShakeInterval); this.screenShakeInterval = null; } } }
Whenever the skeleton hits the maze grid, if changes direction.
/* Player has won */ for (let i = 0; i < gameObjects.length; i++) /* stop all gameObjects from animating */ { gameObjects[i].stop(); } gameObjects[WIN_MESSAGE] = new StaticText("Well Done!", 20, 280, "Times Roman", 100, "red"); gameObjects[WIN_MESSAGE].start(); /* render win message */
/* Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. */ class Monster extends GameObject { /* Each gameObject MUST have a constructor() and a render() method. */ /* If the object animates, then it must also have an updateState() method. */ constructor(monsterImage) { super(5); /* as this class extends from GameObject, you must always call super() */ /* These variables depend on the object */ this.startX = 20; this.startY = 20; this.x = this.startX; this.y = this.startY; this.monsterImage = monsterImage; this.width = 40; this.height = 40; this.setDirection(STOPPED); } updateState() { if (this.direction === UP) { this.y--; } else if (this.direction === LEFT) { this.x--; } else if (this.direction === DOWN) { this.y++; } else if (this.direction === RIGHT) { this.x++; } } render() { ctx.drawImage(this.monsterImage, this.x, this.y, this.width, this.height); } setDirection(newDirection) { if (this.direction !== START) { this.direction = newDirection; } else // spacebar hit, so set monster back to start { this.x = this.startX; this.y = this.startY; this.direction = STOPPED; } } getDirection() { return(this.direction); } getX() { return this.x; } getY() { return this.y; } setX(newX) { this.x = newX; } setY(newY) { this.y = newY; } getWidth() { return this.width; } getHeight() { return this.height; } }
/* Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. */ class Bullseye extends StaticImage { /* Each gameObject MUST have a constructor() and a render() method. */ /* If the object animates, then it must also have an updateState() method. */ constructor(image, x, y, width, height) { super(image, x, y, width, height); /* as this class extends from GameObject, you must always call super() */ /* These variables depend on the object */ this.image = image; this.width = width; this.height = height; this.x = x; this.y = y; this.bullseyeSize = 10; // the granularity of the bullseye target. } getX() { return this.x; } getY() { return this.y; } getWidth() { return this.width; } getHeight() { return this.height; } pointIsInsideBullseyeRectangle(pointX, pointY) { /* The bullseye is set to have a width and height of bullseySize */ /* The bulleseye is set from the centre of the bullseye image */ let bullseyeX = this.x + ((this.width - this.bullseyeSize) / 2); let bullseyeY = this.y + ((this.height - this.bullseyeSize) / 2); if ((pointX > bullseyeX) && (pointY > bullseyeY)) { if (pointX > bullseyeX) { if ((pointX - bullseyeX) > this.bullseyeSize) { return false; // to the right of this gameObject } } if (pointY > bullseyeY) { if ((pointY - bullseyeY) > this.bullseyeSize) { return false; // below this gameObject } } } else // above or to the left of this gameObject { return false; } return true; // inside this gameObject } }
Copyright Derek O' Reilly, Dundalk Institute of Technology (DkIT), Dundalk, Co. Louth, Ireland.