--- id: 64cb2da32f8443669fd4e725 title: Step 96 challengeType: 0 dashedName: step-96 --- # --description-- The next step is to add the `width` and `height` to the `CheckPoint` class. The `width` and `height` should be `proportionalSize(40)` and `proportionalSize(70)` respectively. # --hints-- You should have a `width` property inside the `CheckPoint` class. ```js const splitter = code.split("ctx.fillRect(this.position.x, this.position.y, this.width, this.height);") assert.match(splitter[2], /this\.width\s*;?/); ``` You should have a `height` property inside the `CheckPoint` class. ```js const splitter = code.split("ctx.fillRect(this.position.x, this.position.y, this.width, this.height);") assert.match(splitter[2], /this\.height\s*;?/); ``` You should assign the `width` property to `proportionalSize(40)`. ```js const splitter = code.split("ctx.fillRect(this.position.x, this.position.y, this.width, this.height);") assert.match(splitter[2], /this\.width\s*=\s*proportionalSize\(\s*40\s*\)\s*;?/); ``` You should assign the `height` property to `proportionalSize(70)`. ```js const splitter = code.split("ctx.fillRect(this.position.x, this.position.y, this.width, this.height);") assert.match(splitter[2], /this\.height\s*=\s*proportionalSize\(\s*70\s*\)\s*;?/); ``` # --seed-- ## --seed-contents-- ```html Learn Intermediate OOP by Building a Platformer Game

freeCodeCamp Code Warrior

Help the main player navigate to the yellow checkpoints.

Use the keyboard arrows to move the player around.

You can also use the spacebar to jump.

Congrats!

You reached the last checkpoint.

``` ```css * { margin: 0; padding: 0; box-sizing: border-box; } :root { --main-bg-color: #0a0a23; --section-bg-color: #ffffff; --golden-yellow: #feac32; } body { background-color: var(--main-bg-color); } .start-screen { background-color: var(--section-bg-color); width: 100%; position: absolute; top: 50%; left: 50%; margin-right: -50%; transform: translate(-50%, -50%); border-radius: 30px; padding: 20px; padding-bottom: 5px; } .main-title { text-align: center; } .instructions { text-align: center; font-size: 1.2rem; margin: 15px; line-height: 2rem; } .btn { cursor: pointer; width: 100px; margin: 10px; color: #0a0a23; font-size: 18px; background-color: var(--golden-yellow); background-image: linear-gradient(#fecc4c, #ffac33); border-color: var(--golden-yellow); border-width: 3px; } .btn:hover { background-image: linear-gradient(#ffcc4c, #f89808); } .btn-container { display: flex; align-items: center; justify-content: center; } .checkpoint-screen { position: absolute; left: 0; right: 0; margin-left: auto; margin-right: auto; width: 100%; text-align: center; background-color: var(--section-bg-color); border-radius: 20px; padding: 10px; display: none; } #canvas { display: none; } @media (min-width: 768px) { .start-screen { width: 60%; max-width: 700px; } .checkpoint-screen { max-width: 300px; } } ``` ```js const startBtn = document.getElementById("start-btn"); const canvas = document.getElementById("canvas"); const startScreen = document.querySelector(".start-screen"); const checkpointScreen = document.querySelector(".checkpoint-screen"); const checkpointMessage = document.querySelector(".checkpoint-screen > p"); const ctx = canvas.getContext("2d"); canvas.width = innerWidth; canvas.height = innerHeight; const gravity = 0.5; let isCheckpointCollisionDetectionActive = true; const proportionalSize = (size) => { return innerHeight < 500 ? Math.ceil((size / 500) * innerHeight) : size; } class Player { constructor() { this.position = { x: proportionalSize(10), y: proportionalSize(400), }; this.velocity = { x: 0, y: 0, }; this.width = proportionalSize(40); this.height = proportionalSize(40); } draw() { ctx.fillStyle = "#99c9ff"; ctx.fillRect(this.position.x, this.position.y, this.width, this.height); } update() { this.draw(); this.position.x += this.velocity.x; this.position.y += this.velocity.y; if (this.position.y + this.height + this.velocity.y <= canvas.height) { if (this.position.y < 0) { this.position.y = 0; this.velocity.y = gravity; } this.velocity.y += gravity; } else { this.velocity.y = 0; } if (this.position.x < this.width) { this.position.x = this.width; } if (this.position.x >= canvas.width - 2 * this.width) { this.position.x = canvas.width - 2 * this.width; } } } class Platform { constructor(x, y) { this.position = { x, y, }; this.width = 200; this.height = proportionalSize(40); } draw() { ctx.fillStyle = "#acd157"; ctx.fillRect(this.position.x, this.position.y, this.width, this.height); } } --fcc-editable-region-- class CheckPoint { constructor(x, y, z) { this.position = { x, y, }; }; }; --fcc-editable-region-- const player = new Player(); const platformPositions = [ { x: 500, y: proportionalSize(450) }, { x: 700, y: proportionalSize(400) }, { x: 850, y: proportionalSize(350) }, { x: 900, y: proportionalSize(350) }, { x: 1050, y: proportionalSize(150) }, { x: 2500, y: proportionalSize(450) }, { x: 2900, y: proportionalSize(400) }, { x: 3150, y: proportionalSize(350) }, { x: 3900, y: proportionalSize(450) }, { x: 4200, y: proportionalSize(400) }, { x: 4400, y: proportionalSize(200) }, { x: 4700, y: proportionalSize(150) }, ]; const platforms = platformPositions.map( (platform) => new Platform(platform.x, platform.y) ); const animate = () => { requestAnimationFrame(animate); ctx.clearRect(0, 0, canvas.width, canvas.height); platforms.forEach((platform) => { platform.draw(); }); player.update(); if (keys.rightKey.pressed && player.position.x < proportionalSize(400)) { player.velocity.x = 5; } else if (keys.leftKey.pressed && player.position.x > proportionalSize(100)) { player.velocity.x = -5; } else { player.velocity.x = 0; if (keys.rightKey.pressed && isCheckpointCollisionDetectionActive) { platforms.forEach((platform) => { platform.position.x -= 5; }); } else if (keys.leftKey.pressed && isCheckpointCollisionDetectionActive) { platforms.forEach((platform) => { platform.position.x += 5; }); } } platforms.forEach((platform) => { const collisionDetectionRules = [ player.position.y + player.height <= platform.position.y, player.position.y + player.height + player.velocity.y >= platform.position.y, player.position.x >= platform.position.x - player.width / 2, player.position.x <= platform.position.x + platform.width - player.width / 3, ]; if (collisionDetectionRules.every((rule) => rule)) { player.velocity.y = 0; return; } const platformDetectionRules = [ player.position.x >= platform.position.x - player.width / 2, player.position.x <= platform.position.x + platform.width - player.width / 3, player.position.y + player.height >= platform.position.y, player.position.y <= platform.position.y + platform.height, ]; if (platformDetectionRules.every(rule => rule)) { player.position.y = platform.position.y + player.height; player.velocity.y = gravity; }; }); } const keys = { rightKey: { pressed: false }, leftKey: { pressed: false } }; const movePlayer = (key, xVelocity, isPressed) => { if (!isCheckpointCollisionDetectionActive) { player.velocity.x = 0; player.velocity.y = 0; return; } switch (key) { case "ArrowLeft": keys.leftKey.pressed = isPressed; if (xVelocity === 0) { player.velocity.x = xVelocity; } player.velocity.x -= xVelocity; break; case "ArrowUp": case " ": case "Spacebar": player.velocity.y -= 8; break; case "ArrowRight": keys.rightKey.pressed = isPressed; if (xVelocity === 0) { player.velocity.x = xVelocity; } player.velocity.x += xVelocity; } } const startGame = () => { canvas.style.display = "block"; startScreen.style.display = "none"; animate(); } startBtn.addEventListener("click", startGame); window.addEventListener("keydown", ({ key }) => { movePlayer(key, 8, true); }); window.addEventListener("keyup", ({ key }) => { movePlayer(key, 0, false); }); ```