Skip to content

Commit

Permalink
fix(rhino): movement improved.
Browse files Browse the repository at this point in the history
  • Loading branch information
programad committed Aug 29, 2020
1 parent a2eb3d8 commit b972012
Show file tree
Hide file tree
Showing 13 changed files with 289 additions and 89 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ npm run dev
The game now has a angry rhino chasing the player down the mountain. It can run to the left, to the right and downwards. If it catches the player, you are done.

* The rhino appears after a specific amount of time and at a specific distance from the player;
* The rhino runs faster then the player when both are going downwards but the player goes faster if slides on diagonal, adding some challenge to the game.
* The rhino received a new animation to run to the right. It was possible to flip the sprite by code but having a dedicated sprite is more performant.
* The rhino runs faster then the player when both are going downwards but the player goes faster if slides on diagonal, adding some challenge to the game;
* The rhino sprites were scaled up to 128px height to bring consistency with the skier being eaten size and to look more scary;
* The rhino received a new animation to run to the right. It was possible to flip the sprite by code but having a dedicated sprite is more performant;

**Documentation:**

Expand Down
6 changes: 3 additions & 3 deletions src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ export const RAMP = 'ramp';

export const SKIER_STARTING_SPEED = 10;
export const SKIER_DIAGONAL_FACTOR = 1.1;
export const SKIER_JUMP_FACTOR = 1.002;
export const SKIER_JUMP_FACTOR = 1.003;

export const RHINO_STARTING_SPEED = 10.5;
export const RHINO_STARTING_TIMER = 100;
export const RHINO_STARTING_DISTANCE = 120;
export const RHINO_STARTING_NUMBER = 500;
export const RHINO_STARTING_DISTANCE = 200;

export const ASSETS = {
[SKIER_CRASH]: 'img/skier_crash.png',
Expand Down
22 changes: 9 additions & 13 deletions src/Core/AnimationController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { gameManager } from '../Core/GameManager';
export class AnimationController {
playing = false;
loop = false;
animationFrames = [];
animationFrameDuration = 8;
assetNames = [];
currentFrameIndex = 0;

constructor(name) {
this.lastFrame = gameManager.getCurrentFrame();
Expand All @@ -13,36 +13,32 @@ export class AnimationController {

update() {
let currentFrame = gameManager.getCurrentFrame();

if (currentFrame > this.lastFrame) {
this.lastFrame = currentFrame;
this.currentFrameIndex++;

if (this.loop) {
this.currentFrameIndex = (this.currentFrameIndex % this.animationFrames.length + this.animationFrames.length) % this.animationFrames.length;
this.currentFrameIndex = (this.currentFrameIndex % this.assetNames.length + this.assetNames.length) % this.assetNames.length;
} else {
if (this.currentFrameIndex >= this.animationFrames.length) {
this.currentFrameIndex = this.animationFrames.length - 1;
if (this.currentFrameIndex >= this.assetNames.length) {
this.currentFrameIndex = this.assetNames.length - 1;
this.playing = false;
}
}

this.currentFrame = this.animationFrames[this.currentFrameIndex];
}
}

play(assets, loop) {
if (assets) {
this.loop = loop ? loop : false;
this.playing = true;
this.animationFrames = assets;
this.assetNames = assets;
this.currentFrameIndex = 0;
this.animationInterval = this.animationFrameDuration;

this.currentFrame = this.animationFrames[this.currentFrameIndex];
}
}

getCurrentFrame() {
return this.animationFrames[this.currentFrameIndex];
getCurrentAssetName() {
return this.assetNames[this.currentFrameIndex];
}
}
4 changes: 2 additions & 2 deletions src/Core/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ export class Game {

checkRhinoSpawn() {
if (!this.rhino) {
let totalTimer = gameManager.getTotalTimer();
if (totalTimer >= Constants.RHINO_STARTING_TIMER) {
let score = gameManager.getScore();
if (score >= Constants.RHINO_STARTING_NUMBER) {
this.rhino = new Rhino(this.skier.x, this.skier.y - Constants.RHINO_STARTING_DISTANCE);
this.rhino.chase(this.skier);
}
Expand Down
5 changes: 2 additions & 3 deletions src/Entities/Character.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export class Character extends Entity {

setDirection(direction) {
this.direction = direction;
this.updateAsset();
}

update() {
Expand Down Expand Up @@ -79,8 +78,8 @@ export class Character extends Entity {
}

checkIfSkierHitObstacle(obstacleManager, assetManager) {
this.asset = assetManager.getAsset(this.assetName);
this.myBounds = this.getBounds(this, this.asset);
this.myAsset = assetManager.getAsset(this.assetName);
this.myBounds = this.getBounds(this, this.myAsset);

const collision = obstacleManager.getObstacles().find((obstacle) => {
const obstacleAsset = assetManager.getAsset(obstacle.getAssetName());
Expand Down
28 changes: 14 additions & 14 deletions src/Entities/Obstacles/ObstacleManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ const RAMP_CHANCE = 100;
export class ObstacleManager {
obstacles = [];

constructor() {
}
constructor() {}

getObstacles() {
return this.obstacles;
Expand All @@ -32,7 +31,7 @@ export class ObstacleManager {
const minY = STARTING_OBSTACLE_GAP;
const maxY = Constants.GAME_HEIGHT / 2;

for(let i = 0; i < numberObstacles; i++) {
for (let i = 0; i < numberObstacles; i++) {
this.placeRandomObstacle(minX, maxX, minY, maxY);
}

Expand All @@ -42,30 +41,32 @@ export class ObstacleManager {
}

placeNewObstacle(gameWindow, previousGameWindow) {
const shouldPlaceObstacle = randomInt(1, NEW_OBSTACLE_CHANCE);
if(shouldPlaceObstacle !== NEW_OBSTACLE_CHANCE) {
const shouldPlaceObstacle = this.getObstacleChance();
if (shouldPlaceObstacle !== NEW_OBSTACLE_CHANCE) {
return;
}

if (!previousGameWindow) {
previousGameWindow = gameWindow;
}

if(gameWindow.left < previousGameWindow.left) {
if (gameWindow.left < previousGameWindow.left) {
this.placeObstacleLeft(gameWindow);
}
else if(gameWindow.left > previousGameWindow.left) {
} else if (gameWindow.left > previousGameWindow.left) {
this.placeObstacleRight(gameWindow);
}

if(gameWindow.top < previousGameWindow.top) {
if (gameWindow.top < previousGameWindow.top) {
this.placeObstacleTop(gameWindow);
}
else if(gameWindow.top > previousGameWindow.top) {
} else if (gameWindow.top > previousGameWindow.top) {
this.placeObstacleBottom(gameWindow);
}
};

getObstacleChance(){
return randomInt(1, NEW_OBSTACLE_CHANCE)
}

placeObstacleLeft(gameWindow) {
this.placeRandomObstacle(gameWindow.left, gameWindow.left, gameWindow.top, gameWindow.bottom);
}
Expand Down Expand Up @@ -107,10 +108,9 @@ export class ObstacleManager {
);
});

if(foundCollision) {
if (foundCollision) {
return this.calculateOpenPosition(minX, maxX, minY, maxY);
}
else {
} else {
return {
x: x,
y: y
Expand Down
61 changes: 43 additions & 18 deletions src/Entities/Rhino.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export class Rhino extends Character {
isEating = false;
target = null;

xDiff = 0;

constructor(x, y) {
super(x, y);

Expand All @@ -28,22 +30,19 @@ export class Rhino extends Character {
}

updateAsset() {
this.assetName = this.animationController.getCurrentFrame();
this.assetName = this.animationController.getCurrentAssetName();
}

move() {
if (this.target) {

let xDiff = Math.abs(this.x - this.target.x);

if (xDiff < this.speedX) {
this.setDirection(Constants.CHARACTER_DIRECTIONS.DOWN);
} else if (this.target.x < this.x && this.target.direction !== Constants.CHARACTER_DIRECTIONS.DOWN) {
this.animationController.play(this.runLeftAnimation, true);
this.setDirection(Constants.CHARACTER_DIRECTIONS.LEFT_DOWN);
} else if (this.target.x > this.x && this.target.direction !== Constants.CHARACTER_DIRECTIONS.DOWN) {
this.animationController.play(this.runRightAnimation, true);
this.setDirection(Constants.CHARACTER_DIRECTIONS.RIGHT_DOWN);
this.xDiff = Math.abs(this.x - this.target.x);

if (this.x === this.target.x) {
this.turnDown();
} else if (this.target.x < this.x) {
this.turnLeft();
} else if (this.target.x > this.x) {
this.turnRight();
}

this.switchDirection();
Expand All @@ -53,29 +52,55 @@ export class Rhino extends Character {
switchDirection() {
switch (this.direction) {
case Constants.CHARACTER_DIRECTIONS.LEFT_DOWN:
this.animationController.play(this.runLeftAnimation, true);
this.moveLeftDown();
break;
case Constants.CHARACTER_DIRECTIONS.DOWN:
this.moveDown();
break;
case Constants.CHARACTER_DIRECTIONS.RIGHT_DOWN:
this.animationController.play(this.runRightAnimation, true);
this.moveRightDown();
break;
}
}

moveLeftDown() {
let amountToMoveX = this.setAmountToMove();

if (this.canMove) {
this.x -= amountToMoveX;
this.y += this.speedY * this.diagonalFactor;
}
}

moveRightDown() {
let amountToMoveX = this.setAmountToMove();

if (this.canMove) {
this.x += amountToMoveX;
this.y += this.speedY * this.diagonalFactor;
}
}

setAmountToMove() {
let amountToMoveX = this.speedX * this.diagonalFactor;

if (this.xDiff < amountToMoveX) {
amountToMoveX = this.xDiff;
}

return amountToMoveX;
}

turnLeft() {
if (this.direction === Constants.CHARACTER_DIRECTIONS.LEFT) {
this.moveLeft();
} else {
if (this.direction !== Constants.CHARACTER_DIRECTIONS.LEFT_DOWN) {
this.setDirection(this.direction - 1);
}
}

turnRight() {
if (this.direction === Constants.CHARACTER_DIRECTIONS.RIGHT) {
this.moveRight();
} else {
if (this.direction !== Constants.CHARACTER_DIRECTIONS.RIGHT_DOWN) {
this.setDirection(this.direction + 1);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Entities/Skier.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class Skier extends Character {

updateAsset() {
if (this.isJumping) {
this.assetName = this.animationController.getCurrentFrame();
this.assetName = this.animationController.getCurrentAssetName();
} else {
this.assetName = Constants.SKIER_DIRECTION_ASSET[this.direction];
}
Expand Down Expand Up @@ -59,7 +59,7 @@ export class Skier extends Character {
this.speedY *= Constants.SKIER_JUMP_FACTOR;
}
else {
this.speedY = Constants.RHINO_STARTING_SPEED * 1;
this.speedY = Constants.SKIER_STARTING_SPEED;
}
}

Expand Down
19 changes: 9 additions & 10 deletions src/Test/AnimationController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('no loop animation controller tests', () => {
animationController.play(longAnimation);

let firstFrame = longAnimation[0];
let frame = animationController.getCurrentFrame();
let frame = animationController.getCurrentAssetName();

expect(frame).toBeDefined();
expect(frame).toEqual(firstFrame);
Expand All @@ -55,7 +55,7 @@ describe('no loop animation controller tests', () => {
animationController.update();

let secondFrame = longAnimation[1];
let frame = animationController.getCurrentFrame();
let frame = animationController.getCurrentAssetName();

expect(frame).toBeDefined();
expect(frame).toEqual(secondFrame);
Expand All @@ -69,7 +69,7 @@ describe('no loop animation controller tests', () => {
animationController.update();

let lastFrame = longAnimation[longAnimation.length - 1];
let frame = animationController.getCurrentFrame();
let frame = animationController.getCurrentAssetName();

expect(frame).toBeDefined();
expect(frame).toEqual(lastFrame);
Expand All @@ -83,7 +83,7 @@ describe('no loop animation controller tests', () => {
animationController.update();

let lastFrame = singleFrameAnimation[singleFrameAnimation.length - 1];
let frame = animationController.getCurrentFrame();
let frame = animationController.getCurrentAssetName();

expect(frame).toBeDefined();
expect(frame).toEqual(lastFrame);
Expand All @@ -100,7 +100,7 @@ describe('no loop animation controller tests', () => {
animationController.update();

let lastFrame = longAnimation[longAnimation.length - 1];
let frame = animationController.getCurrentFrame();
let frame = animationController.getCurrentAssetName();

expect(frame).toBeDefined();
expect(frame).toEqual(lastFrame);
Expand All @@ -111,9 +111,8 @@ describe('no loop animation controller tests', () => {

animationController.currentFrameIndex = longAnimation.length;
animationController.update();

let lastFrame = longAnimation[longAnimation.length - 1];
let frame = animationController.getCurrentFrame();

let frame = animationController.getCurrentAssetName();

expect(frame).toBeUndefined();
});
Expand All @@ -135,7 +134,7 @@ describe('when looping animations', () => {
animationController.play(runLeftAnimation, true);

let firstFrame = runLeftAnimation[0];
let frame = animationController.getCurrentFrame();
let frame = animationController.getCurrentAssetName();

expect(frame).toBeDefined();
expect(frame).toEqual(firstFrame);
Expand All @@ -151,7 +150,7 @@ describe('when looping animations', () => {
animationController.update();

let secondFrame = runLeftAnimation[1];
let frame = animationController.getCurrentFrame();
let frame = animationController.getCurrentAssetName();

expect(frame).toBeDefined();
expect(frame).toEqual(secondFrame);
Expand Down
3 changes: 2 additions & 1 deletion src/Test/Mocks.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const CANVAS = { setDrawOffset: () => jest.fn(), measureUiText: () => jest.fn(), drawText: () => jest.fn() };
export const ASSET_MANAGER = { loadAssets: () => jest.fn(), getAsset: () => ({ width: 0, height: 0 }) };
export const ASSET_MANAGER = { loadAssets: () => jest.fn(), getAsset: () => ({ width: 0, height: 0 }) };
export const GAME_WINDOW = { left: 0, top: 0, right: 1000, bottom: 1000 };
Loading

0 comments on commit b972012

Please sign in to comment.