1
1
<!DOCTYPE html>
2
2
< html >
3
+
3
4
< head >
4
5
< title > Breakout</ title >
5
6
< meta charset ="UTF-8 ">
6
7
< style >
7
- html , body {
8
- height : 100% ;
9
- margin : 0 ;
10
- }
8
+ html ,
9
+ body {
10
+ height : 100% ;
11
+ margin : 0 ;
12
+ }
11
13
12
- body {
13
- background : black;
14
-
15
- }
14
+ body {
15
+ background : black;
16
+
17
+ }
16
18
canvas {
17
19
border : 2px solid white;
18
20
display : flex;
19
21
align-items : center;
20
22
justify-content : center;
21
23
margin : auto;
22
24
}
25
+
23
26
h1 {
24
27
color : white;
25
28
text-align : center;
26
29
}
30
+
27
31
h3 {
28
32
color : white;
29
33
text-align : center;
30
34
}
31
35
</ style >
32
36
</ head >
37
+
33
38
< body >
34
39
< h1 > Breakout</ h1 >
35
40
< h3 > Press spacebar to start</ h3 >
36
- < canvas width ="400 " height ="500 " id ="game "> </ canvas >
37
- < script >
38
-
39
- requestAnimationFrame ( loop ) ;
40
- </ script >
41
+ < canvas width ="400 " height ="500 " id ="game "> </ canvas >
42
+ < script >
43
+ const canvas = document . getElementById ( 'game' ) ;
44
+ const context = canvas . getContext ( '2d' ) ;
45
+
46
+ const level1 = [
47
+ [ ] ,
48
+ [ ] ,
49
+ [ 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' ] ,
50
+ [ 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' , 'R' ] ,
51
+ [ 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' ] ,
52
+ [ 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' , 'O' ] ,
53
+ [ 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' ] ,
54
+ [ 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' , 'Y' ] ,
55
+ [ 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' ] ,
56
+ [ 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' , 'G' ] ,
57
+ [ 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' ] ,
58
+ [ 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' , 'B' ] ,
59
+ [ 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' ] ,
60
+ [ 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' , 'I' ] ,
61
+ [ 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' ] ,
62
+ [ 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' , 'V' ]
63
+ ] ;
64
+ const colorMap = {
65
+ 'R' : 'red' ,
66
+ 'O' : 'orange' ,
67
+ 'G' : 'green' ,
68
+ 'Y' : 'yellow' ,
69
+ 'V' : 'Violet' ,
70
+ 'I' : 'Indigo' ,
71
+ 'B' : 'Blue'
72
+ } ;
73
+
74
+ const brickGap = 2 ;
75
+ const brickWidth = 25 ;
76
+ const brickHeight = 12 ;
77
+ const wallSize = 12 ;
78
+ const bricks = [ ] ;
79
+
80
+ for ( let row = 0 ; row < level1 . length ; row ++ ) {
81
+ for ( let col = 0 ; col < level1 [ row ] . length ; col ++ ) {
82
+ const colorCode = level1 [ row ] [ col ] ;
83
+
84
+ bricks . push ( {
85
+ x : wallSize + ( brickWidth + brickGap ) * col ,
86
+ y : wallSize + ( brickHeight + brickGap ) * row ,
87
+ color : colorMap [ colorCode ] ,
88
+ width : brickWidth ,
89
+ height : brickHeight
90
+ } ) ;
91
+ }
92
+ }
93
+
94
+ const paddle = {
95
+ x : canvas . width / 2 - brickWidth / 2 ,
96
+ y : 440 ,
97
+ width : brickWidth ,
98
+ height : brickHeight ,
99
+
100
+ // paddle's velocity
101
+ dx : 0
102
+ } ;
103
+
104
+ const ball = {
105
+ x : 250 ,
106
+ y : 260 ,
107
+ width : 5 ,
108
+ height : 5 ,
109
+
110
+ // how fast the ball should go in the x or y direction
111
+ speed : 3 ,
112
+
113
+ // ball velocity
114
+ dx : 0 ,
115
+ dy : 0
116
+ } ;
117
+
118
+ // check for collision between two objects using axis-aligned bounding box (AABB)
119
+ // @see https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
120
+ function collides ( obj1 , obj2 ) {
121
+ return obj1 . x < obj2 . x + obj2 . width &&
122
+ obj1 . x + obj1 . width > obj2 . x &&
123
+ obj1 . y < obj2 . y + obj2 . height &&
124
+ obj1 . y + obj1 . height > obj2 . y ;
125
+ }
126
+
127
+ // game loop
128
+ function loop ( ) {
129
+ requestAnimationFrame ( loop ) ;
130
+ context . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
131
+
132
+ // move paddle by it's velocity
133
+ paddle . x += paddle . dx ;
134
+
135
+ // prevent paddle from going through walls
136
+ if ( paddle . x < wallSize ) {
137
+ paddle . x = wallSize
138
+ }
139
+ else if ( paddle . x + brickWidth > canvas . width - wallSize ) {
140
+ paddle . x = canvas . width - wallSize - brickWidth ;
141
+ }
142
+
143
+ // move ball by it's velocity
144
+ ball . x += ball . dx ;
145
+ ball . y += ball . dy ;
146
+
147
+ // prevent ball from going through walls by changing its velocity
148
+ // left & right walls
149
+ if ( ball . x < wallSize ) {
150
+ ball . x = wallSize ;
151
+ ball . dx *= - 1 ;
152
+ }
153
+ else if ( ball . x + ball . width > canvas . width - wallSize ) {
154
+ ball . x = canvas . width - wallSize - ball . width ;
155
+ ball . dx *= - 1 ;
156
+ }
157
+ // top wall
158
+ if ( ball . y < wallSize ) {
159
+ ball . y = wallSize ;
160
+ ball . dy *= - 1 ;
161
+ }
162
+
163
+ // reset ball if it goes below the screen
164
+ if ( ball . y > canvas . height ) {
165
+ ball . x = 130 ;
166
+ ball . y = 260 ;
167
+ ball . dx = 0 ;
168
+ ball . dy = 0 ;
169
+ }
170
+
171
+ // check to see if ball collides with paddle. if they do change y velocity
172
+ if ( collides ( ball , paddle ) ) {
173
+ ball . dy *= - 1 ;
174
+
175
+ // move ball above the paddle otherwise the collision will happen again
176
+ // in the next frame
177
+ ball . y = paddle . y - ball . height ;
178
+ }
179
+
180
+ // check to see if ball collides with a brick. if it does, remove the brick
181
+ // and change the ball velocity based on the side the brick was hit on
182
+ for ( let i = 0 ; i < bricks . length ; i ++ ) {
183
+ const brick = bricks [ i ] ;
184
+
185
+ if ( collides ( ball , brick ) ) {
186
+ // remove brick from the bricks array
187
+ bricks . splice ( i , 1 ) ;
188
+
189
+
190
+ // ball is above or below the brick, change y velocity
191
+ // account for the balls speed since it will be inside the brick when it
192
+ // collides
193
+ if ( ball . y + ball . height - ball . speed <= brick . y ||
194
+ ball . y >= brick . y + brick . height - ball . speed ) {
195
+ ball . dy *= - 1 ;
196
+ }
197
+ // ball is on either side of the brick, change x velocity
198
+ else {
199
+ ball . dx *= - 1 ;
200
+ }
201
+
202
+ break ;
203
+ }
204
+ }
205
+
206
+ // draw walls
207
+ context . fillStyle = 'lightgrey' ;
208
+ context . fillRect ( 0 , 0 , canvas . width , wallSize ) ;
209
+ context . fillRect ( 0 , 0 , wallSize , canvas . height ) ;
210
+ context . fillRect ( canvas . width - wallSize , 0 , wallSize , canvas . height ) ;
211
+
212
+ // draw ball if it's moving
213
+ if ( ball . dx || ball . dy ) {
214
+ context . fillRect ( ball . x , ball . y , ball . width , ball . height ) ;
215
+ }
216
+
217
+ // draw bricks
218
+ bricks . forEach ( function ( brick ) {
219
+ context . fillStyle = brick . color ;
220
+ context . fillRect ( brick . x , brick . y , brick . width , brick . height ) ;
221
+ } ) ;
222
+
223
+ // draw paddle
224
+ context . fillStyle = 'white' ;
225
+ context . fillRect ( paddle . x , paddle . y , paddle . width , paddle . height ) ;
226
+ }
227
+
228
+ // listen to keyboard events to move the paddle
229
+ document . addEventListener ( 'keydown' , function ( e ) {
230
+ // left arrow key
231
+ if ( e . which === 65 ) {
232
+ paddle . dx = - 5 ;
233
+ }
234
+ // right arrow key
235
+ else if ( e . which === 68 ) {
236
+ paddle . dx = 5 ;
237
+ }
238
+
239
+ // space key
240
+ // if they ball is not moving, we can launch the ball using the space key. ball
241
+ // will move towards the bottom right to start
242
+ if ( ball . dx === 0 && ball . dy === 0 && e . which === 32 ) {
243
+ ball . dx = ball . speed ;
244
+ ball . dy = ball . speed ;
245
+ }
246
+ } ) ;
247
+
248
+ // listen to keyboard events to stop the paddle if key is released
249
+ document . addEventListener ( 'keyup' , function ( e ) {
250
+ if ( e . which === 65 || e . which === 68 ) {
251
+ paddle . dx = 0 ;
252
+ }
253
+ } ) ;
254
+
255
+ // start the game
256
+ requestAnimationFrame ( loop ) ;
257
+ </ script >
41
258
</ body >
259
+
42
260
</ html >
0 commit comments