Skip to content

Commit aa93325

Browse files
committed
new(apps): pong game with obstacles
1 parent 5cd20b5 commit aa93325

File tree

1 file changed

+58
-3
lines changed

1 file changed

+58
-3
lines changed

src/pages/apps/SoccerPongPage.js

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ const PADDLE_HEIGHT = 80;
1313
const BALL_SIZE = 15;
1414
const PADDLE_SPEED = 5;
1515
const BALL_SPEED = 4;
16-
// const MAX_SCORE = 5; // Removed hardcoded constant
16+
17+
// Obstacle Constants
18+
const OBSTACLE_WIDTH = 10;
19+
const OBSTACLE_HEIGHT = 60;
20+
const OBSTACLE_SPEED = 2;
1721

1822
const SoccerPongPage = () => {
1923
useSeo({
@@ -48,6 +52,7 @@ const SoccerPongPage = () => {
4852
ballDy: BALL_SPEED,
4953
playerMoveUp: false,
5054
playerMoveDown: false,
55+
obstacles: [], // Array to hold obstacle data
5156
});
5257

5358
const resetBall = useCallback(() => {
@@ -57,17 +62,29 @@ const SoccerPongPage = () => {
5762
gameState.current.ballDy = (Math.random() > 0.5 ? 1 : -1) * BALL_SPEED;
5863
}, []);
5964

65+
const initializeObstacles = useCallback(() => {
66+
gameState.current.obstacles = [
67+
// Left half obstacles
68+
{ x: GAME_WIDTH / 4 - OBSTACLE_WIDTH / 2, y: GAME_HEIGHT / 4, width: OBSTACLE_WIDTH, height: OBSTACLE_HEIGHT, dy: OBSTACLE_SPEED },
69+
{ x: GAME_WIDTH / 4 - OBSTACLE_WIDTH / 2, y: GAME_HEIGHT * 3 / 4 - OBSTACLE_HEIGHT, width: OBSTACLE_WIDTH, height: OBSTACLE_HEIGHT, dy: -OBSTACLE_SPEED },
70+
// Right half obstacles
71+
{ x: GAME_WIDTH * 3 / 4 - OBSTACLE_WIDTH / 2, y: GAME_HEIGHT / 4, width: OBSTACLE_WIDTH, height: OBSTACLE_HEIGHT, dy: -OBSTACLE_SPEED },
72+
{ x: GAME_WIDTH * 3 / 4 - OBSTACLE_WIDTH / 2, y: GAME_HEIGHT * 3 / 4 - OBSTACLE_HEIGHT, width: OBSTACLE_WIDTH, height: OBSTACLE_HEIGHT, dy: OBSTACLE_SPEED },
73+
];
74+
}, []);
75+
6076
const startGame = useCallback(() => {
6177
setPlayerScore(0);
6278
setAiScore(0);
6379
setGameOver(false);
6480
setWinner(null);
6581
setGoalAnimation({ active: false, scorer: null });
6682
resetBall();
83+
initializeObstacles(); // Initialize obstacles when starting game
6784
gameState.current.playerPaddleY = GAME_HEIGHT / 2 - PADDLE_HEIGHT / 2;
6885
gameState.current.aiPaddleY = GAME_HEIGHT / 2 - PADDLE_HEIGHT / 2;
6986
setGameStarted(true);
70-
}, [resetBall]);
87+
}, [resetBall, initializeObstacles]);
7188

7289
// No useEffect for auto-start, game starts only with button press
7390

@@ -97,6 +114,12 @@ const SoccerPongPage = () => {
97114
ctx.fillStyle = '#4B0082'; // Indigo
98115
ctx.fillRect(GAME_WIDTH - PADDLE_WIDTH, gameState.current.aiPaddleY, PADDLE_WIDTH, PADDLE_HEIGHT);
99116

117+
// Draw obstacles
118+
ctx.fillStyle = '#808080'; // Gray color for obstacles
119+
gameState.current.obstacles.forEach(obstacle => {
120+
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
121+
});
122+
100123
// Draw ball
101124
ctx.fillStyle = '#FFFFFF'; // White
102125
ctx.beginPath();
@@ -122,6 +145,15 @@ const SoccerPongPage = () => {
122145
gameState.current.aiPaddleY = Math.min(GAME_HEIGHT - PADDLE_HEIGHT, gameState.current.aiPaddleY + PADDLE_SPEED * 0.8);
123146
}
124147

148+
// Obstacle movement
149+
gameState.current.obstacles.forEach(obstacle => {
150+
obstacle.y += obstacle.dy;
151+
// Reverse direction if hitting top or bottom
152+
if (obstacle.y < 0 || obstacle.y + obstacle.height > GAME_HEIGHT) {
153+
obstacle.dy *= -1;
154+
}
155+
});
156+
125157
// Ball movement
126158
gameState.current.ballX += gameState.current.ballDx;
127159
gameState.current.ballY += gameState.current.ballDy;
@@ -153,6 +185,29 @@ const SoccerPongPage = () => {
153185
gameState.current.ballDy += (Math.random() - 0.5) * 2;
154186
}
155187

188+
// Ball collision with obstacles
189+
gameState.current.obstacles.forEach(obstacle => {
190+
if (
191+
gameState.current.ballX + BALL_SIZE / 2 > obstacle.x &&
192+
gameState.current.ballX - BALL_SIZE / 2 < obstacle.x + obstacle.width &&
193+
gameState.current.ballY + BALL_SIZE / 2 > obstacle.y &&
194+
gameState.current.ballY - BALL_SIZE / 2 < obstacle.y + obstacle.height
195+
) {
196+
// Collision detected, reverse ball direction
197+
// Determine if collision is horizontal or vertical for more realistic bounce
198+
const overlapX = Math.min(gameState.current.ballX + BALL_SIZE / 2, obstacle.x + obstacle.width) - Math.max(gameState.current.ballX - BALL_SIZE / 2, obstacle.x);
199+
const overlapY = Math.min(gameState.current.ballY + BALL_SIZE / 2, obstacle.y + obstacle.height) - Math.max(gameState.current.ballY - BALL_SIZE / 2, obstacle.y);
200+
201+
if (overlapX < overlapY) { // Horizontal collision
202+
gameState.current.ballDx *= -1;
203+
} else { // Vertical collision
204+
gameState.current.ballDy *= -1;
205+
}
206+
// Add a slight random angle change
207+
gameState.current.ballDy += (Math.random() - 0.5) * 2;
208+
}
209+
});
210+
156211
// Scoring
157212
if (gameState.current.ballX - BALL_SIZE / 2 < 0) { // AI scores
158213
setGoalAnimation({ active: true, scorer: 'AI' });
@@ -200,7 +255,7 @@ const SoccerPongPage = () => {
200255
return () => {
201256
cancelAnimationFrame(animationFrameId);
202257
};
203-
}, [gameStarted, gameOver, resetBall, goalAnimation.active, maxScore]); // Add maxScore to dependencies
258+
}, [gameStarted, gameOver, resetBall, goalAnimation.active, maxScore, initializeObstacles]); // Add initializeObstacles to dependencies
204259

205260
// Keyboard controls
206261
useEffect(() => {

0 commit comments

Comments
 (0)