mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2025-12-22 11:36:11 -05:00
9.5 KiB
9.5 KiB
id, title, challengeType, dashedName
| id | title | challengeType | dashedName |
|---|---|---|---|
| 64cb3f62b10c336bada1c70c | Step 102 | 0 | step-102 |
--description--
Inside the animate function, you will need to draw each of the checkpoints onto the canvas.
Add a forEach loop that iterates through the checkpoints array.
Inside the callback function, add a checkpoint parameter and for the body of the function call the draw method on each checkpoint.
--hints--
You should have a forEach loop that iterates through the checkpoints array.
assert.match(code, /\bcheckpoints\b\s*\.\s*forEach\s*\(/s);
You should have a checkpoint parameter inside the forEach callback function.
assert.match(code, /\s*checkpoints\s*\.\s*forEach\s*\(\s*(\(\s*checkpoint\s*\)|checkpoint)\s*=>\s*{?/s);
You should call the draw method on each checkpoint inside the forEach callback function.
assert.match(code, /\s*checkpoints\.forEach\s*\(\s*(\(\s*checkpoint\s*\)|checkpoint)\s*=>\s*(\{\s*checkpoint\.draw\(\s*\)\s*;?\s*\}|checkpoint\.draw\(\s*\))\s*\)\s*;?/s);
--seed--
--seed-contents--
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Learn Intermediate OOP by Building a Platformer Game</title>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div class="start-screen">
<h1 class="main-title">freeCodeCamp Code Warrior</h1>
<p class="instructions">
Help the main player navigate to the yellow checkpoints.
</p>
<p class="instructions">
Use the keyboard arrows to move the player around.
</p>
<p class="instructions">You can also use the spacebar to jump.</p>
<div class="btn-container">
<button class="btn" id="start-btn">Start Game</button>
</div>
</div>
<div class="checkpoint-screen">
<h2>Congrats!</h2>
<p>You reached the last checkpoint.</p>
</div>
<canvas id="canvas"></canvas>
<script src="./script.js"></script>
</body>
</html>
* {
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;
}
}
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);
}
}
class CheckPoint {
constructor(x, y, z) {
this.position = {
x,
y,
};
this.width = proportionalSize(40);
this.height = proportionalSize(70);
this.claimed = false;
};
draw() {
ctx.fillStyle = "#f1be32";
ctx.fillRect(this.position.x, this.position.y, this.width, this.height);
}
claim() {
this.width = 0;
this.height = 0;
this.position.y = Infinity;
this.claimed = true;
}
};
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 checkpointPositions = [
{ x: 1170, y: proportionalSize(80), z: 1 },
{ x: 2900, y: proportionalSize(330), z: 2 },
{ x: 4800, y: proportionalSize(80), z: 3 },
];
const checkpoints = checkpointPositions.map(
(checkpoint) => new CheckPoint(checkpoint.x, checkpoint.y, checkpoint.z)
);
const animate = () => {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvas.width, canvas.height);
platforms.forEach((platform) => {
platform.draw();
});
--fcc-editable-region--
--fcc-editable-region--
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);
});