@@ -13,7 +13,11 @@ const PADDLE_HEIGHT = 80;
1313const BALL_SIZE = 15 ;
1414const PADDLE_SPEED = 5 ;
1515const 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
1822const 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