1
+ // grab a reference of our "canvas" using its id
2
+ const canvas = document . getElementById ( 'canvas' ) ;
3
+ /* get a "context". Without "context", we can't draw on canvas */
4
+ const ctx = canvas . getContext ( '2d' ) ;
5
+
6
+ // some sounds
7
+ const hitSound = new Audio ( ) ;
8
+ const scoreSound = new Audio ( ) ;
9
+ const wallHitSound = new Audio ( ) ;
10
+
11
+ hitSound . src = 'https://raw.githubusercontent.com/the-coding-pie/Ping-Pong-Javascript/master/sounds/hitSound.wav' ;
12
+ scoreSound . src = 'https://raw.githubusercontent.com/the-coding-pie/Ping-Pong-Javascript/master/sounds/scoreSound.wav' ;
13
+ wallHitSound . src = 'https://raw.githubusercontent.com/the-coding-pie/Ping-Pong-Javascript/master/sounds/wallHitSound.wav' ;
14
+
15
+ /* some extra variables */
16
+ const netWidth = 4 ;
17
+ const netHeight = canvas . height ;
18
+
19
+ const paddleWidth = 10 ;
20
+ const paddleHeight = 100 ;
21
+
22
+ let upArrowPressed = false ;
23
+ let downArrowPressed = false ;
24
+
25
+ /* some extra variables ends */
26
+
27
+ /* objects */
28
+ // net
29
+ const net = {
30
+ x : canvas . width / 2 - netWidth / 2 ,
31
+ y : 0 ,
32
+ width : netWidth ,
33
+ height : netHeight ,
34
+ color : "#FFF"
35
+ } ;
36
+
37
+ // user paddle
38
+ const user = {
39
+ x : 10 ,
40
+ y : canvas . height / 2 - paddleHeight / 2 ,
41
+ width : paddleWidth ,
42
+ height : paddleHeight ,
43
+ color : '#FFF' ,
44
+ score : 0
45
+ } ;
46
+
47
+ const ai = {
48
+ x : canvas . width - ( paddleWidth + 10 ) ,
49
+ y : canvas . height / 2 - paddleHeight / 2 ,
50
+ width : paddleWidth ,
51
+ height : paddleHeight ,
52
+ color : '#FFF' ,
53
+ score : 0
54
+ } ;
55
+
56
+ // ball
57
+ const ball = {
58
+ x : canvas . width / 2 ,
59
+ y : canvas . height / 2 ,
60
+ radius : 7 ,
61
+ speed : 7 ,
62
+ velocityX : 5 ,
63
+ velocityY : 5 ,
64
+ color : '#05EDFF'
65
+ } ;
66
+
67
+ /* objects declaration ends */
68
+
69
+ /* drawing functions */
70
+ // function to draw net
71
+ function drawNet ( ) {
72
+ // set the color of net
73
+ ctx . fillStyle = net . color ;
74
+
75
+ // syntax --> fillRect(x, y, width, height)
76
+ ctx . fillRect ( net . x , net . y , net . width , net . height ) ;
77
+ }
78
+
79
+ // function to draw score
80
+ function drawScore ( x , y , score ) {
81
+ ctx . fillStyle = '#fff' ;
82
+ ctx . font = '35px sans-serif' ;
83
+
84
+ // syntax --> fillText(text, x, y)
85
+ ctx . fillText ( score , x , y ) ;
86
+ }
87
+
88
+ // function to draw paddle
89
+ function drawPaddle ( x , y , width , height , color ) {
90
+ ctx . fillStyle = color ;
91
+ ctx . fillRect ( x , y , width , height ) ;
92
+ }
93
+
94
+ // function to draw ball
95
+ function drawBall ( x , y , radius , color ) {
96
+ ctx . fillStyle = color ;
97
+ ctx . beginPath ( ) ;
98
+ // syntax --> arc(x, y, radius, startAngle, endAngle, antiClockwise_or_not)
99
+ ctx . arc ( x , y , radius , 0 , Math . PI * 2 , true ) ; // π * 2 Radians = 360 degrees
100
+ ctx . closePath ( ) ;
101
+ ctx . fill ( ) ;
102
+ }
103
+
104
+ /* drawing functions end */
105
+
106
+ /* moving Paddles */
107
+ // add an eventListener to browser window
108
+ window . addEventListener ( 'keydown' , keyDownHandler ) ;
109
+ window . addEventListener ( 'keyup' , keyUpHandler ) ;
110
+
111
+ // gets activated when we press down a key
112
+ function keyDownHandler ( event ) {
113
+ // get the keyCode
114
+ switch ( event . keyCode ) {
115
+ // "up arrow" key
116
+ case 38 :
117
+ // set upArrowPressed = true
118
+ upArrowPressed = true ;
119
+ break ;
120
+ // "down arrow" key
121
+ case 40 :
122
+ downArrowPressed = true ;
123
+ break ;
124
+ }
125
+ }
126
+
127
+ // gets activated when we release the key
128
+ function keyUpHandler ( event ) {
129
+ switch ( event . keyCode ) {
130
+ // "up arraow" key
131
+ case 38 :
132
+ upArrowPressed = false ;
133
+ break ;
134
+ // "down arrow" key
135
+ case 40 :
136
+ downArrowPressed = false ;
137
+ break ;
138
+ }
139
+ }
140
+
141
+ /* moving paddles section end */
142
+
143
+ // reset the ball
144
+ function reset ( ) {
145
+ // reset ball's value to older values
146
+ ball . x = canvas . width / 2 ;
147
+ ball . y = canvas . height / 2 ;
148
+ ball . speed = 7 ;
149
+
150
+ // changes the direction of ball
151
+ ball . velocityX = - ball . velocityX ;
152
+ ball . velocityY = - ball . velocityY ;
153
+ }
154
+
155
+ // collision Detect function
156
+ function collisionDetect ( player , ball ) {
157
+ // returns true or false
158
+ player . top = player . y ;
159
+ player . right = player . x + player . width ;
160
+ player . bottom = player . y + player . height ;
161
+ player . left = player . x ;
162
+
163
+ ball . top = ball . y - ball . radius ;
164
+ ball . right = ball . x + ball . radius ;
165
+ ball . bottom = ball . y + ball . radius ;
166
+ ball . left = ball . x - ball . radius ;
167
+
168
+ return ball . left < player . right && ball . top < player . bottom && ball . right > player . left && ball . bottom > player . top ;
169
+ }
170
+
171
+ // update function, to update things position
172
+ function update ( ) {
173
+ // move the paddle
174
+ if ( upArrowPressed && user . y > 0 ) {
175
+ user . y -= 8 ;
176
+ } else if ( downArrowPressed && ( user . y < canvas . height - user . height ) ) {
177
+ user . y += 8 ;
178
+ }
179
+
180
+ // check if ball hits top or bottom wall
181
+ if ( ball . y + ball . radius >= canvas . height || ball . y - ball . radius <= 0 ) {
182
+ // play wallHitSound
183
+ wallHitSound . play ( ) ;
184
+ ball . velocityY = - ball . velocityY ;
185
+ }
186
+
187
+ // if ball hit on right wall
188
+ if ( ball . x + ball . radius >= canvas . width ) {
189
+ // play scoreSound
190
+ scoreSound . play ( ) ;
191
+ // then user scored 1 point
192
+ user . score += 1 ;
193
+ reset ( ) ;
194
+ }
195
+
196
+ // if ball hit on left wall
197
+ if ( ball . x - ball . radius <= 0 ) {
198
+ // play scoreSound
199
+ scoreSound . play ( ) ;
200
+ // then ai scored 1 point
201
+ ai . score += 1 ;
202
+ reset ( ) ;
203
+ }
204
+
205
+ // move the ball
206
+ ball . x += ball . velocityX ;
207
+ ball . y += ball . velocityY ;
208
+
209
+ // ai paddle movement
210
+ ai . y += ( ( ball . y - ( ai . y + ai . height / 2 ) ) ) * 0.09 ;
211
+
212
+ // collision detection on paddles
213
+ let player = ( ball . x < canvas . width / 2 ) ? user : ai ;
214
+
215
+ if ( collisionDetect ( player , ball ) ) {
216
+ // play hitSound
217
+ hitSound . play ( ) ;
218
+ // default angle is 0deg in Radian
219
+ let angle = 0 ;
220
+
221
+ // if ball hit the top of paddle
222
+ if ( ball . y < ( player . y + player . height / 2 ) ) {
223
+ // then -1 * Math.PI / 4 = -45deg
224
+ angle = - 1 * Math . PI / 4 ;
225
+ } else if ( ball . y > ( player . y + player . height / 2 ) ) {
226
+ // if it hit the bottom of paddle
227
+ // then angle will be Math.PI / 4 = 45deg
228
+ angle = Math . PI / 4 ;
229
+ }
230
+
231
+ /* change velocity of ball according to on which paddle the ball hitted */
232
+ ball . velocityX = ( player === user ? 1 : - 1 ) * ball . speed * Math . cos ( angle ) ;
233
+ ball . velocityY = ball . speed * Math . sin ( angle ) ;
234
+
235
+ // increase ball speed
236
+ ball . speed += 0.2 ;
237
+ }
238
+ }
239
+
240
+ // render function draws everything on to canvas
241
+ function render ( ) {
242
+ // set a style
243
+ ctx . fillStyle = "#000" ; /* whatever comes below this acquires black color (#000). */
244
+ // draws the black board
245
+ ctx . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
246
+
247
+ // draw net
248
+ drawNet ( ) ;
249
+ // draw user score
250
+ drawScore ( canvas . width / 4 , canvas . height / 6 , user . score ) ;
251
+ // draw ai score
252
+ drawScore ( 3 * canvas . width / 4 , canvas . height / 6 , ai . score ) ;
253
+ // draw user paddle
254
+ drawPaddle ( user . x , user . y , user . width , user . height , user . color ) ;
255
+ // draw ai paddle
256
+ drawPaddle ( ai . x , ai . y , ai . width , ai . height , ai . color ) ;
257
+ // draw ball
258
+ drawBall ( ball . x , ball . y , ball . radius , ball . color ) ;
259
+ }
260
+
261
+ // gameLoop
262
+ function gameLoop ( ) {
263
+ // update() function here
264
+ update ( ) ;
265
+ // render() function here
266
+ render ( ) ;
267
+ }
268
+
269
+ // calls gameLoop() function 60 times per second
270
+ setInterval ( gameLoop , 1000 / 60 ) ;
0 commit comments