pijou commited on
Commit
3ea2a99
·
verified ·
1 Parent(s): f961199

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +316 -38
index.html CHANGED
@@ -3,54 +3,69 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>2D Fighting Game</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
 
8
  <style>
9
- /* Custom CSS for animations and game elements */
10
  body {
11
  overflow: hidden;
12
  background-color: #1a202c;
 
13
  }
14
 
 
 
15
  #game-container {
16
  position: relative;
17
  width: 800px;
18
  height: 400px;
19
  margin: 0 auto;
20
- background-image: url('https://images.unsplash.com/photo-1542273917363-3b1817f69a2d?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80');
21
  background-size: cover;
22
  overflow: hidden;
 
 
 
23
  }
24
 
25
  .character {
26
  position: absolute;
27
- width: 80px;
28
  height: 120px;
29
  bottom: 0;
30
  transition: transform 0.1s;
 
 
 
31
  }
32
 
33
  #player1 {
34
  left: 100px;
35
- background-color: #4299e1;
 
36
  }
37
 
38
  #player2 {
39
  right: 100px;
40
- background-color: #f56565;
 
 
41
  }
42
 
43
  .health-bar {
44
  height: 20px;
45
  transition: width 0.3s;
 
 
46
  }
47
 
48
  #player1-health {
49
- background-color: #4299e1;
50
  }
51
 
52
  #player2-health {
53
- background-color: #f56565;
54
  }
55
 
56
  .attack-effect {
@@ -111,45 +126,138 @@
111
  text-align: center;
112
  color: white;
113
  font-size: 14px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  }
115
  </style>
116
  </head>
117
  <body class="bg-gray-900 text-white">
118
  <div class="container mx-auto py-8">
119
- <h1 class="text-4xl font-bold text-center mb-6">2D Fighting Game</h1>
 
 
120
 
121
  <div class="flex justify-between mb-4">
122
  <div class="w-1/2 pr-4">
123
- <h2 class="text-xl font-semibold mb-2">Player 1 (Blue)</h2>
 
 
124
  <div class="health-container bg-gray-700 rounded h-6 mb-2">
125
- <div id="player1-health" class="health-bar rounded" style="width: 100%"></div>
 
 
 
126
  </div>
127
- <p class="text-sm">Controls: WASD to move, Space to attack</p>
 
 
128
  </div>
129
  <div class="w-1/2 pl-4">
130
- <h2 class="text-xl font-semibold mb-2">Player 2 (Red)</h2>
 
 
131
  <div class="health-container bg-gray-700 rounded h-6 mb-2">
132
- <div id="player2-health" class="health-bar rounded" style="width: 100%"></div>
 
 
 
133
  </div>
134
- <p class="text-sm">Controls: Arrow keys to move, Enter to attack</p>
 
 
135
  </div>
136
  </div>
137
 
138
- <div id="game-container" class="border-4 border-gray-600 rounded-lg relative">
139
- <div id="player1" class="character rounded-t-lg"></div>
140
- <div id="player2" class="character rounded-t-lg"></div>
 
 
 
 
 
 
141
 
142
  <div id="game-over">
143
- <h2 id="winner-text" class="text-4xl font-bold mb-6"></h2>
144
- <button id="restart-btn" class="px-6 py-3 bg-blue-500 hover:bg-blue-600 rounded-lg font-semibold">
145
- Play Again
146
  </button>
147
  </div>
148
 
149
  <div class="controls">
150
  <p>First to reduce opponent's health to zero wins!</p>
 
151
  </div>
152
  </div>
 
 
 
 
 
153
  </div>
154
 
155
  <script>
@@ -160,35 +268,50 @@
160
  const player2 = document.getElementById('player2');
161
  const player1Health = document.getElementById('player1-health');
162
  const player2Health = document.getElementById('player2-health');
 
 
163
  const gameOverScreen = document.getElementById('game-over');
164
  const winnerText = document.getElementById('winner-text');
165
  const restartBtn = document.getElementById('restart-btn');
 
 
 
 
166
 
167
  // Game state
168
  const gameState = {
169
  player1: {
170
  x: 100,
171
  y: 0,
172
- width: 80,
173
  height: 120,
174
  speed: 5,
175
  health: 100,
 
176
  isJumping: false,
177
  isAttacking: false,
178
- direction: 'right'
 
 
 
179
  },
180
  player2: {
181
- x: gameContainer.offsetWidth - 180,
182
  y: 0,
183
- width: 80,
184
  height: 120,
185
  speed: 5,
186
  health: 100,
 
187
  isJumping: false,
188
  isAttacking: false,
189
- direction: 'left'
 
 
 
190
  },
191
- gameRunning: true
 
192
  };
193
 
194
  // Key states
@@ -197,12 +320,14 @@
197
  a: false,
198
  s: false,
199
  d: false,
 
200
  space: false,
201
  arrowup: false,
202
  arrowleft: false,
203
  arrowdown: false,
204
  arrowright: false,
205
- enter: false
 
206
  };
207
 
208
  // Event listeners for keyboard
@@ -214,12 +339,14 @@
214
  case 'a': keys.a = true; break;
215
  case 's': keys.s = true; break;
216
  case 'd': keys.d = true; break;
 
217
  case ' ': keys.space = true; break;
218
  case 'arrowup': keys.arrowup = true; break;
219
  case 'arrowleft': keys.arrowleft = true; break;
220
  case 'arrowdown': keys.arrowdown = true; break;
221
  case 'arrowright': keys.arrowright = true; break;
222
  case 'enter': keys.enter = true; break;
 
223
  }
224
  });
225
 
@@ -229,12 +356,14 @@
229
  case 'a': keys.a = false; break;
230
  case 's': keys.s = false; break;
231
  case 'd': keys.d = false; break;
 
232
  case ' ': keys.space = false; break;
233
  case 'arrowup': keys.arrowup = false; break;
234
  case 'arrowleft': keys.arrowleft = false; break;
235
  case 'arrowdown': keys.arrowdown = false; break;
236
  case 'arrowright': keys.arrowright = false; break;
237
  case 'enter': keys.enter = false; break;
 
238
  }
239
  });
240
 
@@ -242,18 +371,35 @@
242
  restartBtn.addEventListener('click', () => {
243
  gameState.player1.health = 100;
244
  gameState.player2.health = 100;
 
 
245
  gameState.player1.x = 100;
246
- gameState.player2.x = gameContainer.offsetWidth - 180;
247
  gameState.player1.isJumping = false;
248
  gameState.player2.isJumping = false;
249
  gameState.player1.isAttacking = false;
250
  gameState.player2.isAttacking = false;
 
 
 
 
251
  gameState.gameRunning = true;
 
252
 
253
  player1Health.style.width = '100%';
254
  player2Health.style.width = '100%';
 
 
 
 
 
255
 
256
  gameOverScreen.style.display = 'none';
 
 
 
 
 
257
  });
258
 
259
  // Game loop
@@ -264,10 +410,12 @@
264
  if (keys.a && gameState.player1.x > 0) {
265
  gameState.player1.x -= gameState.player1.speed;
266
  gameState.player1.direction = 'left';
 
267
  }
268
  if (keys.d && gameState.player1.x < gameContainer.offsetWidth - gameState.player1.width) {
269
  gameState.player1.x += gameState.player1.speed;
270
  gameState.player1.direction = 'right';
 
271
  }
272
  if (keys.w && !gameState.player1.isJumping) {
273
  gameState.player1.isJumping = true;
@@ -279,7 +427,7 @@
279
  }
280
 
281
  // Player 1 attack
282
- if (keys.space && !gameState.player1.isAttacking) {
283
  gameState.player1.isAttacking = true;
284
  const attackX = gameState.player1.direction === 'right' ?
285
  gameState.player1.x + gameState.player1.width :
@@ -291,17 +439,62 @@
291
  gameState.player1.isAttacking = false;
292
  }, 300);
293
 
294
- checkAttackHit('player1');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  }
296
 
297
  // Player 2 movement
298
  if (keys.arrowleft && gameState.player2.x > 0) {
299
  gameState.player2.x -= gameState.player2.speed;
300
  gameState.player2.direction = 'left';
 
301
  }
302
  if (keys.arrowright && gameState.player2.x < gameContainer.offsetWidth - gameState.player2.width) {
303
  gameState.player2.x += gameState.player2.speed;
304
  gameState.player2.direction = 'right';
 
305
  }
306
  if (keys.arrowup && !gameState.player2.isJumping) {
307
  gameState.player2.isJumping = true;
@@ -313,7 +506,7 @@
313
  }
314
 
315
  // Player 2 attack
316
- if (keys.enter && !gameState.player2.isAttacking) {
317
  gameState.player2.isAttacking = true;
318
  const attackX = gameState.player2.direction === 'right' ?
319
  gameState.player2.x + gameState.player2.width :
@@ -325,13 +518,60 @@
325
  gameState.player2.isAttacking = false;
326
  }, 300);
327
 
328
- checkAttackHit('player2');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  }
330
 
331
  // Update positions
332
  player1.style.left = gameState.player1.x + 'px';
333
  player2.style.left = gameState.player2.x + 'px';
334
 
 
 
 
335
  requestAnimationFrame(gameLoop);
336
  }
337
 
@@ -349,23 +589,46 @@
349
  }
350
 
351
  // Check if attack hits opponent
352
- function checkAttackHit(attacker) {
353
  const attackerState = gameState[attacker];
354
  const defender = attacker === 'player1' ? 'player2' : 'player1';
355
  const defenderState = gameState[defender];
356
  const defenderElement = document.getElementById(defender);
357
 
358
  // Simple collision detection
359
- const attackRange = 50;
360
  const attackerCenterX = attackerState.x + attackerState.width / 2;
361
  const defenderCenterX = defenderState.x + defenderState.width / 2;
362
  const distance = Math.abs(attackerCenterX - defenderCenterX);
363
 
364
- if (distance < attackRange && !defenderState.isJumping) {
365
  // Hit successful
366
- defenderState.health -= 10;
 
367
  document.getElementById(`${defender}-health`).style.width = `${defenderState.health}%`;
368
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  // Visual feedback for hit
370
  defenderElement.classList.add('hit');
371
  setTimeout(() => {
@@ -376,11 +639,26 @@
376
  if (defenderState.health <= 0) {
377
  gameState.gameRunning = false;
378
  gameOverScreen.style.display = 'flex';
379
- winnerText.textContent = `${attacker === 'player1' ? 'Player 1 (Blue)' : 'Player 2 (Red)'} Wins!`;
380
  }
381
  }
382
  }
383
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  // Start the game
385
  gameLoop();
386
  });
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Raccoon Rumble</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ /* Custom CSS */
11
  body {
12
  overflow: hidden;
13
  background-color: #1a202c;
14
+ font-family: 'Press Start 2P', cursive;
15
  }
16
 
17
+ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
18
+
19
  #game-container {
20
  position: relative;
21
  width: 800px;
22
  height: 400px;
23
  margin: 0 auto;
24
+ background-image: url('https://images.unsplash.com/photo-1518098268026-4e89f1a2cd8e?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80');
25
  background-size: cover;
26
  overflow: hidden;
27
+ box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
28
+ border: 4px solid #4fd1c5;
29
+ border-radius: 10px;
30
  }
31
 
32
  .character {
33
  position: absolute;
34
+ width: 100px;
35
  height: 120px;
36
  bottom: 0;
37
  transition: transform 0.1s;
38
+ background-size: contain;
39
+ background-repeat: no-repeat;
40
+ background-position: bottom;
41
  }
42
 
43
  #player1 {
44
  left: 100px;
45
+ background-image: url('https://i.imgur.com/JQZv0Qp.png');
46
+ transform: scaleX(1);
47
  }
48
 
49
  #player2 {
50
  right: 100px;
51
+ background-image: url('https://i.imgur.com/JQZv0Qp.png');
52
+ transform: scaleX(-1);
53
+ filter: hue-rotate(180deg) brightness(1.2);
54
  }
55
 
56
  .health-bar {
57
  height: 20px;
58
  transition: width 0.3s;
59
+ border-radius: 5px;
60
+ box-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
61
  }
62
 
63
  #player1-health {
64
+ background: linear-gradient(90deg, #3b82f6, #1d4ed8);
65
  }
66
 
67
  #player2-health {
68
+ background: linear-gradient(90deg, #ef4444, #b91c1c);
69
  }
70
 
71
  .attack-effect {
 
126
  text-align: center;
127
  color: white;
128
  font-size: 14px;
129
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
130
+ }
131
+
132
+ .finisher-move {
133
+ position: absolute;
134
+ width: 200px;
135
+ height: 200px;
136
+ background-size: contain;
137
+ background-repeat: no-repeat;
138
+ background-position: center;
139
+ z-index: 50;
140
+ animation: finisher 1.5s forwards;
141
+ display: none;
142
+ }
143
+
144
+ @keyframes finisher {
145
+ 0% { transform: scale(0.5); opacity: 0; }
146
+ 20% { transform: scale(1.2); opacity: 1; }
147
+ 80% { transform: scale(1.2); opacity: 1; }
148
+ 100% { transform: scale(1.5); opacity: 0; }
149
+ }
150
+
151
+ .finisher-text {
152
+ position: absolute;
153
+ color: #fff;
154
+ font-size: 24px;
155
+ font-weight: bold;
156
+ text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #e60073;
157
+ z-index: 60;
158
+ animation: textPulse 1s infinite;
159
+ display: none;
160
+ }
161
+
162
+ @keyframes textPulse {
163
+ 0% { transform: scale(1); }
164
+ 50% { transform: scale(1.2); }
165
+ 100% { transform: scale(1); }
166
+ }
167
+
168
+ .power-meter {
169
+ height: 10px;
170
+ background: linear-gradient(90deg, #f59e0b, #fbbf24);
171
+ border-radius: 5px;
172
+ transition: width 0.3s;
173
+ box-shadow: 0 0 5px rgba(245, 158, 11, 0.8);
174
+ }
175
+
176
+ .combo-counter {
177
+ position: absolute;
178
+ top: 10px;
179
+ right: 10px;
180
+ color: white;
181
+ font-size: 18px;
182
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
183
+ display: none;
184
+ }
185
+
186
+ .combo-text {
187
+ animation: comboPulse 0.3s;
188
+ }
189
+
190
+ @keyframes comboPulse {
191
+ 0% { transform: scale(1); }
192
+ 50% { transform: scale(1.5); }
193
+ 100% { transform: scale(1); }
194
  }
195
  </style>
196
  </head>
197
  <body class="bg-gray-900 text-white">
198
  <div class="container mx-auto py-8">
199
+ <h1 class="text-4xl font-bold text-center mb-6 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-red-500">
200
+ <i class="fas fa-paw mr-2"></i>Raccoon Rumble<i class="fas fa-paw ml-2"></i>
201
+ </h1>
202
 
203
  <div class="flex justify-between mb-4">
204
  <div class="w-1/2 pr-4">
205
+ <h2 class="text-xl font-semibold mb-2 text-blue-400">
206
+ <i class="fas fa-band-aid mr-2"></i>Blue Bandit
207
+ </h2>
208
  <div class="health-container bg-gray-700 rounded h-6 mb-2">
209
+ <div id="player1-health" class="health-bar" style="width: 100%"></div>
210
+ </div>
211
+ <div class="power-container bg-gray-800 rounded h-3 mb-2">
212
+ <div id="player1-power" class="power-meter" style="width: 0%"></div>
213
  </div>
214
+ <p class="text-sm text-blue-300">
215
+ WASD: Move | Space: Attack | F: Finisher
216
+ </p>
217
  </div>
218
  <div class="w-1/2 pl-4">
219
+ <h2 class="text-xl font-semibold mb-2 text-red-400">
220
+ <i class="fas fa-band-aid mr-2"></i>Red Raider
221
+ </h2>
222
  <div class="health-container bg-gray-700 rounded h-6 mb-2">
223
+ <div id="player2-health" class="health-bar" style="width: 100%"></div>
224
+ </div>
225
+ <div class="power-container bg-gray-800 rounded h-3 mb-2">
226
+ <div id="player2-power" class="power-meter" style="width: 0%"></div>
227
  </div>
228
+ <p class="text-sm text-red-300">
229
+ Arrows: Move | Enter: Attack | M: Finisher
230
+ </p>
231
  </div>
232
  </div>
233
 
234
+ <div id="game-container" class="relative">
235
+ <div id="player1" class="character"></div>
236
+ <div id="player2" class="character"></div>
237
+
238
+ <div id="finisher-effect" class="finisher-move"></div>
239
+ <div id="finisher-text" class="finisher-text">FINISHER!</div>
240
+
241
+ <div id="player1-combo" class="combo-counter">Combo: 0</div>
242
+ <div id="player2-combo" class="combo-counter">Combo: 0</div>
243
 
244
  <div id="game-over">
245
+ <h2 id="winner-text" class="text-4xl font-bold mb-6 text-transparent bg-clip-text bg-gradient-to-r from-yellow-300 to-red-500"></h2>
246
+ <button id="restart-btn" class="px-6 py-3 bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 rounded-lg font-semibold shadow-lg transform transition hover:scale-105">
247
+ <i class="fas fa-redo mr-2"></i>Play Again
248
  </button>
249
  </div>
250
 
251
  <div class="controls">
252
  <p>First to reduce opponent's health to zero wins!</p>
253
+ <p>Build power meter to unleash FINISHER moves!</p>
254
  </div>
255
  </div>
256
+
257
+ <div class="mt-6 text-center text-gray-400 text-sm">
258
+ <p>Special Moves: Press Attack + Down for a low attack</p>
259
+ <p>Finishers can only be used when power meter is full</p>
260
+ </div>
261
  </div>
262
 
263
  <script>
 
268
  const player2 = document.getElementById('player2');
269
  const player1Health = document.getElementById('player1-health');
270
  const player2Health = document.getElementById('player2-health');
271
+ const player1Power = document.getElementById('player1-power');
272
+ const player2Power = document.getElementById('player2-power');
273
  const gameOverScreen = document.getElementById('game-over');
274
  const winnerText = document.getElementById('winner-text');
275
  const restartBtn = document.getElementById('restart-btn');
276
+ const finisherEffect = document.getElementById('finisher-effect');
277
+ const finisherText = document.getElementById('finisher-text');
278
+ const player1Combo = document.getElementById('player1-combo');
279
+ const player2Combo = document.getElementById('player2-combo');
280
 
281
  // Game state
282
  const gameState = {
283
  player1: {
284
  x: 100,
285
  y: 0,
286
+ width: 100,
287
  height: 120,
288
  speed: 5,
289
  health: 100,
290
+ power: 0,
291
  isJumping: false,
292
  isAttacking: false,
293
+ isUsingFinisher: false,
294
+ direction: 'right',
295
+ comboCount: 0,
296
+ lastHitTime: 0
297
  },
298
  player2: {
299
+ x: gameContainer.offsetWidth - 200,
300
  y: 0,
301
+ width: 100,
302
  height: 120,
303
  speed: 5,
304
  health: 100,
305
+ power: 0,
306
  isJumping: false,
307
  isAttacking: false,
308
+ isUsingFinisher: false,
309
+ direction: 'left',
310
+ comboCount: 0,
311
+ lastHitTime: 0
312
  },
313
+ gameRunning: true,
314
+ finisherActive: false
315
  };
316
 
317
  // Key states
 
320
  a: false,
321
  s: false,
322
  d: false,
323
+ f: false,
324
  space: false,
325
  arrowup: false,
326
  arrowleft: false,
327
  arrowdown: false,
328
  arrowright: false,
329
+ enter: false,
330
+ m: false
331
  };
332
 
333
  // Event listeners for keyboard
 
339
  case 'a': keys.a = true; break;
340
  case 's': keys.s = true; break;
341
  case 'd': keys.d = true; break;
342
+ case 'f': keys.f = true; break;
343
  case ' ': keys.space = true; break;
344
  case 'arrowup': keys.arrowup = true; break;
345
  case 'arrowleft': keys.arrowleft = true; break;
346
  case 'arrowdown': keys.arrowdown = true; break;
347
  case 'arrowright': keys.arrowright = true; break;
348
  case 'enter': keys.enter = true; break;
349
+ case 'm': keys.m = true; break;
350
  }
351
  });
352
 
 
356
  case 'a': keys.a = false; break;
357
  case 's': keys.s = false; break;
358
  case 'd': keys.d = false; break;
359
+ case 'f': keys.f = false; break;
360
  case ' ': keys.space = false; break;
361
  case 'arrowup': keys.arrowup = false; break;
362
  case 'arrowleft': keys.arrowleft = false; break;
363
  case 'arrowdown': keys.arrowdown = false; break;
364
  case 'arrowright': keys.arrowright = false; break;
365
  case 'enter': keys.enter = false; break;
366
+ case 'm': keys.m = false; break;
367
  }
368
  });
369
 
 
371
  restartBtn.addEventListener('click', () => {
372
  gameState.player1.health = 100;
373
  gameState.player2.health = 100;
374
+ gameState.player1.power = 0;
375
+ gameState.player2.power = 0;
376
  gameState.player1.x = 100;
377
+ gameState.player2.x = gameContainer.offsetWidth - 200;
378
  gameState.player1.isJumping = false;
379
  gameState.player2.isJumping = false;
380
  gameState.player1.isAttacking = false;
381
  gameState.player2.isAttacking = false;
382
+ gameState.player1.isUsingFinisher = false;
383
+ gameState.player2.isUsingFinisher = false;
384
+ gameState.player1.comboCount = 0;
385
+ gameState.player2.comboCount = 0;
386
  gameState.gameRunning = true;
387
+ gameState.finisherActive = false;
388
 
389
  player1Health.style.width = '100%';
390
  player2Health.style.width = '100%';
391
+ player1Power.style.width = '0%';
392
+ player2Power.style.width = '0%';
393
+
394
+ player1Combo.style.display = 'none';
395
+ player2Combo.style.display = 'none';
396
 
397
  gameOverScreen.style.display = 'none';
398
+ finisherEffect.style.display = 'none';
399
+ finisherText.style.display = 'none';
400
+
401
+ player1.style.transform = 'scaleX(1)';
402
+ player2.style.transform = 'scaleX(-1)';
403
  });
404
 
405
  // Game loop
 
410
  if (keys.a && gameState.player1.x > 0) {
411
  gameState.player1.x -= gameState.player1.speed;
412
  gameState.player1.direction = 'left';
413
+ player1.style.transform = 'scaleX(1)';
414
  }
415
  if (keys.d && gameState.player1.x < gameContainer.offsetWidth - gameState.player1.width) {
416
  gameState.player1.x += gameState.player1.speed;
417
  gameState.player1.direction = 'right';
418
+ player1.style.transform = 'scaleX(-1)';
419
  }
420
  if (keys.w && !gameState.player1.isJumping) {
421
  gameState.player1.isJumping = true;
 
427
  }
428
 
429
  // Player 1 attack
430
+ if (keys.space && !gameState.player1.isAttacking && !gameState.player1.isUsingFinisher) {
431
  gameState.player1.isAttacking = true;
432
  const attackX = gameState.player1.direction === 'right' ?
433
  gameState.player1.x + gameState.player1.width :
 
439
  gameState.player1.isAttacking = false;
440
  }, 300);
441
 
442
+ checkAttackHit('player1', keys.s ? 'low' : 'normal');
443
+ }
444
+
445
+ // Player 1 finisher
446
+ if (keys.f && gameState.player1.power >= 100 && !gameState.finisherActive) {
447
+ gameState.player1.isUsingFinisher = true;
448
+ gameState.finisherActive = true;
449
+ gameState.player1.power = 0;
450
+ player1Power.style.width = '0%';
451
+
452
+ // Show finisher effect
453
+ finisherEffect.style.backgroundImage = 'url("https://i.imgur.com/8KQn3kG.png")';
454
+ finisherEffect.style.left = (gameState.player2.x - 50) + 'px';
455
+ finisherEffect.style.top = (gameState.player2.y - 50) + 'px';
456
+ finisherEffect.style.display = 'block';
457
+
458
+ finisherText.style.left = (gameState.player2.x + 50) + 'px';
459
+ finisherText.style.top = (gameState.player2.y - 80) + 'px';
460
+ finisherText.style.display = 'block';
461
+
462
+ setTimeout(() => {
463
+ finisherEffect.style.display = 'none';
464
+ finisherText.style.display = 'none';
465
+ gameState.player1.isUsingFinisher = false;
466
+ gameState.finisherActive = false;
467
+ }, 1500);
468
+
469
+ // Big damage
470
+ gameState.player2.health -= 30;
471
+ player2Health.style.width = `${gameState.player2.health}%`;
472
+
473
+ // Visual feedback for hit
474
+ player2.classList.add('hit');
475
+ setTimeout(() => {
476
+ player2.classList.remove('hit');
477
+ }, 300);
478
+
479
+ // Check if game over
480
+ if (gameState.player2.health <= 0) {
481
+ gameState.gameRunning = false;
482
+ gameOverScreen.style.display = 'flex';
483
+ winnerText.textContent = `Blue Bandit Wins!`;
484
+ winnerText.innerHTML += '<br><span class="text-2xl">Finisher Move!</span>';
485
+ }
486
  }
487
 
488
  // Player 2 movement
489
  if (keys.arrowleft && gameState.player2.x > 0) {
490
  gameState.player2.x -= gameState.player2.speed;
491
  gameState.player2.direction = 'left';
492
+ player2.style.transform = 'scaleX(-1)';
493
  }
494
  if (keys.arrowright && gameState.player2.x < gameContainer.offsetWidth - gameState.player2.width) {
495
  gameState.player2.x += gameState.player2.speed;
496
  gameState.player2.direction = 'right';
497
+ player2.style.transform = 'scaleX(1)';
498
  }
499
  if (keys.arrowup && !gameState.player2.isJumping) {
500
  gameState.player2.isJumping = true;
 
506
  }
507
 
508
  // Player 2 attack
509
+ if (keys.enter && !gameState.player2.isAttacking && !gameState.player2.isUsingFinisher) {
510
  gameState.player2.isAttacking = true;
511
  const attackX = gameState.player2.direction === 'right' ?
512
  gameState.player2.x + gameState.player2.width :
 
518
  gameState.player2.isAttacking = false;
519
  }, 300);
520
 
521
+ checkAttackHit('player2', keys.arrowdown ? 'low' : 'normal');
522
+ }
523
+
524
+ // Player 2 finisher
525
+ if (keys.m && gameState.player2.power >= 100 && !gameState.finisherActive) {
526
+ gameState.player2.isUsingFinisher = true;
527
+ gameState.finisherActive = true;
528
+ gameState.player2.power = 0;
529
+ player2Power.style.width = '0%';
530
+
531
+ // Show finisher effect
532
+ finisherEffect.style.backgroundImage = 'url("https://i.imgur.com/8KQn3kG.png")';
533
+ finisherEffect.style.filter = 'hue-rotate(180deg)';
534
+ finisherEffect.style.left = (gameState.player1.x - 50) + 'px';
535
+ finisherEffect.style.top = (gameState.player1.y - 50) + 'px';
536
+ finisherEffect.style.display = 'block';
537
+
538
+ finisherText.style.left = (gameState.player1.x + 50) + 'px';
539
+ finisherText.style.top = (gameState.player1.y - 80) + 'px';
540
+ finisherText.style.display = 'block';
541
+
542
+ setTimeout(() => {
543
+ finisherEffect.style.display = 'none';
544
+ finisherText.style.display = 'none';
545
+ gameState.player2.isUsingFinisher = false;
546
+ gameState.finisherActive = false;
547
+ }, 1500);
548
+
549
+ // Big damage
550
+ gameState.player1.health -= 30;
551
+ player1Health.style.width = `${gameState.player1.health}%`;
552
+
553
+ // Visual feedback for hit
554
+ player1.classList.add('hit');
555
+ setTimeout(() => {
556
+ player1.classList.remove('hit');
557
+ }, 300);
558
+
559
+ // Check if game over
560
+ if (gameState.player1.health <= 0) {
561
+ gameState.gameRunning = false;
562
+ gameOverScreen.style.display = 'flex';
563
+ winnerText.textContent = `Red Raider Wins!`;
564
+ winnerText.innerHTML += '<br><span class="text-2xl">Finisher Move!</span>';
565
+ }
566
  }
567
 
568
  // Update positions
569
  player1.style.left = gameState.player1.x + 'px';
570
  player2.style.left = gameState.player2.x + 'px';
571
 
572
+ // Update combo counters
573
+ updateComboCounters();
574
+
575
  requestAnimationFrame(gameLoop);
576
  }
577
 
 
589
  }
590
 
591
  // Check if attack hits opponent
592
+ function checkAttackHit(attacker, attackType) {
593
  const attackerState = gameState[attacker];
594
  const defender = attacker === 'player1' ? 'player2' : 'player1';
595
  const defenderState = gameState[defender];
596
  const defenderElement = document.getElementById(defender);
597
 
598
  // Simple collision detection
599
+ const attackRange = attackType === 'low' ? 60 : 50;
600
  const attackerCenterX = attackerState.x + attackerState.width / 2;
601
  const defenderCenterX = defenderState.x + defenderState.width / 2;
602
  const distance = Math.abs(attackerCenterX - defenderCenterX);
603
 
604
+ if (distance < attackRange && (attackType === 'low' || !defenderState.isJumping)) {
605
  // Hit successful
606
+ const damage = attackType === 'low' ? 8 : 10;
607
+ defenderState.health -= damage;
608
  document.getElementById(`${defender}-health`).style.width = `${defenderState.health}%`;
609
 
610
+ // Add power to attacker
611
+ attackerState.power = Math.min(attackerState.power + 15, 100);
612
+ document.getElementById(`${attacker}-power`).style.width = `${attackerState.power}%`;
613
+
614
+ // Combo system
615
+ const now = Date.now();
616
+ if (now - attackerState.lastHitTime < 1000) {
617
+ attackerState.comboCount++;
618
+ } else {
619
+ attackerState.comboCount = 1;
620
+ }
621
+ attackerState.lastHitTime = now;
622
+
623
+ // Update combo display
624
+ const comboElement = document.getElementById(`${attacker}-combo`);
625
+ comboElement.textContent = `Combo: ${attackerState.comboCount}`;
626
+ comboElement.style.display = 'block';
627
+ comboElement.classList.add('combo-text');
628
+ setTimeout(() => {
629
+ comboElement.classList.remove('combo-text');
630
+ }, 300);
631
+
632
  // Visual feedback for hit
633
  defenderElement.classList.add('hit');
634
  setTimeout(() => {
 
639
  if (defenderState.health <= 0) {
640
  gameState.gameRunning = false;
641
  gameOverScreen.style.display = 'flex';
642
+ winnerText.textContent = `${attacker === 'player1' ? 'Blue Bandit' : 'Red Raider'} Wins!`;
643
  }
644
  }
645
  }
646
 
647
+ // Update combo counters
648
+ function updateComboCounters() {
649
+ const now = Date.now();
650
+
651
+ if (now - gameState.player1.lastHitTime > 2000 && gameState.player1.comboCount > 0) {
652
+ gameState.player1.comboCount = 0;
653
+ player1Combo.style.display = 'none';
654
+ }
655
+
656
+ if (now - gameState.player2.lastHitTime > 2000 && gameState.player2.comboCount > 0) {
657
+ gameState.player2.comboCount = 0;
658
+ player2Combo.style.display = 'none';
659
+ }
660
+ }
661
+
662
  // Start the game
663
  gameLoop();
664
  });