Pair Review 1
Anvay and Yash's review of week 19 CSSE2
- Implementing and Experimenting with JavaScript Objects with our game level (Ancient Greece)
- Utilizing Finite-State Machines (FSM)
- Utilizing Single Responsibility Principle
Implementing and Experimenting with JavaScript Objects with our game level (Ancient Greece)
To our best understanding, Javascript objects are literally just objects with different properties. In our case, the game has many objects including the floor, the background, the player, the enemies, the blocks, and much more! These objects also have their own properties.
{ name: 'sandstone', id: 'jumpPlatform', class: BlockPlatform, data: this.assets.platforms.sandstone, xPercentage: 0.6, yPercentage: 0.34 },
In the above code here, we can see the object with its own properties:
- *name: The name property sets a name for the object. In this case, it’s set to ‘sandstone’.
- id: The id property specifies an identifier for the object. Here, it’s set to ‘jumpPlatform’.
- class: The class property likely the class or “type” of the object. In this case, it’s set to ‘BlockPlatform’.
- data: The data property holds some data associated with the object.
- xPercentage: This property represents the horizontal position of the object as a percentage of the screen width/container. Here, it’s set to 0.6, indicating 40% off from the right side, or 60% off from the left side.
- yPercentage: Similarly to x-percentage, this property represents the vertical position of the object as a percentage of the screen width/container.It’s set to 0.34, indicating 34%. This means that the object is placed at 66% off from the bottom of the screen, or 34% off from the top of the screen.
// Define an object
let myObject = {
name: "Team 1",
memberCount: 6,
class: "CSSE2",
memberNames: ["Anvay", "Yash", "Mihir", "Tianbin", "Quinn", "Lily"],
classroomLocation: {
location: "Del Norte High School",
building: "A",
classNumber: "101"
},
};
// Function to print all properties of the object
function printProperties(obj) {
console.log("Properties of the object:");
for (let prop in obj) {
if (typeof obj[prop] === 'object') {
console.log(`${prop}:`);
for (let subProp in obj[prop]) {
console.log(` ${subProp}: ${obj[prop][subProp]}`);
}
} else {
console.log(`${prop}: ${obj[prop]}`);
}
}
}
// Print all properties of the object
printProperties(myObject);
Utilizing Finite-State Machines (FSM)
updateAnimation() {
switch (this.state.animation) {
case 'idle':
this.setSpriteAnimation(this.playerData.idle[this.state.direction]);
break;
case 'walk':
this.setSpriteAnimation(this.playerData.walk[this.state.direction]);
break;
case 'run':
this.setSpriteAnimation(this.playerData.run[this.state.direction]);
break;
case 'jump':
this.setSpriteAnimation(this.playerData.jump[this.state.direction]);
break;
default:
console.error(`Invalid state: ${this.state.animation}`);
}
}
In the above code here, we can see the states of the knight, with properties assigned to each state:
- src: the location of the sprite sheet that the knight utilizes
- width/height: the size of one frame in the sprite sheet
- scaleSize: the size that the frame should be scaled to when used
- speedRatio: the speed ratio that the sprite should use in comparision to the :game speed”
- idle: the row and number of frames that should be ran when a key is not being pressed
- walk: the row and number of frames that should be ran when the left or right walk key is pressed (a or d)
- run: the row and number of frames that should be ran when the left or right run keys are pressed (as or sd)
- jump: the row and number of frames that should be ran when the left or right jump keys are pressed (aw, w, or wd)
- hitbox: the width/height percentage of the entire frame that should be accounted for when the player has collisions
The hard part was matching all of the frames of the actual sprite sheet to the states. The steps we took to do this were:
- Find a sprite sheet with all of the basic required animations (idle, walk, run, jump)
- After using this, we determined that the animations ran too fast, because there were only 8 frames per animation
- To fix that, I duplicated each frame twice (creating three of each frame), allowing the sprite to run an animation three times per click, essentially slowing down the frame rate
- There were only right facing animations, so we had to duplicate our entire spritesheet and reverse each sprite over the y-axis so that it faced the other way. This was a fairly meticulous process but the results were outstanding!
Utilizing Single Responsibility Principle
Single Responsiblity Principle is when a method or function has one responibility in code so that debugging and extending classes becomes much easier.
In our code, heres how we implemented it:
checkBoundaries(){
// Check for boundaries
if (this.x <= this.minPosition || (this.x + this.canvasWidth >= this.maxPosition)) {
if (this.state.direction === "left") {
this.state.animation = "right";
this.state.direction = "right";
}
else if (this.state.direction === "right") {
this.state.animation = "left";
this.state.direction = "left";
}
};
}
updateMovement(){
if (this.state.animation === "right") {
this.speed = Math.abs(this.speed)
}
else if (this.state.animation === "left") {
this.speed = -Math.abs(this.speed);
}
else if (this.state.animation === "idle") {
this.speed = 0
}
else if (this.state.animation === "death") {
this.speed = 0
}
// Move the enemy\
this.x += this.speed;
this.playerBottomCollision = false;
}
update() {
super.update();
this.setAnimation(this.state.animation);
this.checkBoundaries();
this.updateMovement();
}
Before, all of this used to be one function with many responsibilities but now, the reponsibilites are split up so that when we extend the class, we dont have to copy paste all of the code in the update function when we only want to change one small thing.