File size: 4,777 Bytes
a3b97ad
 
 
 
a4b6ccc
 
a3b97ad
ae20685
 
 
 
 
 
a4b6ccc
 
ae20685
a3b97ad
 
5994a14
 
ae20685
5994a14
 
 
ae20685
5994a14
 
 
ae20685
a4b6ccc
 
 
 
5994a14
 
a3b97ad
ae20685
b00bf58
484355f
 
 
ae20685
484355f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25cc5de
8d12a80
 
a3b97ad
a4b6ccc
ae20685
a4b6ccc
 
 
 
 
 
 
a3b97ad
ae20685
 
a3b97ad
ae20685
 
 
 
a4b6ccc
 
 
 
 
 
 
 
 
a3b97ad
 
ae20685
 
fc7647d
ae20685
fc7647d
ae20685
fc7647d
 
 
ae20685
fc7647d
a3b97ad
 
 
 
 
 
 
 
a4b6ccc
ae20685
a4b6ccc
 
ae20685
a4b6ccc
ae20685
 
 
a4b6ccc
ae20685
a4b6ccc
 
ae20685
a3b97ad
 
5994a14
a3b97ad
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
const gameArea = document.getElementById('gameArea');
const paddleLeft = document.getElementById('paddleLeft');
const paddleRight = document.getElementById('paddleRight');
const ball = document.getElementById('ball');
const playerScoreDisplay = document.getElementById('playerScore');
const botScoreDisplay = document.getElementById('botScore');

let paddleLeftY = window.innerHeight / 2 - 40;
let paddleRightY = window.innerHeight / 2 - 40;
let ballX = window.innerWidth / 2;
let ballY = window.innerHeight / 2;
let ballSpeedX = 3;
let ballSpeedY = 0;
let playerScore = 0;
let botScore = 0;
let isGamePaused = true;

const paddleHeight = 80;
const paddleWidth = 10;
const ballSize = 15;
const maxAngle = 45;

gameArea.addEventListener('touchmove', (e) => {
    e.preventDefault();
    let touchY = e.touches[0].clientY;

    if (e.touches[0].clientX < window.innerWidth / 2) {
        paddleLeftY = touchY - paddleHeight / 2;
        paddleLeftY = Math.max(0, Math.min(paddleLeftY, window.innerHeight - paddleHeight));

        if (isGamePaused) {
            isGamePaused = false;
        }
    }
});

function handlePaddleCollision(paddleY, paddleX, isLeftPaddle) {
    const ballRadius = ballSize / 2;
    const paddleRight = paddleX + paddleWidth;
    const paddleTop = paddleY;
    const paddleBottom = paddleY + paddleHeight;

    // Closest point on paddle to ball's center
    let closestX = ballX;
    if (isLeftPaddle) {
        closestX = paddleRight;
    } else {
        closestX = paddleX;
    }

    let closestY = ballY;
    if (ballY < paddleTop) {
        closestY = paddleTop;
    } else if (ballY > paddleBottom) {
        closestY = paddleBottom;
    }

    // Vector from ball to closest point
    const dx = ballX - closestX;
    const dy = ballY - closestY;
    const distance = Math.sqrt(dx * dx + dy * dy);

    if (distance <= ballRadius) {
        // Collision occurs
        // Calculate normal vector
        const normalX = isLeftPaddle ? 1 : -1;
        const normalY = 0;

        // Current velocity
        const velocity = { x: ballSpeedX, y: ballSpeedY };

        // Reflect velocity over the normal
        const dot = velocity.x * normalX + velocity.y * normalY;
        const reflected = {
            x: velocity.x - 2 * dot * normalX,
            y: velocity.y - 2 * dot * normalY
        };

        // Adjust Y velocity based on hit position
        const hitPosition = (closestY - (paddleTop + paddleHeight / 2)) / (paddleHeight / 2);
        const angle = hitPosition * maxAngle * (Math.PI / 180);
        reflected.y = Math.sin(angle) * Math.abs(reflected.x);

        // Set new velocity
        ballSpeedX = reflected.x;
        ballSpeedY = reflected.y;

        // Reposition ball outside the paddle
        const overlap = ballRadius - distance;
        ballX += normalX * overlap;
    }
}

function update() {
    if (!isGamePaused) {
        let previousBallX = ballX;
        ballX += ballSpeedX;
        ballY += ballSpeedY;

        // Ball collision with top and bottom walls
        if (ballY <= 0 || ballY >= window.innerHeight - ballSize) {
            ballSpeedY = -ballSpeedY;
        }

        // Check collision with left paddle using swept collision detection
        handlePaddleCollision(paddleLeftY, paddleWidth, true);

        // Check collision with right paddle using swept collision detection
        handlePaddleCollision(paddleRightY, window.innerWidth - paddleWidth - 25, false);

        // Ball out of bounds
        if (ballX <= 0) {
            botScore++;
            botScoreDisplay.textContent = botScore;
            resetBall('right');
        } else if (ballX >= window.innerWidth) {
            playerScore++;
            playerScoreDisplay.textContent = playerScore;
            resetBall('left');
        }
    }

    // Bot AI movement
    if (ballSpeedX > 0) {
        if (paddleRightY + paddleHeight / 2 < ballY) {
            paddleRightY += 3;
        } else if (paddleRightY + paddleHeight / 2 > ballY) {
            paddleRightY -= 3;
        }
    }

    paddleRightY = Math.max(0, Math.min(paddleRightY, window.innerHeight - paddleHeight));

    ball.style.left = ballX + 'px';
    ball.style.top = ballY + 'px';
    paddleLeft.style.top = paddleLeftY + 'px';
    paddleRight.style.top = paddleRightY + 'px';

    requestAnimationFrame(update);
}

function resetBall(side) {
    isGamePaused = true;

    if (side === 'left') {
        ballX = paddleWidth + 10;
        ballY = paddleLeftY + paddleHeight / 2;
        ballSpeedX = Math.abs(ballSpeedX);
    } else {
        ballX = window.innerWidth - paddleWidth - 25;
        ballY = paddleRightY + paddleHeight / 2;
        ballSpeedX = -Math.abs(ballSpeedX);
    }

    ballSpeedY = 0;
}

// Start the game loop
update();