@@ -3,8 +3,13 @@ class PlayerWarship {
33 this . width = 100 ;
44 this . height = 50 ;
55 this . speed = 5 ;
6+ this . maxLife = 10 ;
7+ this . life = this . maxLife ;
8+ this . isDead = false ;
9+ this . direction = 'up' ;
610 this . warshipAction = document . getElementById ( 'player-warship' ) ;
711 this . container = this . warshipAction ?. parentElement || document . body ;
12+ this . lifeLabel = this . createLifeLabel ( ) ;
813 this . positionX = Math . max ( 0 , this . container . clientWidth / 2 - this . width / 2 ) ;
914 this . positionY = Math . max ( 0 , this . container . clientHeight - this . height - 10 ) ;
1015 this . motion ( ) ;
@@ -17,24 +22,29 @@ class PlayerWarship {
1722 this . warshipAction . style . width = this . width + 'px' ;
1823 this . warshipAction . style . height = this . height + 'px' ;
1924 this . getPosition ( ) ;
25+ this . updateLifeLabel ( ) ;
2026 }
2127
2228 motionLeft ( ) {
29+ this . direction = 'left' ;
2330 const minX = 0 ;
2431 this . positionX = Math . max ( minX , this . positionX - this . speed ) ;
2532 this . motion ( ) ;
2633 }
2734 motionRight ( ) {
35+ this . direction = 'right' ;
2836 const maxX = this . container . clientWidth - this . width ;
2937 this . positionX = Math . min ( maxX , this . positionX + this . speed ) ;
3038 this . motion ( ) ;
3139 }
3240
3341 motionUp ( ) {
42+ this . direction = 'up' ;
3443 this . positionY = Math . max ( 0 , this . positionY - this . speed ) ;
3544 this . motion ( ) ;
3645 }
3746 motionDown ( ) {
47+ this . direction = 'down' ;
3848 const maxY = this . container . clientHeight - this . height ;
3949 this . positionY = Math . min ( maxY , this . positionY + this . speed ) ;
4050 this . motion ( ) ;
@@ -44,11 +54,70 @@ class PlayerWarship {
4454 getPosition ( ) {
4555 return { x : this . positionX , y : this . positionY } ;
4656 }
57+
58+ createLifeLabel ( ) {
59+ if ( ! this . warshipAction ) {
60+ return null ;
61+ }
62+
63+ const bar = document . createElement ( 'div' ) ;
64+ bar . className = 'life-bar life-bar-player' ;
65+ const fill = document . createElement ( 'div' ) ;
66+ fill . className = 'life-fill life-fill-player' ;
67+ bar . appendChild ( fill ) ;
68+ this . warshipAction . appendChild ( bar ) ;
69+ return { bar, fill } ;
70+ }
71+
72+ updateLifeLabel ( ) {
73+ if ( ! this . lifeLabel ) {
74+ return ;
75+ }
76+ const percent = Math . max ( 0 , Math . min ( 100 , ( this . life / this . maxLife ) * 100 ) ) ;
77+ this . lifeLabel . fill . style . width = `${ percent } %` ;
78+ }
79+
80+ takeDamage ( amount ) {
81+ if ( this . isDead ) {
82+ return ;
83+ }
84+ this . life = Math . max ( 0 , this . life - amount ) ;
85+ this . updateLifeLabel ( ) ;
86+ if ( this . life === 0 ) {
87+ this . isDead = true ;
88+ if ( ! gameEnded ) {
89+ gameEnded = true ;
90+ window . location . href = './gemeOver.html' ;
91+ }
92+ }
93+ }
4794}
4895const newPlayer = new PlayerWarship ( ) ;
4996
5097const enemies = [ ] ;
5198const SPAWN_GAP = 20 ;
99+ const MAX_ENEMIES = 6 ;
100+ const WIN_KILLS = 5 ;
101+ let kills = 0 ;
102+ let gameEnded = false ;
103+
104+ function createScoreboard ( ) {
105+ const board = document . createElement ( 'div' ) ;
106+ board . className = 'scoreboard' ;
107+ board . textContent = `Kills: ${ kills } /${ WIN_KILLS } ` ;
108+ const seaboard = document . getElementById ( 'seaboard' ) ;
109+ ( seaboard || document . body ) . appendChild ( board ) ;
110+ return board ;
111+ }
112+
113+ const scoreboard = createScoreboard ( ) ;
114+
115+ function updateScoreboard ( ) {
116+ if ( ! scoreboard ) {
117+ return ;
118+ }
119+ scoreboard . textContent = `Kills: ${ kills } /${ WIN_KILLS } ` ;
120+ }
52121
53122function rectanglesOverlap ( a , b ) {
54123 return (
@@ -93,8 +162,12 @@ class EnemyWarship {
93162 this . width = 100 ;
94163 this . height = 50 ;
95164 this . speed = 1 ;
165+ this . maxLife = 5 ;
166+ this . life = this . maxLife ;
167+ this . isDestroyed = false ;
96168 this . el = element ;
97169 this . container = this . el . parentElement || document . body ;
170+ this . lifeLabel = this . createLifeLabel ( ) ;
98171 this . positionX = startX ;
99172 this . positionY = startY ;
100173 this . updateDom ( ) ;
@@ -107,6 +180,7 @@ class EnemyWarship {
107180 this . el . style . top = this . positionY + 'px' ;
108181 this . el . style . width = this . width + 'px' ;
109182 this . el . style . height = this . height + 'px' ;
183+ this . updateLifeLabel ( ) ;
110184 }
111185
112186 chasePlayer ( ) {
@@ -134,27 +208,71 @@ class EnemyWarship {
134208 }
135209
136210 checkCollision ( player ) {
211+ if ( this . isDestroyed ) {
212+ return ;
213+ }
137214 const hit =
138215 this . positionX < player . x + newPlayer . width &&
139216 this . positionX + this . width > player . x &&
140217 this . positionY < player . y + newPlayer . height &&
141218 this . positionY + this . height > player . y ;
142219
143220 if ( hit ) {
144- window . location . href = './gemeOver.html' ;
221+ newPlayer . takeDamage ( 1 ) ;
222+ this . takeDamage ( this . life ) ;
145223 }
146224 }
147225
148226 destroy ( ) {
227+ if ( this . isDestroyed ) {
228+ return ;
229+ }
230+ this . isDestroyed = true ;
149231 clearInterval ( this . chaseInterval ) ;
150232 clearInterval ( this . shootInterval ) ;
151233 this . el . remove ( ) ;
234+ const idx = enemies . indexOf ( this ) ;
235+ if ( idx !== - 1 ) {
236+ enemies . splice ( idx , 1 ) ;
237+ }
152238 }
153239
154240 shoot ( ) {
241+ if ( this . isDestroyed ) {
242+ return ;
243+ }
155244 const bulletX = this . positionX + this . width / 2 - 4 ;
156245 const bulletY = this . positionY + this . height ;
157- enemyBullets . push ( new Bullet ( bulletX , bulletY , 4 , 'enemy' ) ) ;
246+ enemyBullets . push ( new Bullet ( bulletX , bulletY , 0 , 4 , 'enemy' ) ) ;
247+ }
248+
249+ createLifeLabel ( ) {
250+ const bar = document . createElement ( 'div' ) ;
251+ bar . className = 'life-bar life-bar-enemy' ;
252+ const fill = document . createElement ( 'div' ) ;
253+ fill . className = 'life-fill life-fill-enemy' ;
254+ bar . appendChild ( fill ) ;
255+ this . el . appendChild ( bar ) ;
256+ return { bar, fill } ;
257+ }
258+
259+ updateLifeLabel ( ) {
260+ if ( ! this . lifeLabel ) {
261+ return ;
262+ }
263+ const percent = Math . max ( 0 , Math . min ( 100 , ( this . life / this . maxLife ) * 100 ) ) ;
264+ this . lifeLabel . fill . style . width = `${ percent } %` ;
265+ }
266+
267+ takeDamage ( amount ) {
268+ if ( this . isDestroyed ) {
269+ return ;
270+ }
271+ this . life = Math . max ( 0 , this . life - amount ) ;
272+ this . updateLifeLabel ( ) ;
273+ if ( this . life === 0 ) {
274+ this . destroy ( ) ;
275+ }
158276 }
159277}
160278function addElement ( ) {
@@ -164,7 +282,11 @@ function addElement() {
164282 return ;
165283 }
166284
167- if ( enemies . length >= 6 ) {
285+ if ( gameEnded ) {
286+ return ;
287+ }
288+
289+ if ( enemies . length >= MAX_ENEMIES ) {
168290 return ;
169291 }
170292
@@ -212,7 +334,7 @@ function addElement() {
212334 newWarship . style . position = 'absolute' ;
213335 newWarship . style . width = `${ width } px` ;
214336 newWarship . style . height = `${ height } px` ;
215- newWarship . style . backgroundColor = 'red ' ;
337+ newWarship . style . backgroundColor = 'transparent ' ;
216338 newWarship . style . zIndex = '2' ;
217339 newWarship . style . left = `${ spawn . x } px` ;
218340 newWarship . style . top = `${ spawn . y } px` ;
@@ -228,9 +350,10 @@ const playerBullets = [];
228350const enemyBullets = [ ] ;
229351
230352class Bullet {
231- constructor ( x , y , dy , owner ) {
353+ constructor ( x , y , dx , dy , owner ) {
232354 this . width = 8 ;
233355 this . height = 16 ;
356+ this . dx = dx ;
234357 this . dy = dy ;
235358 this . owner = owner ;
236359 this . el = document . createElement ( 'div' ) ;
@@ -252,13 +375,20 @@ class Bullet {
252375 }
253376
254377 update ( ) {
378+ this . positionX += this . dx ;
255379 this . positionY += this . dy ;
256380 this . updateDom ( ) ;
257381 }
258382
259383 isOffscreen ( ) {
260384 const maxY = this . container . clientHeight ;
261- return this . positionY < - this . height || this . positionY > maxY + this . height ;
385+ const maxX = this . container . clientWidth ;
386+ return (
387+ this . positionY < - this . height ||
388+ this . positionY > maxY + this . height ||
389+ this . positionX < - this . width ||
390+ this . positionX > maxX + this . width
391+ ) ;
262392 }
263393
264394 destroy ( ) {
@@ -281,8 +411,15 @@ function updateBullets() {
281411 if ( hitEnemy ) {
282412 bullet . destroy ( ) ;
283413 playerBullets . splice ( i , 1 ) ;
284- enemy . destroy ( ) ;
285- enemies . splice ( j , 1 ) ;
414+ enemy . takeDamage ( 1 ) ;
415+ if ( enemy . isDestroyed ) {
416+ kills += 1 ;
417+ updateScoreboard ( ) ;
418+ if ( kills >= WIN_KILLS && ! gameEnded ) {
419+ gameEnded = true ;
420+ window . location . href = './win.html' ;
421+ }
422+ }
286423 break ;
287424 }
288425 }
@@ -314,7 +451,7 @@ function updateBullets() {
314451 if ( hitPlayer ) {
315452 bullet . destroy ( ) ;
316453 enemyBullets . splice ( i , 1 ) ;
317- window . location . href = './gemeOver.html' ;
454+ newPlayer . takeDamage ( 1 ) ;
318455 return ;
319456 }
320457
@@ -339,9 +476,27 @@ document.addEventListener('keydown', (e) => {
339476 }
340477
341478 if ( e . code === 'Space' ) {
342- const bulletX = newPlayer . positionX + newPlayer . width / 2 - 4 ;
343- const bulletY = newPlayer . positionY - 16 ;
344- playerBullets . push ( new Bullet ( bulletX , bulletY , - 6 , 'player' ) ) ;
479+ let bulletX = newPlayer . positionX + newPlayer . width / 2 - 4 ;
480+ let bulletY = newPlayer . positionY - 16 ;
481+ let dx = 0 ;
482+ let dy = - 6 ;
483+
484+ if ( newPlayer . direction === 'down' ) {
485+ bulletY = newPlayer . positionY + newPlayer . height ;
486+ dy = 6 ;
487+ } else if ( newPlayer . direction === 'left' ) {
488+ bulletX = newPlayer . positionX - 16 ;
489+ bulletY = newPlayer . positionY + newPlayer . height / 2 - 4 ;
490+ dx = - 6 ;
491+ dy = 0 ;
492+ } else if ( newPlayer . direction === 'right' ) {
493+ bulletX = newPlayer . positionX + newPlayer . width ;
494+ bulletY = newPlayer . positionY + newPlayer . height / 2 - 4 ;
495+ dx = 6 ;
496+ dy = 0 ;
497+ }
498+
499+ playerBullets . push ( new Bullet ( bulletX , bulletY , dx , dy , 'player' ) ) ;
345500 }
346501
347502 if ( e . code === 'ArrowRight' ) {
0 commit comments