Gregniuki commited on
Commit
adb0008
·
verified ·
1 Parent(s): 484355f

Update script.js

Browse files
Files changed (1) hide show
  1. script.js +188 -95
script.js CHANGED
@@ -5,155 +5,248 @@ const ball = document.getElementById('ball');
5
  const playerScoreDisplay = document.getElementById('playerScore');
6
  const botScoreDisplay = document.getElementById('botScore');
7
 
8
- let paddleLeftY = window.innerHeight / 2 - 40;
9
- let paddleRightY = window.innerHeight / 2 - 40;
10
- let ballX = window.innerWidth / 2;
11
- let ballY = window.innerHeight / 2;
12
- let ballSpeedX = 3;
13
- let ballSpeedY = 0;
14
- let playerScore = 0;
15
- let botScore = 0;
16
- let isGamePaused = true;
17
-
18
  const paddleHeight = 80;
19
  const paddleWidth = 10;
20
  const ballSize = 15;
21
- const maxAngle = 45;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
 
23
  gameArea.addEventListener('touchmove', (e) => {
24
  e.preventDefault();
 
 
25
  let touchY = e.touches[0].clientY;
 
26
 
27
- if (e.touches[0].clientX < window.innerWidth / 2) {
 
28
  paddleLeftY = touchY - paddleHeight / 2;
 
29
  paddleLeftY = Math.max(0, Math.min(paddleLeftY, window.innerHeight - paddleHeight));
 
30
 
 
31
  if (isGamePaused) {
 
 
32
  isGamePaused = false;
33
  }
34
  }
 
 
 
 
 
 
 
 
 
 
35
  });
36
 
 
 
37
  function handlePaddleCollision(paddleY, paddleX, isLeftPaddle) {
38
  const ballRadius = ballSize / 2;
39
- const paddleRight = paddleX + paddleWidth;
 
 
40
  const paddleTop = paddleY;
41
  const paddleBottom = paddleY + paddleHeight;
42
-
43
- // Closest point on paddle to ball's center
44
- let closestX = ballX;
45
- if (isLeftPaddle) {
46
- closestX = paddleRight;
47
- } else {
48
- closestX = paddleX;
49
- }
50
-
51
- let closestY = ballY;
52
- if (ballY < paddleTop) {
53
- closestY = paddleTop;
54
- } else if (ballY > paddleBottom) {
55
- closestY = paddleBottom;
56
  }
57
 
58
- // Vector from ball to closest point
59
- const dx = ballX - closestX;
60
- const dy = ballY - closestY;
61
- const distance = Math.sqrt(dx * dx + dy * dy);
62
-
63
- if (distance <= ballRadius) {
64
- // Collision occurs
65
- // Calculate normal vector
66
- const normalX = isLeftPaddle ? 1 : -1;
67
- const normalY = 0;
68
-
69
- // Current velocity
70
- const velocity = { x: ballSpeedX, y: ballSpeedY };
71
-
72
- // Reflect velocity over the normal
73
- const dot = velocity.x * normalX + velocity.y * normalY;
74
- const reflected = {
75
- x: velocity.x - 2 * dot * normalX,
76
- y: velocity.y - 2 * dot * normalY
77
- };
78
-
79
- // Adjust Y velocity based on hit position
80
- const hitPosition = (closestY - (paddleTop + paddleHeight / 2)) / (paddleHeight / 2);
81
- const angle = hitPosition * maxAngle * (Math.PI / 180);
82
- reflected.y = Math.sin(angle) * Math.abs(reflected.x);
83
-
84
- // Set new velocity
85
- ballSpeedX = reflected.x;
86
- ballSpeedY = reflected.y;
87
-
88
- // Reposition ball outside the paddle
89
- const overlap = ballRadius - distance;
90
- ballX += normalX * overlap;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
92
  }
93
 
 
 
94
  function update() {
95
  if (!isGamePaused) {
96
- let previousBallX = ballX;
 
 
 
 
97
  ballX += ballSpeedX;
98
  ballY += ballSpeedY;
99
 
100
  // Ball collision with top and bottom walls
101
- if (ballY <= 0 || ballY >= window.innerHeight - ballSize) {
102
- ballSpeedY = -ballSpeedY;
 
 
 
 
103
  }
104
 
105
- // Check collision with left paddle using swept collision detection
106
- handlePaddleCollision(paddleLeftY, paddleWidth, true);
 
 
 
 
 
 
 
107
 
108
- // Check collision with right paddle using swept collision detection
109
- handlePaddleCollision(paddleRightY, window.innerWidth - paddleWidth - 25, false);
110
 
111
- // Ball out of bounds
112
- if (ballX <= 0) {
113
  botScore++;
114
  botScoreDisplay.textContent = botScore;
115
- resetBall('right');
116
- } else if (ballX >= window.innerWidth) {
117
  playerScore++;
118
  playerScoreDisplay.textContent = playerScore;
119
- resetBall('left');
120
  }
121
- }
122
 
123
- // Bot AI movement
124
- if (ballSpeedX > 0) {
125
- if (paddleRightY + paddleHeight / 2 < ballY) {
126
- paddleRightY += 3;
127
- } else if (paddleRightY + paddleHeight / 2 > ballY) {
128
- paddleRightY -= 3;
 
 
 
 
 
 
 
 
 
 
129
  }
130
  }
131
 
132
- paddleRightY = Math.max(0, Math.min(paddleRightY, window.innerHeight - paddleHeight));
133
-
134
  ball.style.left = ballX + 'px';
135
  ball.style.top = ballY + 'px';
136
- paddleLeft.style.top = paddleLeftY + 'px';
137
- paddleRight.style.top = paddleRightY + 'px';
 
138
 
 
139
  requestAnimationFrame(update);
140
  }
141
 
142
- function resetBall(side) {
143
- isGamePaused = true;
144
-
145
- if (side === 'left') {
146
- ballX = paddleWidth + 10;
147
- ballY = paddleLeftY + paddleHeight / 2;
148
- ballSpeedX = Math.abs(ballSpeedX);
149
- } else {
150
- ballX = window.innerWidth - paddleWidth - 25;
151
- ballY = paddleRightY + paddleHeight / 2;
152
- ballSpeedX = -Math.abs(ballSpeedX);
 
 
 
153
  }
154
 
 
155
  ballSpeedY = 0;
 
 
 
 
 
 
 
 
156
  }
157
 
 
 
 
 
 
 
 
 
 
 
 
158
  // Start the game loop
159
- update();
 
5
  const playerScoreDisplay = document.getElementById('playerScore');
6
  const botScoreDisplay = document.getElementById('botScore');
7
 
8
+ // --- Constants ---
 
 
 
 
 
 
 
 
 
9
  const paddleHeight = 80;
10
  const paddleWidth = 10;
11
  const ballSize = 15;
12
+ const maxAngle = 45; // Max bounce angle in degrees
13
+ const initialBallSpeedX = 4; // Starting horizontal speed
14
+ const speedIncreaseFactor = 1.1; // Speed multiplier on hit
15
+ const maxBallSpeed = 15; // Maximum overall ball speed
16
+ const botPaddleSpeed = 4; // Speed of the bot paddle
17
+
18
+ // --- Game State Variables ---
19
+ let paddleLeftY = window.innerHeight / 2 - paddleHeight / 2;
20
+ let paddleRightY = window.innerHeight / 2 - paddleHeight / 2;
21
+ let ballX = window.innerWidth / 2 - ballSize / 2;
22
+ let ballY = window.innerHeight / 2 - ballSize / 2;
23
+ let ballSpeedX = initialBallSpeedX; // Start with initial speed
24
+ let ballSpeedY = 0;
25
+ let playerScore = 0;
26
+ let botScore = 0;
27
+ let isGamePaused = true; // Start paused
28
 
29
+ // --- Event Listeners ---
30
  gameArea.addEventListener('touchmove', (e) => {
31
  e.preventDefault();
32
+ if (!e.touches || e.touches.length === 0) return; // Safety check
33
+
34
  let touchY = e.touches[0].clientY;
35
+ let touchX = e.touches[0].clientX;
36
 
37
+ // Only control left paddle if touch is on the left half
38
+ if (touchX < window.innerWidth / 2) {
39
  paddleLeftY = touchY - paddleHeight / 2;
40
+ // Clamp paddle position within screen bounds
41
  paddleLeftY = Math.max(0, Math.min(paddleLeftY, window.innerHeight - paddleHeight));
42
+ paddleLeft.style.top = paddleLeftY + 'px';
43
 
44
+ // Start the game on first touch if paused
45
  if (isGamePaused) {
46
+ // Determine initial direction based on which side was touched (less relevant here, but good practice)
47
+ // ballSpeedX = initialBallSpeedX; // Or keep the direction from resetBall
48
  isGamePaused = false;
49
  }
50
  }
51
+ }, { passive: false }); // Use passive: false if preventDefault is needed
52
+
53
+ // Add a click/tap listener to start the game as well
54
+ gameArea.addEventListener('click', () => {
55
+ if (isGamePaused) {
56
+ isGamePaused = false;
57
+ // Optional: decide initial direction if needed
58
+ // if (ballX < window.innerWidth / 2) ballSpeedX = initialBallSpeedX;
59
+ // else ballSpeedX = -initialBallSpeedX;
60
+ }
61
  });
62
 
63
+
64
+ // --- Collision Handling ---
65
  function handlePaddleCollision(paddleY, paddleX, isLeftPaddle) {
66
  const ballRadius = ballSize / 2;
67
+ const ballCenterX = ballX + ballRadius;
68
+ const ballCenterY = ballY + ballRadius;
69
+
70
  const paddleTop = paddleY;
71
  const paddleBottom = paddleY + paddleHeight;
72
+ const paddleLeftEdge = paddleX;
73
+ const paddleRightEdge = paddleX + paddleWidth;
74
+
75
+ // Simple AABB collision check first (optimization)
76
+ if (ballCenterX + ballRadius < paddleLeftEdge ||
77
+ ballCenterX - ballRadius > paddleRightEdge ||
78
+ ballCenterY + ballRadius < paddleTop ||
79
+ ballCenterY - ballRadius > paddleBottom) {
80
+ return; // No collision based on bounding boxes
 
 
 
 
 
81
  }
82
 
83
+ // More precise check: Find closest point on paddle to ball center
84
+ let closestX = Math.max(paddleLeftEdge, Math.min(ballCenterX, paddleRightEdge));
85
+ let closestY = Math.max(paddleTop, Math.min(ballCenterY, paddleBottom));
86
+
87
+ // Calculate distance between ball center and closest point
88
+ const dx = ballCenterX - closestX;
89
+ const dy = ballCenterY - closestY;
90
+ const distanceSquared = (dx * dx) + (dy * dy);
91
+
92
+ // Check if collision occurred (distance < radius)
93
+ if (distanceSquared < (ballRadius * ballRadius)) {
94
+
95
+ // --- Collision Response ---
96
+
97
+ // 1. Calculate where the ball hit the paddle vertically (normalized)
98
+ // hitPosition: -1 (top edge) to +1 (bottom edge)
99
+ const paddleCenterY = paddleTop + paddleHeight / 2;
100
+ let hitPosition = (ballCenterY - paddleCenterY) / (paddleHeight / 2);
101
+ // Clamp hitPosition to avoid extreme angles if hit exactly on corner
102
+ hitPosition = Math.max(-1, Math.min(1, hitPosition));
103
+
104
+ // 2. Calculate the bounce angle in radians
105
+ const bounceAngle = hitPosition * maxAngle * (Math.PI / 180);
106
+
107
+ // 3. Calculate the current speed
108
+ const currentSpeed = Math.sqrt(ballSpeedX * ballSpeedX + ballSpeedY * ballSpeedY);
109
+
110
+ // 4. Calculate the new speed (increase and cap)
111
+ let newSpeed = currentSpeed * speedIncreaseFactor;
112
+ newSpeed = Math.min(newSpeed, maxBallSpeed); // Apply max speed limit
113
+
114
+ // 5. Calculate new X and Y speeds based on angle and new total speed
115
+ // Determine the outward direction for X based on which paddle was hit
116
+ const directionX = isLeftPaddle ? 1 : -1;
117
+ ballSpeedX = directionX * newSpeed * Math.cos(bounceAngle);
118
+ ballSpeedY = newSpeed * Math.sin(bounceAngle);
119
+
120
+ // 6. Reposition ball slightly outside the paddle to prevent sticking (optional but recommended)
121
+ // Move ball along the collision normal (simplified as horizontal push)
122
+ const overlap = ballRadius - Math.sqrt(distanceSquared);
123
+ if (isLeftPaddle && dx < 0) { // Ball was moving right, hit left paddle
124
+ ballX += overlap; // Push right
125
+ } else if (!isLeftPaddle && dx > 0) { // Ball was moving left, hit right paddle
126
+ ballX -= overlap; // Push left
127
+ }
128
+ // A more accurate push would be along the dx, dy vector, but horizontal is often sufficient
129
+
130
+ // Ensure ball is definitely outside after adjustment
131
+ if (isLeftPaddle && ballX + ballSize < paddleRightEdge) {
132
+ ballX = paddleRightEdge - ballSize / 2; // Adjust precisely if needed
133
+ } else if (!isLeftPaddle && ballX > paddleLeftEdge) {
134
+ ballX = paddleLeftEdge - ballSize / 2; // Adjust precisely if needed
135
+ }
136
  }
137
  }
138
 
139
+
140
+ // --- Game Update Loop ---
141
  function update() {
142
  if (!isGamePaused) {
143
+ // Store previous position for collision checks if needed (not strictly needed with current collision)
144
+ // let previousBallX = ballX;
145
+ // let previousBallY = ballY;
146
+
147
+ // Move Ball
148
  ballX += ballSpeedX;
149
  ballY += ballSpeedY;
150
 
151
  // Ball collision with top and bottom walls
152
+ if (ballY <= 0) {
153
+ ballY = 0; // Prevent sticking
154
+ ballSpeedY = Math.abs(ballSpeedY); // Ensure it bounces down
155
+ } else if (ballY >= window.innerHeight - ballSize) {
156
+ ballY = window.innerHeight - ballSize; // Prevent sticking
157
+ ballSpeedY = -Math.abs(ballSpeedY); // Ensure it bounces up
158
  }
159
 
160
+ // Paddle Collisions
161
+ // Check collision with left paddle
162
+ if (ballSpeedX < 0) { // Only check left paddle if ball is moving left
163
+ handlePaddleCollision(paddleLeftY, 0, true); // Left paddle is at x=0
164
+ }
165
+ // Check collision with right paddle
166
+ else if (ballSpeedX > 0) { // Only check right paddle if ball is moving right
167
+ handlePaddleCollision(paddleRightY, window.innerWidth - paddleWidth, false); // Right paddle position
168
+ }
169
 
 
 
170
 
171
+ // Ball out of bounds (Score)
172
+ if (ballX + ballSize <= 0) { // Ball went past left edge
173
  botScore++;
174
  botScoreDisplay.textContent = botScore;
175
+ resetBall('right'); // Bot serves next
176
+ } else if (ballX >= window.innerWidth) { // Ball went past right edge
177
  playerScore++;
178
  playerScoreDisplay.textContent = playerScore;
179
+ resetBall('left'); // Player serves next
180
  }
 
181
 
182
+ // --- Bot AI Movement ---
183
+ // Move bot paddle only if the ball is moving towards it
184
+ if (ballSpeedX > 0) {
185
+ const botPaddleCenter = paddleRightY + paddleHeight / 2;
186
+ const ballCenter = ballY + ballSize / 2;
187
+ const targetY = ballCenter - paddleHeight / 2; // Target top position for bot paddle
188
+
189
+ // Move towards the ball's Y position, but not faster than botPaddleSpeed
190
+ if (paddleRightY < targetY) {
191
+ paddleRightY += Math.min(botPaddleSpeed, targetY - paddleRightY);
192
+ } else if (paddleRightY > targetY) {
193
+ paddleRightY -= Math.min(botPaddleSpeed, paddleRightY - targetY);
194
+ }
195
+ // Clamp bot paddle position
196
+ paddleRightY = Math.max(0, Math.min(paddleRightY, window.innerHeight - paddleHeight));
197
+ paddleRight.style.top = paddleRightY + 'px';
198
  }
199
  }
200
 
201
+ // Update visual positions regardless of pause state (allows resetBall positioning)
 
202
  ball.style.left = ballX + 'px';
203
  ball.style.top = ballY + 'px';
204
+ // Player paddle updated in event listener
205
+ // Bot paddle updated in AI logic or here if needed outside AI block
206
+
207
 
208
+ // Request next frame
209
  requestAnimationFrame(update);
210
  }
211
 
212
+ // --- Reset Ball Function ---
213
+ function resetBall(scoringSide) {
214
+ isGamePaused = true; // Pause until next touch/click
215
+
216
+ // Center the ball vertically
217
+ ballY = window.innerHeight / 2 - ballSize / 2;
218
+
219
+ // Position ball near the paddle that will serve
220
+ if (scoringSide === 'left') { // Player scored, player serves (ball starts near left paddle)
221
+ ballX = paddleWidth + 20; // Start just right of left paddle
222
+ ballSpeedX = initialBallSpeedX; // Move right
223
+ } else { // Bot scored, bot serves (ball starts near right paddle)
224
+ ballX = window.innerWidth - paddleWidth - ballSize - 20; // Start just left of right paddle
225
+ ballSpeedX = -initialBallSpeedX; // Move left
226
  }
227
 
228
+ // Reset vertical speed
229
  ballSpeedY = 0;
230
+
231
+ // Optional: Briefly show ball position before game restarts on touch/click
232
+ ball.style.left = ballX + 'px';
233
+ ball.style.top = ballY + 'px';
234
+
235
+ // Display message (optional)
236
+ // gameMessage.textContent = "Tap to Serve";
237
+ // gameMessage.style.display = 'block';
238
  }
239
 
240
+ // --- Initial Setup ---
241
+ // Set initial paddle positions visually
242
+ paddleLeft.style.top = paddleLeftY + 'px';
243
+ paddleRight.style.top = paddleRightY + 'px';
244
+ // Set initial ball position visually
245
+ ball.style.left = ballX + 'px';
246
+ ball.style.top = ballY + 'px';
247
+ // Set initial scores visually
248
+ playerScoreDisplay.textContent = playerScore;
249
+ botScoreDisplay.textContent = botScore;
250
+
251
  // Start the game loop
252
+ requestAnimationFrame(update);