Final Individual Game Review
yayayay
Final Individual Review
In this month-long group project, I learned a variety of different skills, both code related and non-code related. I learned how to work as a team to integrate a computer science blog and project. My group was able to cooperate together and bounce ideas off of each other to futher devlop our game. At some points, if one person couldn’t get something to work, they would pass it on to the next person to try and so on and so forth. Regarding code, I learned how to properly debug code that didnt work by checking the console in inspect. I learned about sprite movement, key inputs, collision, and looping. I learned about how to interpert chatGPT code and how to effectively ask for correct code.
Code for Box Character Sprite
- jumping animation is run only when up key/w is pressed
- able to jump and move at the same time
%%html
<body>
<div>
<canvas id="spriteContainer">
<img id="box" src="/student/images/box.png">
</canvas>
</div>
</body>
<script>
window.addEventListener('load', function () {
const canvas = document.getElementById('spriteContainer');
const ctx = canvas.getContext('2d');
const SPRITE_WIDTH = 71.75;
const SPRITE_HEIGHT = 82.5;
const SCALE_FACTOR = 2;
const DESIRED_FRAME_RATE = 15;
const FRAME_INTERVAL = 1000 / DESIRED_FRAME_RATE;
canvas.width = SPRITE_WIDTH * SCALE_FACTOR * 7;
canvas.height = SPRITE_HEIGHT * SCALE_FACTOR;
class Box {
constructor() {
this.image = document.getElementById("box");
this.spriteWidth = SPRITE_WIDTH;
this.spriteHeight = SPRITE_HEIGHT;
this.width = this.spriteWidth;
this.height = this.spriteHeight;
this.x = 0;
this.y = 0;
this.scale = SCALE_FACTOR;
this.minFrame = 0;
this.frameY = 0;
this.frameX = 0;
this.maxFrame = 7;
this.speed = 10;
}
setFrameLimit(limit) {
this.maxFrame = limit;
}
setPosition(x, y) {
this.x = x;
this.y = y;
}
draw(context) {
context.drawImage(
this.image,
this.frameX * this.spriteWidth,
this.frameY * this.spriteHeight,
this.spriteWidth,
this.spriteHeight,
this.x,
this.y,
this.width * this.scale,
this.height * this.scale
);
}
update() {
if (this.frameX < this.maxFrame) {
this.frameX++;
} else {
this.frameX = 0;
}
}
}
const box = new Box();
const keyState = {
ArrowLeft: false,
ArrowRight: false,
ArrowUp: false,
};
document.addEventListener('keydown', function (event) {
switch (event.key) {
case 'w':
keyState.ArrowLeft = true;
break;
case 'a':
keyState.ArrowRight = true;
break;
case 'd':
keyState.ArrowUp = true;
break;
}
});
document.addEventListener('keyup', function (event) {
switch (event.key) {
case 'w':
keyState.ArrowLeft = false;
break;
case 'a':
keyState.ArrowRight = false;
break;
case 'd':
keyState.ArrowUp = false;
break;
}
});
function updateAnimations() {
let selectedAnimation = 'A';
box.frameY = 0;
if (keyState.ArrowLeft) {
box.x -= box.speed;
}
if (keyState.ArrowRight) {
box.x += box.speed;
}
if (keyState.ArrowUp) {
selectedAnimation = 'B';
box.frameY = 1;
}
}
let lastTimestamp = 0;
function animate(timestamp) {
const deltaTime = timestamp - lastTimestamp;
if (deltaTime >= FRAME_INTERVAL) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
box.draw(ctx);
box.update();
updateAnimations();
lastTimestamp = timestamp;
}
requestAnimationFrame(animate);
}
animate();
});
</script>
Box Issue example:
Previously, I used the keydown function to move the box left or right. This created glitchly frames and points at which the sprite kept being cutoff. The box could also only move or jump, it couldn’t jump and move at the same time. To fix this, I created variables in which the box would move if the variable was true. The variable was set to true when the key was pressed down and then set back to false when the key was released. This fixed the problem.
Integrating platform and box
- platform is drawn as the first frame
- just before box reaches platform, platform moving up animation is run
- box then interacts with platform using collison
%%html
<style>
.canvas-container {
display: flex;
background-image: url('images/Backy_Roundy.jpg');
background-size: repeat;
background-attachment: fixed;
background-repeat: repeat;
}
canvas {
margin: 0;
border: 1px solid white;
}
</style>
<body>
<div class="canvas-container">
<canvas id="playerCanvas">
<img id="box" src="/student/images/box.png">
<img id="platform" src="/student/images/platform.png">
<img id="ninjaSprite" src="/student/images/midnightStalker.png">
</canvas>
</div>
</body>
<script>
window.addEventListener('load', function () {
const canvas = document.getElementById('playerCanvas');
const ctx = canvas.getContext('2d');
const BOX_SPRITE_WIDTH = 71.75;
const BOX_SPRITE_HEIGHT = 82.5;
const BOX_SCALE_FACTOR = 2;
const DESIRED_FRAME_RATE = 15;
const FRAME_INTERVAL = 1000 / DESIRED_FRAME_RATE;
const PLATFORM_SPRITE_WIDTH = 362.25;
const PLATFORM_SPRITE_HEIGHT = 377;
const PLATFORM_SCALE_FACTOR = 0.25;
const PLATFORM_FRAME_LIMIT = 4;
const NINJA_SPRITE_WIDTH = 30;
const NINJA_SPRITE_HEIGHT = 30;
const NINJA_SCALE_FACTOR = 4;
const NINJA_FRAME_LIMIT = 5;
const NINJA_DESIRED_FRAME_RATE = 8;
const NINJA_FRAME_INTERVAL = 1000 / NINJA_DESIRED_FRAME_RATE;
const BOMB_RADIUS = 5;
const BOMB_SPEED = 20;
const BOMB_DISTANCE = 200;
const BOMB_THROW_INTERVAL = 5000; // 5 seconds
canvas.width = BOX_SPRITE_WIDTH * BOX_SCALE_FACTOR*6;
canvas.height = BOX_SPRITE_HEIGHT * BOX_SCALE_FACTOR*3;
class Box {
constructor() {
this.image = document.getElementById("box");
this.spriteWidth = BOX_SPRITE_WIDTH;
this.spriteHeight = BOX_SPRITE_HEIGHT;
this.width = this.spriteWidth;
this.height = this.spriteHeight;
this.x = 0;
this.y = 300;
this.scale = BOX_SCALE_FACTOR;
this.minFrame = 0;
this.frameY = 0;
this.frameX = 0;
this.maxFrame = 7;
this.speed = 10;
this.gravity = 0; // Gravity value
this.onPlatform = false; // Flag to track if on platform
}
setFrameLimit(limit) {
this.maxFrame = limit;
}
setPosition(x, y) {
this.x = x;
this.y = y;
}
draw(context) {
context.drawImage(
this.image,
this.frameX * this.spriteWidth,
this.frameY * this.spriteHeight,
this.spriteWidth,
this.spriteHeight,
this.x,
this.y,
this.width * this.scale,
this.height * this.scale
);
}
update() {
if (this.frameX < this.maxFrame) {
this.frameX++;
} else {
this.frameX = 0;
}
if (!this.onPlatform) {
this.y += this.gravity; // Apply gravity
}
}
checkCollision(platform) {
const isColliding = (
this.x < platform.x + platform.width * platform.scale &&
this.x + this.width * this.scale > platform.x &&
this.y < platform.y + platform.height * platform.scale &&
this.y + this.height * this.scale > platform.y
);
this.onPlatform = isColliding; // Update onPlatform flag
return isColliding;
}
}
class Platform {
constructor() {
this.image = document.getElementById("platform");
this.spriteWidth = PLATFORM_SPRITE_WIDTH;
this.spriteHeight = PLATFORM_SPRITE_HEIGHT;
this.width = this.spriteWidth;
this.height = this.spriteHeight;
this.x = 200;
this.y = 400;
this.scale = PLATFORM_SCALE_FACTOR;
this.minFrame = 0;
this.maxFrame = PLATFORM_FRAME_LIMIT;
this.frameX = 0;
this.frameY = 0;
}
draw(context) {
context.drawImage(
this.image,
this.frameX * this.spriteWidth,
this.frameY * this.spriteHeight,
this.spriteWidth,
this.spriteHeight,
this.x,
this.y,
this.width * this.scale,
this.height * this.scale
);
}
update() {
if (this.frameX < this.maxFrame) {
this.frameX++;
} else {
this.frameX = 0;
}
}
}
class Ninja {
constructor() {
this.image = document.getElementById("ninjaSprite");
this.spriteWidth = NINJA_SPRITE_WIDTH;
this.spriteHeight = NINJA_SPRITE_HEIGHT;
this.width = this.spriteWidth;
this.height = this.spriteHeight;
this.x = 0;
this.y = 350;
this.scale = NINJA_SCALE_FACTOR;
this.minFrame = 0;
this.maxFrame = NINJA_FRAME_LIMIT;
this.frameX = 0;
this.frameY = 2;
this.velocityX = 6;
this.animationCounter = 0;
this.animationLimit = 2; // Change this to control the number of times each animation should run
}
draw(context) {
context.drawImage(
this.image,
this.frameX * this.spriteWidth,
this.frameY * this.spriteHeight,
this.spriteWidth,
this.spriteHeight,
this.x,
this.y,
this.width * this.scale,
this.height * this.scale
);
}
update() {
if (this.frameX < this.maxFrame) {
this.frameX++;
} else {
this.frameX = 0;
this.animationCounter++;
if (this.animationCounter >= this.animationLimit) {
this.animationCounter = 0;
switch (this.frameY) {
case 2:
this.frameY = 5; // Switch to Sword Fighting
break;
case 5:
this.frameY = 6; // Switch to Sword Strikes
break;
case 6:
this.frameY = 2; // Switch back to Jumping
break;
}
}
}
this.x += this.velocityX;
if (this.x > canvas.width) {
this.x = -this.width * this.scale;
}
}
}
class Bomb {
constructor(x, y) {
this.x = x;
this.y = y;
this.radius = BOMB_RADIUS;
this.speed = BOMB_SPEED;
this.distanceTravelled = 0;
this.color = 'black';
}
draw(context) {
context.beginPath();
context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
context.fillStyle = this.color;
context.fill();
context.closePath();
}
update() {
this.x += this.speed;
this.distanceTravelled += this.speed;
if (this.distanceTravelled >= BOMB_DISTANCE) {
bombs.splice(bombs.indexOf(this), 1);
} else if (this.distanceTravelled >= 180) {
this.color = 'orange';
this.radius = BOMB_RADIUS * 2.5;
}
}
}
const ninja = new Ninja();
const bombs = [];
function throwBomb() {
const bomb = new Bomb(ninja.x + ninja.width * ninja.scale, ninja.y + ninja.height * ninja.scale / 2);
bombs.push(bomb);
}
function automaticBombThrow() {
throwBomb(); // Throw a bomb initially
setInterval(throwBomb, BOMB_THROW_INTERVAL);
}
automaticBombThrow(); // Start the automatic bomb throwing
const box = new Box();
const platform = new Platform();
const keyState = {
ArrowLeft: false,
ArrowRight: false,
ArrowUp: false,
};
document.addEventListener('keydown', function (event) {
switch (event.key) {
case 'w':
keyState.ArrowUp = true;
break;
case 'a':
keyState.ArrowLeft = true;
break;
case 'd':
keyState.ArrowRight = true;
break;
}
});
document.addEventListener('keyup', function (event) {
switch (event.key) {
case 'w':
keyState.ArrowUp = false;
break;
case 'a':
keyState.ArrowLeft = false;
break;
case 'd':
keyState.ArrowRight = false;
break;
}
});
function updateAnimations() {
let selectedAnimation = 'A';
box.frameY = 0;
if (keyState.ArrowLeft) {
box.x -= box.speed;
}
if (keyState.ArrowRight) {
box.x += box.speed;
}
if (keyState.ArrowUp) {
selectedAnimation = 'B';
box.frameY = 1;
}
}
let lastTimestamp = 0;
function animate(timestamp) {
const deltaTime = timestamp - lastTimestamp;
if (deltaTime >= FRAME_INTERVAL) {
ctx.clearRect(box.x, box.y, box.width * box.scale, box.height * box.scale);
ctx.clearRect(ninja.x, ninja.y, ninja.width * ninja.scale, ninja.height * ninja.scale);
if (box.checkCollision(platform)) {
box.y = platform.y - box.height * box.scale;
platform.y = box.y + box.height * box.scale;
} else {
box.onPlatform = false;
}
box.draw(ctx);
box.update();
updateAnimations();
ninja.draw(ctx);
ninja.update();
bombs.forEach(bomb => {
bomb.draw(ctx);
bomb.update();
});
lastTimestamp = timestamp;
}
requestAnimationFrame(animate);
}
animate();
let animationHasRun = false;
let platformAnimationFinished = false;
function animatePlatform() {
if (!platformAnimationFinished) {
ctx.clearRect(platform.x, platform.y, platform.width, platform.height);
platform.draw(ctx);
platform.update();
if (platform.frameX === platform.maxFrame) {
platformAnimationFinished = true;
}
if (!platformAnimationFinished) {
setTimeout(function () {
requestAnimationFrame(animatePlatform);
}, 100);
}
}
}
if (box.frameX*box.scale >= 180){
if (!animationHasRun) {
animationHasRun = true;
platformAnimationFinished = false;
animatePlatform();
}
}
});
</script>
picture of this

ChatGPT logs are Here.