Skip to content

Commit 89ad068

Browse files
a2937jdwilkin4
andauthored
feat: create a pong prototype (#865)
* feat: create pong prototype * feat: create pong prototype * computer move better * Apply suggestions from code review Co-authored-by: Jessica Wilkins <[email protected]> * apply some suggestions * experimental mouse movement * better button styles * padding and controls * add confirmation box * chore: cleanup formatting inconsistencies * fix: removing unused variables * refactor: ball speed * fix: sliding problem for ball and paddle * refactor: game rules styles * chore: cleaning up comments * feat: adding custom reset modal --------- Co-authored-by: Jessica Wilkins <[email protected]> Co-authored-by: jdwilkin4 <[email protected]>
1 parent f702ca3 commit 89ad068

File tree

3 files changed

+407
-0
lines changed

3 files changed

+407
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Pong</title>
7+
<link rel="stylesheet" href="./styles.css" />
8+
</head>
9+
<body>
10+
<h1>Pong Game</h1>
11+
<div id="game-rules" class="game-rules center">
12+
<p>Try to score against the unbeatable computer opponent!</p>
13+
<p>Move your paddle with your mouse.</p>
14+
<br />
15+
<button id="start-game">Start Game</button>
16+
</div>
17+
<div id="game" class="hidden">
18+
<div class="center inline">
19+
<p id="player-score" class="player-score"></p>
20+
<p id="computer-score" class="computer-score"></p>
21+
</div>
22+
<canvas
23+
id="board"
24+
class="board center green-border"
25+
width="800"
26+
height="400"
27+
></canvas>
28+
<br />
29+
<button id="reset">Reset Game</button>
30+
</div>
31+
32+
<dialog id="reset-modal" class="reset-modal">
33+
<div class="modal-content">
34+
<h2>Reset Game?</h2>
35+
<p>
36+
Are you sure you want to reset the game? This will clear all scores.
37+
</p>
38+
<div class="modal-buttons">
39+
<button id="confirm-reset" class="confirm-btn">Yes, reset</button>
40+
<button id="cancel-reset" class="cancel-btn">Cancel</button>
41+
</div>
42+
</div>
43+
</dialog>
44+
45+
<script src="./script.js"></script>
46+
</body>
47+
</html>

coding-challenges/pong-game/script.js

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
let lastTime = 0;
2+
let delta = 1;
3+
let playerScore = 0;
4+
let computerScore = 0;
5+
let gameRunning = false;
6+
const playerOneScoreElement = document.querySelector("#player-score");
7+
const playerTwoScoreElement = document.querySelector("#computer-score");
8+
const canvas = document.getElementById("board");
9+
const startGameButton = document.getElementById("start-game");
10+
const resetGameButton = document.getElementById("reset");
11+
const resetModal = document.getElementById("reset-modal");
12+
const confirmResetButton = document.getElementById("confirm-reset");
13+
const cancelResetButton = document.getElementById("cancel-reset");
14+
const ctx = canvas.getContext("2d");
15+
16+
// Paddle Variables
17+
const paddleWidth = 10;
18+
const paddleHeight = 100;
19+
20+
let paddle1Y = canvas?.height / 2 - paddleHeight / 2;
21+
22+
let paddle2Y = canvas?.height / 2 - paddleHeight / 2;
23+
24+
// Ball Variables
25+
const ballSize = 10;
26+
27+
let ballX = canvas?.width / 2;
28+
29+
let ballY = canvas?.height / 2;
30+
let ballSpeedX = 3.5;
31+
let ballSpeedY = 3.5;
32+
33+
function startGame() {
34+
const gameRules = document.querySelector(".game-rules");
35+
const game = document.querySelector("#game");
36+
gameRules?.classList.add("hidden");
37+
game?.classList.remove("hidden");
38+
39+
playerOneScoreElement.textContent = "Player: " + playerScore;
40+
41+
playerTwoScoreElement.textContent = "Computer: " + computerScore;
42+
gameRunning = true;
43+
gameLoop();
44+
}
45+
46+
function resetGame() {
47+
gameRunning = false;
48+
resetModal.showModal();
49+
}
50+
51+
function confirmReset() {
52+
playerScore = 0;
53+
computerScore = 0;
54+
55+
playerOneScoreElement.textContent = "Player: " + playerScore;
56+
playerTwoScoreElement.textContent = "Computer: " + computerScore;
57+
58+
resetModal.close();
59+
gameRunning = true;
60+
}
61+
62+
function cancelReset() {
63+
resetModal.close();
64+
gameRunning = true;
65+
} // Draw Functions
66+
/**
67+
* @param {number} x
68+
* @param {number} y
69+
* @param {number} width
70+
* @param {number} height
71+
* @param {string} color
72+
*/
73+
function drawRect(x, y, width, height, color) {
74+
ctx.fillStyle = color;
75+
ctx.fillRect(x, y, width, height);
76+
}
77+
78+
/**
79+
* @param {number} x
80+
* @param {number} y
81+
* @param {number} radius
82+
* @param {string} color
83+
*/
84+
function drawCircle(x, y, radius, color) {
85+
ctx.fillStyle = color;
86+
ctx.beginPath();
87+
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
88+
ctx.fill();
89+
}
90+
91+
function drawSeparator() {
92+
ctx.beginPath();
93+
ctx.setLineDash([5, 15]);
94+
95+
ctx.moveTo(canvas?.width / 2, 0);
96+
97+
ctx.lineTo(canvas?.height, canvas?.width / 2);
98+
ctx.strokeStyle = "#8dff41";
99+
100+
ctx.stroke();
101+
}
102+
103+
function draw() {
104+
// Clear Canvas
105+
drawRect(0, 0, canvas?.width, canvas?.height, "#005430");
106+
107+
drawSeparator();
108+
109+
// Draw Paddles
110+
drawRect(0, paddle1Y, paddleWidth, paddleHeight, "#00df86");
111+
drawRect(
112+
canvas?.width - paddleWidth,
113+
paddle2Y,
114+
paddleWidth,
115+
paddleHeight,
116+
"#00df86"
117+
);
118+
119+
// Draw Ball
120+
drawCircle(ballX, ballY, ballSize, "#92e84c");
121+
}
122+
123+
function increasePlayerScore() {
124+
playerScore++;
125+
playerOneScoreElement.textContent = "Player: " + playerScore.toString();
126+
}
127+
128+
function increaseComputerScore() {
129+
computerScore++;
130+
playerTwoScoreElement.textContent = "Computer: " + computerScore.toString();
131+
}
132+
133+
function update() {
134+
if (!gameRunning) return;
135+
136+
// Move Ball
137+
ballX += ballSpeedX;
138+
ballY += ballSpeedY;
139+
140+
// Ball Collision with Top and Bottom Walls
141+
if (ballY - ballSize < 0 || ballY + ballSize > canvas?.height) {
142+
ballSpeedY = -ballSpeedY;
143+
}
144+
145+
// Left paddle collision
146+
if (
147+
ballX - ballSize <= paddleWidth &&
148+
ballX - ballSize > 0 &&
149+
ballY >= paddle1Y &&
150+
ballY <= paddle1Y + paddleHeight &&
151+
ballSpeedX < 0
152+
) {
153+
ballSpeedX = -ballSpeedX;
154+
ballX = paddleWidth + ballSize;
155+
}
156+
157+
// Right paddle collision
158+
if (
159+
ballX + ballSize >= canvas?.width - paddleWidth &&
160+
ballX + ballSize < canvas?.width &&
161+
ballY >= paddle2Y &&
162+
ballY <= paddle2Y + paddleHeight &&
163+
ballSpeedX > 0
164+
) {
165+
ballSpeedX = -ballSpeedX;
166+
ballX = canvas?.width - paddleWidth - ballSize;
167+
}
168+
169+
const paddle2Center = paddleHeight / 2 + paddle2Y;
170+
if (paddle2Center < ballY - 35) {
171+
paddle2Y += 6;
172+
} else if (paddle2Center > ballY + 35) {
173+
paddle2Y -= 6;
174+
}
175+
176+
// Ball Out of Bounds
177+
if (ballX - ballSize < 0) {
178+
increaseComputerScore();
179+
resetBall();
180+
} else if (ballX + ballSize > canvas?.width) {
181+
increasePlayerScore();
182+
resetBall();
183+
}
184+
}
185+
186+
function resetBall() {
187+
ballX = canvas?.width / 2;
188+
ballY = canvas?.height / 2;
189+
ballSpeedX = -ballSpeedX;
190+
}
191+
192+
function calculateMousePos(evt) {
193+
const rect = canvas.getBoundingClientRect();
194+
const root = document.documentElement;
195+
const mouseX = evt.clientX - rect.left - root.scrollLeft;
196+
const mouseY = evt.clientY - rect.top - root.scrollTop;
197+
return {
198+
x: mouseX,
199+
y: mouseY,
200+
};
201+
}
202+
203+
canvas.addEventListener("mousemove", function (evt) {
204+
const mousePos = calculateMousePos(evt);
205+
paddle1Y = mousePos.y - paddleHeight / 2;
206+
paddle1Y = Math.min(Math.max(0, paddle1Y), canvas?.height - paddleHeight);
207+
});
208+
209+
// Game Loop
210+
/**
211+
* @param {number | undefined} [currentTime]
212+
*/
213+
function gameLoop(currentTime) {
214+
if (lastTime !== undefined && currentTime !== undefined) {
215+
delta = Math.round(currentTime - lastTime);
216+
lastTime = currentTime;
217+
}
218+
draw();
219+
update();
220+
requestAnimationFrame(gameLoop);
221+
}
222+
223+
startGameButton?.addEventListener("click", startGame);
224+
resetGameButton?.addEventListener("click", resetGame);
225+
confirmResetButton?.addEventListener("click", confirmReset);
226+
cancelResetButton?.addEventListener("click", cancelReset);
227+
228+
// Close modal when clicking outside of it
229+
resetModal?.addEventListener("click", (e) => {
230+
if (e.target === resetModal) {
231+
resetModal.close();
232+
gameRunning = true;
233+
}
234+
});

0 commit comments

Comments
 (0)