KaiShin1885 commited on
Commit
e5f4407
1 Parent(s): df3d9b0

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +193 -74
index.html CHANGED
@@ -172,41 +172,94 @@
172
  };
173
 
174
  const SPRITES = {
175
- stand: ['kstand1.png', 'kstand2.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
 
193
- if (isPlayer) {
194
- this.element.style.backgroundImage = `url(${SPRITES.stand[0]})`;
195
- }
 
 
 
 
196
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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]})`;
204
- this.lastAnimationUpdate = timestamp;
205
- }
206
- }
 
 
 
 
 
 
 
 
207
  }
208
  }
209
 
 
 
 
 
 
 
210
  class Game {
211
  constructor() {
212
  this.lastFrameTime = 0;
@@ -224,6 +277,48 @@
224
  this.setupControls();
225
  this.startGame();
226
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
  setupControls() {
229
  document.addEventListener('keydown', (e) => {
@@ -258,8 +353,21 @@
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
 
@@ -269,18 +377,25 @@
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
  this.checkGameOver();
279
  }
280
  }, SETTINGS.ATTACK_DELAY);
281
-
282
  setTimeout(() => {
283
  attacker.isAttacking = false;
 
 
 
 
284
  }, SETTINGS.ATTACK_DELAY + 100);
285
  }
286
 
@@ -346,55 +461,59 @@
346
  'right' : 'left';
347
  }
348
 
349
- update(timestamp) {
350
- if (timestamp - this.lastFrameTime >= SETTINGS.FRAME_TIME) {
351
- if (this.keys['w'] && !this.player.isJumping) {
352
- this.player.isJumping = true;
353
- this.player.vel.y = -SETTINGS.JUMP_FORCE;
354
- }
355
- if (this.keys['a']) {
356
- this.player.vel.x = -SETTINGS.MOVE_SPEED;
357
- this.player.direction = 'left';
358
- this.player.isMoving = true;
359
- this.player.element.classList.add('facing-left');
360
- } else if (this.keys['d']) {
361
- this.player.vel.x = SETTINGS.MOVE_SPEED;
362
- this.player.direction = 'right';
363
- this.player.isMoving = true;
364
- this.player.element.classList.remove('facing-left');
365
- } else {
366
- this.player.isMoving = false;
367
- }
368
-
369
- [this.player, this.enemy].forEach(char => {
370
- if (char.isJumping) {
371
- char.vel.y += SETTINGS.GRAVITY;
372
- char.pos.y = Math.max(0, char.pos.y - char.vel.y);
373
- if (char.pos.y === 0) {
374
- char.isJumping = false;
375
- char.vel.y = 0;
376
- }
377
- }
378
-
379
- char.pos.x += char.vel.x;
380
- char.pos.x = Math.max(0, Math.min(755, char.pos.x));
381
- char.vel.x *= 0.8;
382
-
383
- char.element.style.left = `${char.pos.x}px`;
384
- char.element.style.bottom = `${char.pos.y}px`;
385
-
386
- char.updateAnimation(timestamp);
387
- });
388
 
389
- this.updateAI();
390
- this.lastFrameTime = timestamp;
391
- }
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
- if (!this.isGameOver) {
394
- requestAnimationFrame(this.update.bind(this));
 
 
 
 
 
 
395
  }
396
  }
397
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
  updateHealthBars() {
399
  document.getElementById('playerHealthFill').style.width =
400
  `${(this.player.health / SETTINGS.INITIAL_HEALTH) * 100}%`;
 
172
  };
173
 
174
  const SPRITES = {
175
+ stand: ['kstand1.png', 'kstand2.png'],
176
+ midAttack: [
177
+ 'kmidattack1.png',
178
+ 'kmidattack2.png',
179
+ 'kmidattack3.png',
180
+ 'kmidattack4.png',
181
+ 'kmidattack5.png'
182
+ ]
183
  };
184
 
185
  class Character {
186
+ constructor(element, isPlayer = true) {
187
+ this.element = element;
188
+ this.isPlayer = isPlayer;
189
+ this.health = SETTINGS.INITIAL_HEALTH;
190
+ this.pos = { x: isPlayer ? 100 : 650, y: 0 };
191
+ this.vel = { x: 0, y: 0 };
192
+ this.direction = isPlayer ? 'right' : 'left';
193
+ this.isMoving = false;
194
+ this.isAttacking = false;
195
+ this.isJumping = false;
196
+ this.isBlocking = false;
197
+ this.currentFrame = 0;
198
+ this.lastAnimationUpdate = 0;
199
+ this.midAttackHits = 0;
200
+ this.isInCombo = false;
201
+ this.currentAnimation = 'stand';
202
+ this.animationFrame = 0;
203
+ this.lastAction = 0; // AI를 위한 마지막 행동 시간 추가
204
+
205
+ if (isPlayer) {
206
+ this.element.style.backgroundImage = `url(${SPRITES.stand[0]})`;
207
+ }
208
+ }
209
 
210
+ updateAnimation(timestamp) {
211
+ if (!this.isPlayer) return;
212
+
213
+ if (timestamp - this.lastAnimationUpdate >= SETTINGS.ANIMATION_INTERVAL) {
214
+ if (this.currentAnimation === 'stand' && !this.isMoving && !this.isAttacking) {
215
+ this.currentFrame = (this.currentFrame + 1) % SPRITES.stand.length;
216
+ this.element.style.backgroundImage = `url(${SPRITES.stand[this.currentFrame]})`;
217
  }
218
+ else if (this.currentAnimation === 'midAttack') {
219
+ this.animationFrame = (this.animationFrame + 1) % SPRITES.midAttack.length;
220
+ this.element.style.backgroundImage = `url(${SPRITES.midAttack[this.animationFrame]})`;
221
+ }
222
+ this.lastAnimationUpdate = timestamp;
223
+ }
224
+ }
225
+
226
+ move(direction) {
227
+ this.vel.x = direction * SETTINGS.MOVE_SPEED;
228
+ this.direction = direction > 0 ? 'right' : 'left';
229
+ this.isMoving = true;
230
+ if (direction < 0) {
231
+ this.element.classList.add('facing-left');
232
+ } else {
233
+ this.element.classList.remove('facing-left');
234
+ }
235
+ }
236
 
237
+ stop() {
238
+ this.vel.x = 0;
239
+ this.isMoving = false;
240
+ }
241
+
242
+ updatePosition() {
243
+ // Update position based on velocity
244
+ this.pos.x += this.vel.x;
245
+ this.pos.x = Math.max(0, Math.min(755, this.pos.x));
246
+
247
+ // Update vertical position if jumping
248
+ if (this.isJumping) {
249
+ this.vel.y += SETTINGS.GRAVITY;
250
+ this.pos.y = Math.max(0, this.pos.y - this.vel.y);
251
+ if (this.pos.y === 0) {
252
+ this.isJumping = false;
253
+ this.vel.y = 0;
254
  }
255
  }
256
 
257
+ // Update DOM element position
258
+ this.element.style.left = `${this.pos.x}px`;
259
+ this.element.style.bottom = `${this.pos.y}px`;
260
+ }
261
+ }
262
+
263
  class Game {
264
  constructor() {
265
  this.lastFrameTime = 0;
 
277
  this.setupControls();
278
  this.startGame();
279
  }
280
+ checkMidAttackHit() {
281
+ // 중단 공격이 성공했을 때만 호출됨
282
+ if (this.player.currentAnimation === 'midAttack') {
283
+ this.player.midAttackHits++;
284
+
285
+ if (this.player.midAttackHits === 2) {
286
+ this.executeCombo(this.player, this.enemy);
287
+ }
288
+ }
289
+ }
290
+ executeCombo(attacker, defender) {
291
+ attacker.isInCombo = true;
292
+
293
+ // 첫번째 콤보 공격 (kmidattack3.png)
294
+ attacker.element.style.backgroundImage = `url(${SPRITES.midAttack[2]})`;
295
+
296
+ // 0.25초 후 두번째 이미지
297
+ setTimeout(() => {
298
+ attacker.element.style.backgroundImage = `url(${SPRITES.midAttack[3]})`;
299
+ if (!defender.isBlocking) {
300
+ defender.health -= SETTINGS.DAMAGE;
301
+ this.updateHealthBars();
302
+ }
303
+ }, 250);
304
+
305
+ // 0.5초 후 마지막 이미지
306
+ setTimeout(() => {
307
+ attacker.element.style.backgroundImage = `url(${SPRITES.midAttack[4]})`;
308
+ if (!defender.isBlocking) {
309
+ defender.health -= SETTINGS.DAMAGE;
310
+ this.updateHealthBars();
311
+ }
312
+
313
+ // 콤보 종료
314
+ setTimeout(() => {
315
+ attacker.isInCombo = false;
316
+ attacker.midAttackHits = 0;
317
+ attacker.currentAnimation = 'stand';
318
+ attacker.element.style.backgroundImage = `url(${SPRITES.stand[0]})`;
319
+ }, 250);
320
+ }, 500);
321
+ }
322
 
323
  setupControls() {
324
  document.addEventListener('keydown', (e) => {
 
353
  });
354
  }
355
 
356
+ startAttack(attacker, defender, type) {
357
+ if (attacker.isInCombo) return; // 콤보 중에는 새 공격 불가
358
+
359
  attacker.isAttacking = true;
360
+
361
+ // 중단 공격일 경우 애니메이션 처리
362
+ if (type === 'mid' && attacker.isPlayer) {
363
+ attacker.currentAnimation = 'midAttack';
364
+ attacker.element.style.backgroundImage = `url(${SPRITES.midAttack[0]})`;
365
+
366
+ setTimeout(() => {
367
+ attacker.element.style.backgroundImage = `url(${SPRITES.midAttack[1]})`;
368
+ }, 100);
369
+ }
370
+
371
  const attackEl = document.createElement('div');
372
  attackEl.className = `attack ${type}Attack`;
373
 
 
377
  attackEl.style.left = `${attacker.pos.x + xOffset}px`;
378
  attackEl.style.bottom = `${yOffset}px`;
379
  document.getElementById('gameArea').appendChild(attackEl);
380
+
381
  setTimeout(() => {
382
  attackEl.remove();
383
  if (!defender.isBlocking) {
384
  defender.health -= SETTINGS.DAMAGE;
385
+ if (type === 'mid' && attacker.isPlayer) {
386
+ this.checkMidAttackHit();
387
+ }
388
  this.updateHealthBars();
389
  this.checkGameOver();
390
  }
391
  }, SETTINGS.ATTACK_DELAY);
392
+
393
  setTimeout(() => {
394
  attacker.isAttacking = false;
395
+ if (!attacker.isInCombo) {
396
+ attacker.currentAnimation = 'stand';
397
+ attacker.element.style.backgroundImage = `url(${SPRITES.stand[0]})`;
398
+ }
399
  }, SETTINGS.ATTACK_DELAY + 100);
400
  }
401
 
 
461
  'right' : 'left';
462
  }
463
 
464
+ update(timestamp) {
465
+ if (timestamp - this.lastFrameTime >= SETTINGS.FRAME_TIME) {
466
+ // Jump handling
467
+ if (this.keys['w'] && !this.player.isJumping) {
468
+ this.player.isJumping = true;
469
+ this.player.vel.y = -SETTINGS.JUMP_FORCE;
470
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
 
472
+ // Movement handling
473
+ if (this.keys['a']) {
474
+ this.player.vel.x = -SETTINGS.MOVE_SPEED;
475
+ this.player.direction = 'left';
476
+ this.player.isMoving = true;
477
+ this.player.element.classList.add('facing-left');
478
+ } else if (this.keys['d']) {
479
+ this.player.vel.x = SETTINGS.MOVE_SPEED;
480
+ this.player.direction = 'right';
481
+ this.player.isMoving = true;
482
+ this.player.element.classList.remove('facing-left');
483
+ } else {
484
+ this.player.isMoving = false;
485
+ this.player.vel.x = 0; // 키를 떼면 속도를 즉시 0으로 설정
486
+ }
487
 
488
+ // Update characters
489
+ [this.player, this.enemy].forEach(char => {
490
+ if (char.isJumping) {
491
+ char.vel.y += SETTINGS.GRAVITY;
492
+ char.pos.y = Math.max(0, char.pos.y - char.vel.y);
493
+ if (char.pos.y === 0) {
494
+ char.isJumping = false;
495
+ char.vel.y = 0;
496
  }
497
  }
498
+
499
+ char.pos.x += char.vel.x;
500
+ char.pos.x = Math.max(0, Math.min(755, char.pos.x));
501
+
502
+ // Remove this line: char.vel.x *= 0.8;
503
+
504
+ char.element.style.left = `${char.pos.x}px`;
505
+ char.element.style.bottom = `${char.pos.y}px`;
506
+ char.updateAnimation(timestamp);
507
+ });
508
+
509
+ this.updateAI();
510
+ this.lastFrameTime = timestamp;
511
+ }
512
+
513
+ if (!this.isGameOver) {
514
+ requestAnimationFrame(this.update.bind(this));
515
+ }
516
+ }
517
  updateHealthBars() {
518
  document.getElementById('playerHealthFill').style.width =
519
  `${(this.player.health / SETTINGS.INITIAL_HEALTH) * 100}%`;