KaiShin1885 commited on
Commit
5dd528f
·
verified ·
1 Parent(s): b5d9e98

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +235 -22
index.html CHANGED
@@ -17,7 +17,6 @@
17
  height: 100px;
18
  position: absolute;
19
  bottom: 0;
20
- transition: height 0.2s;
21
  background-size: contain;
22
  background-repeat: no-repeat;
23
  background-position: center;
@@ -100,16 +99,6 @@
100
  animation: counterAnim 0.4s linear;
101
  }
102
 
103
- #status {
104
- position: fixed;
105
- left: 20px;
106
- bottom: 20px;
107
- padding: 10px;
108
- background: rgba(0,0,0,0.8);
109
- color: white;
110
- font-family: monospace;
111
- }
112
-
113
  #instructions {
114
  position: fixed;
115
  right: 20px;
@@ -152,7 +141,6 @@
152
  </div>
153
  <div id="player" class="character"></div>
154
  <div id="enemy" class="character"></div>
155
- <div id="status"></div>
156
  <div id="instructions">
157
  Controls:<br><br>
158
  W - Jump<br>
@@ -167,28 +155,38 @@
167
  </div>
168
 
169
  <script>
170
- // 기본 스프라이트 이미지 설정
171
- const SPRITE_BASE64 = "data:image/png;base64,<provided_image_base64>";
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
  const SPRITES = {
174
- stand: [
175
- SPRITE_BASE64, // kstand1
176
- SPRITE_BASE64, // kstand2 - 실제로는 다른 이미지
177
- SPRITE_BASE64 // kstand3 - 실제로는 다른 이미지
178
- ]
179
  };
180
 
181
  class Character {
182
  constructor(element, isPlayer = true) {
183
  this.element = element;
184
  this.isPlayer = isPlayer;
185
- this.health = 1000;
186
  this.pos = { x: isPlayer ? 100 : 650, y: 0 };
187
  this.vel = { x: 0, y: 0 };
188
  this.direction = isPlayer ? 'right' : 'left';
189
  this.isMoving = false;
190
  this.isAttacking = false;
191
  this.isJumping = false;
 
192
  this.currentFrame = 0;
193
  this.lastAnimationUpdate = 0;
194
 
@@ -199,7 +197,7 @@
199
 
200
  updateAnimation(timestamp) {
201
  if (this.isPlayer && !this.isMoving && !this.isAttacking) {
202
- if (timestamp - this.lastAnimationUpdate >= 500) {
203
  this.currentFrame = (this.currentFrame + 1) % SPRITES.stand.length;
204
  this.element.style.backgroundImage =
205
  `url(${SPRITES.stand[this.currentFrame]})`;
@@ -209,7 +207,222 @@
209
  }
210
  }
211
 
212
- // Game 클래스를 계속 구현할까요?
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  </script>
214
  </body>
215
  </html>
 
17
  height: 100px;
18
  position: absolute;
19
  bottom: 0;
 
20
  background-size: contain;
21
  background-repeat: no-repeat;
22
  background-position: center;
 
99
  animation: counterAnim 0.4s linear;
100
  }
101
 
 
 
 
 
 
 
 
 
 
 
102
  #instructions {
103
  position: fixed;
104
  right: 20px;
 
141
  </div>
142
  <div id="player" class="character"></div>
143
  <div id="enemy" class="character"></div>
 
144
  <div id="instructions">
145
  Controls:<br><br>
146
  W - Jump<br>
 
155
  </div>
156
 
157
  <script>
158
+ const SETTINGS = {
159
+ FPS: 60,
160
+ FRAME_TIME: 1000 / 60,
161
+ MOVE_SPEED: 5,
162
+ JUMP_FORCE: 15,
163
+ GRAVITY: 0.8,
164
+ INITIAL_HEALTH: 1000,
165
+ DAMAGE: 10,
166
+ SPECIAL_DAMAGE: 300,
167
+ ATTACK_DELAY: 200,
168
+ COUNTER_WINDOW: 400,
169
+ COUNTER_COOLDOWN: 5000,
170
+ SPECIAL_COOLDOWN: 30000,
171
+ ANIMATION_INTERVAL: 500
172
+ };
173
 
174
  const SPRITES = {
175
+ stand: ['kstand1.png', 'kstand2.png', 'kstand3.png']
 
 
 
 
176
  };
177
 
178
  class Character {
179
  constructor(element, isPlayer = true) {
180
  this.element = element;
181
  this.isPlayer = isPlayer;
182
+ this.health = SETTINGS.INITIAL_HEALTH;
183
  this.pos = { x: isPlayer ? 100 : 650, y: 0 };
184
  this.vel = { x: 0, y: 0 };
185
  this.direction = isPlayer ? 'right' : 'left';
186
  this.isMoving = false;
187
  this.isAttacking = false;
188
  this.isJumping = false;
189
+ this.isBlocking = false;
190
  this.currentFrame = 0;
191
  this.lastAnimationUpdate = 0;
192
 
 
197
 
198
  updateAnimation(timestamp) {
199
  if (this.isPlayer && !this.isMoving && !this.isAttacking) {
200
+ if (timestamp - this.lastAnimationUpdate >= SETTINGS.ANIMATION_INTERVAL) {
201
  this.currentFrame = (this.currentFrame + 1) % SPRITES.stand.length;
202
  this.element.style.backgroundImage =
203
  `url(${SPRITES.stand[this.currentFrame]})`;
 
207
  }
208
  }
209
 
210
+ class Game {
211
+ constructor() {
212
+ this.lastFrameTime = 0;
213
+ this.gameTime = 60;
214
+ this.specialCooldown = Date.now() + SETTINGS.SPECIAL_COOLDOWN;
215
+ this.counterCooldown = 0;
216
+ this.canCounter = false;
217
+ this.lastHit = null;
218
+ this.isGameOver = false;
219
+
220
+ this.player = new Character(document.getElementById('player'), true);
221
+ this.enemy = new Character(document.getElementById('enemy'), false);
222
+
223
+ this.keys = {};
224
+ this.setupControls();
225
+ this.startGame();
226
+ }
227
+
228
+ setupControls() {
229
+ document.addEventListener('keydown', (e) => {
230
+ if (this.isGameOver) return;
231
+ this.keys[e.key.toLowerCase()] = true;
232
+
233
+ switch(e.key.toLowerCase()) {
234
+ case 'j':
235
+ case 'k':
236
+ this.startAttack(this.player, this.enemy,
237
+ e.key === 'k' ? 'high' : 'mid');
238
+ break;
239
+ case 'q':
240
+ if (Date.now() >= this.specialCooldown) {
241
+ this.useUltimate(this.player, this.enemy);
242
+ }
243
+ break;
244
+ case 'l':
245
+ this.tryCounter();
246
+ break;
247
+ case 's':
248
+ this.player.element.classList.add('crouch');
249
+ break;
250
+ }
251
+ });
252
+
253
+ document.addEventListener('keyup', (e) => {
254
+ this.keys[e.key.toLowerCase()] = false;
255
+ if (e.key.toLowerCase() === 's') {
256
+ this.player.element.classList.remove('crouch');
257
+ }
258
+ });
259
+ }
260
+
261
+ startAttack(attacker, defender, type) {
262
+ attacker.isAttacking = true;
263
+ const attackEl = document.createElement('div');
264
+ attackEl.className = `attack ${type}Attack`;
265
+
266
+ const xOffset = attacker.direction === 'right' ? 45 : -30;
267
+ const yOffset = type === 'high' ? 70 : 35;
268
+
269
+ attackEl.style.left = `${attacker.pos.x + xOffset}px`;
270
+ attackEl.style.bottom = `${yOffset}px`;
271
+ document.getElementById('gameArea').appendChild(attackEl);
272
+
273
+ setTimeout(() => {
274
+ attackEl.remove();
275
+ if (!defender.isBlocking) {
276
+ defender.health -= SETTINGS.DAMAGE;
277
+ this.updateHealthBars();
278
+ }
279
+ }, SETTINGS.ATTACK_DELAY);
280
+
281
+ setTimeout(() => {
282
+ attacker.isAttacking = false;
283
+ }, SETTINGS.ATTACK_DELAY + 100);
284
+ }
285
+
286
+ useUltimate(attacker, defender) {
287
+ const ultimateEl = document.createElement('div');
288
+ ultimateEl.className = 'attack ultimate';
289
+
290
+ const xOffset = attacker.direction === 'right' ? 45 : -300;
291
+ ultimateEl.style.left = `${attacker.pos.x + xOffset}px`;
292
+ ultimateEl.style.bottom = '0px';
293
+
294
+ document.getElementById('gameArea').appendChild(ultimateEl);
295
+
296
+ setTimeout(() => {
297
+ if (!defender.isBlocking) {
298
+ defender.health -= SETTINGS.SPECIAL_DAMAGE;
299
+ this.updateHealthBars();
300
+ }
301
+ ultimateEl.remove();
302
+ }, 300);
303
+
304
+ this.specialCooldown = Date.now() + SETTINGS.SPECIAL_COOLDOWN;
305
+ }
306
+
307
+ tryCounter() {
308
+ if (Date.now() < this.counterCooldown) return;
309
+
310
+ const counterEl = document.createElement('div');
311
+ counterEl.className = 'counter-effect';
312
+ counterEl.style.left = `${this.player.pos.x}px`;
313
+ counterEl.style.bottom = '0px';
314
+ document.getElementById('gameArea').appendChild(counterEl);
315
+
316
+ setTimeout(() => counterEl.remove(), 400);
317
+
318
+ if (this.lastHit && Date.now() - this.lastHit.time <= SETTINGS.COUNTER_WINDOW) {
319
+ this.player.isBlocking = true;
320
+ setTimeout(() => {
321
+ this.player.isBlocking = false;
322
+ }, 400);
323
+ } else {
324
+ this.counterCooldown = Date.now() + SETTINGS.COUNTER_COOLDOWN;
325
+ }
326
+ }
327
+
328
+ updateAI() {
329
+ if (Date.now() - this.enemy.lastAction < 300) return;
330
+
331
+ const distance = Math.abs(this.player.pos.x - this.enemy.pos.x);
332
+ const healthRatio = this.enemy.health / this.player.health;
333
+
334
+ if (healthRatio < 0.7 || distance < 80) {
335
+ this.enemy.vel.x = -SETTINGS.MOVE_SPEED;
336
+ } else if (distance > 150) {
337
+ this.enemy.vel.x = SETTINGS.MOVE_SPEED;
338
+ } else if (Math.random() < 0.05) {
339
+ this.startAttack(this.enemy, this.player,
340
+ Math.random() > 0.5 ? 'high' : 'mid');
341
+ }
342
+
343
+ this.enemy.direction = this.player.pos.x > this.enemy.pos.x ?
344
+ 'right' : 'left';
345
+ }
346
+
347
+ update(timestamp) {
348
+ if (timestamp - this.lastFrameTime >= SETTINGS.FRAME_TIME) {
349
+ if (this.keys['w'] && !this.player.isJumping) {
350
+ this.player.isJumping = true;
351
+ this.player.vel.y = -SETTINGS.JUMP_FORCE;
352
+ }
353
+ if (this.keys['a']) {
354
+ this.player.vel.x = -SETTINGS.MOVE_SPEED;
355
+ this.player.direction = 'left';
356
+ this.player.isMoving = true;
357
+ this.player.element.classList.add('facing-left');
358
+ } else if (this.keys['d']) {
359
+ this.player.vel.x = SETTINGS.MOVE_SPEED;
360
+ this.player.direction = 'right';
361
+ this.player.isMoving = true;
362
+ this.player.element.classList.remove('facing-left');
363
+ } else {
364
+ this.player.isMoving = false;
365
+ }
366
+
367
+ [this.player, this.enemy].forEach(char => {
368
+ if (char.isJumping) {
369
+ char.vel.y += SETTINGS.GRAVITY;
370
+ char.pos.y = Math.max(0, char.pos.y - char.vel.y);
371
+ if (char.pos.y === 0) {
372
+ char.isJumping = false;
373
+ char.vel.y = 0;
374
+ }
375
+ }
376
+
377
+ char.pos.x += char.vel.x;
378
+ char.pos.x = Math.max(0, Math.min(755, char.pos.x));
379
+ char.vel.x *= 0.8;
380
+
381
+ char.element.style.left = `${char.pos.x}px`;
382
+ char.element.style.bottom = `${char.pos.y}px`;
383
+
384
+ char.updateAnimation(timestamp);
385
+ });
386
+
387
+ this.updateAI();
388
+ this.lastFrameTime = timestamp;
389
+ }
390
+
391
+ if (!this.isGameOver) {
392
+ requestAnimationFrame(this.update.bind(this));
393
+ }
394
+ }
395
+
396
+ updateHealthBars() {
397
+ document.getElementById('playerHealthFill').style.width =
398
+ `${(this.player.health/SETTINGS.INITIAL_HEALTH)*100}%`;
399
+ document.getElementById('enemyHealthFill').style.width =
400
+ `${(this.enemy.health/SETTINGS.INITIAL_HEALTH)*100}%`;
401
+ }
402
+
403
+ startGame() {
404
+ this.updateHealthBars();
405
+ requestAnimationFrame(this.update.bind(this));
406
+
407
+ const timer = setInterval(() => {
408
+ this.gameTime--;
409
+ document.getElementById('timer').textContent = this.gameTime;
410
+
411
+ if (this.gameTime <= 0) {
412
+ clearInterval(timer);
413
+ this.endGame();
414
+ }
415
+ }, 1000);
416
+ }
417
+
418
+ endGame() {
419
+ this.isGameOver = true;
420
+ const winner = this.player.health > this.enemy.health ? 'Player' : 'Enemy';
421
+ alert(`Game Over! ${winner} wins!`);
422
+ }
423
+ }
424
+
425
+ new Game();
426
  </script>
427
  </body>
428
  </html>