KaiShin1885 commited on
Commit
c39f044
·
verified ·
1 Parent(s): 6d3fee3

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +149 -241
index.html CHANGED
@@ -1,264 +1,172 @@
1
- class Game {
2
- constructor() {
3
- this.lastFrameTime = 0;
4
- this.gameTime = 60;
5
- this.specialCooldown = Date.now() + SETTINGS.SPECIAL_COOLDOWN;
6
- this.counterCooldown = 0;
7
- this.canCounter = false;
8
- this.lastHit = null;
9
- this.isGameOver = false;
10
-
11
- // 이미지 프리로드
12
- this.preloadImages();
13
-
14
- // 캐릭터 초기화
15
- this.player = new Character(document.getElementById('player'), true);
16
- this.enemy = new Character(document.getElementById('enemy'), false);
17
-
18
- this.keys = {};
19
- this.setupControls();
20
- this.startGame();
21
- }
22
-
23
- preloadImages() {
24
- SPRITES.stand.forEach(src => {
25
- const img = new Image();
26
- img.src = src;
27
- });
28
- }
29
-
30
- setupControls() {
31
- document.addEventListener('keydown', (e) => {
32
- if (this.isGameOver) return;
33
- this.keys[e.key.toLowerCase()] = true;
34
-
35
- switch(e.key.toLowerCase()) {
36
- case 'j':
37
- case 'k':
38
- this.startAttack(this.player, this.enemy, e.key === 'k' ? 'high' : 'mid');
39
- break;
40
- case 'q':
41
- if (Date.now() >= this.specialCooldown) {
42
- this.useUltimate(this.player, this.enemy);
43
- }
44
- break;
45
- case 'l':
46
- this.tryCounter();
47
- break;
48
- case 's':
49
- this.player.element.classList.add('crouch');
50
- break;
51
- }
52
- });
53
-
54
- document.addEventListener('keyup', (e) => {
55
- this.keys[e.key.toLowerCase()] = false;
56
- if (e.key.toLowerCase() === 's') {
57
- this.player.element.classList.remove('crouch');
58
- }
59
- });
60
- }
61
-
62
- startAttack(attacker, defender, type) {
63
- attacker.isAttacking = true;
64
-
65
- // 공격 차지 이펙트 생성
66
- const chargeEffect = document.createElement('div');
67
- chargeEffect.className = `attack ${type}Attack`;
68
-
69
- const xOffset = attacker.direction === 'right' ? 45 : -30;
70
- const yOffset = type === 'high' ? 70 : 35;
71
-
72
- chargeEffect.style.left = `${attacker.pos.x + xOffset}px`;
73
- chargeEffect.style.bottom = `${yOffset}px`;
74
- document.getElementById('gameArea').appendChild(chargeEffect);
75
-
76
- setTimeout(() => {
77
- chargeEffect.remove();
78
- this.executeAttack(attacker, defender, type);
79
- }, SETTINGS.ATTACK_DELAY);
80
-
81
- setTimeout(() => {
82
- attacker.isAttacking = false;
83
- }, SETTINGS.ATTACK_DELAY + 100);
84
- }
85
-
86
- executeAttack(attacker, defender, type) {
87
- const attackEl = document.createElement('div');
88
- attackEl.className = `attack ${type}Attack`;
89
-
90
- const xOffset = attacker.direction === 'right' ? 45 : -30;
91
- const yOffset = type === 'high' ? 70 : 35;
92
-
93
- attackEl.style.left = `${attacker.pos.x + xOffset}px`;
94
- attackEl.style.bottom = `${yOffset}px`;
95
- document.getElementById('gameArea').appendChild(attackEl);
96
-
97
- const distance = Math.abs(attacker.pos.x - defender.pos.x);
98
- if (distance < 100) {
99
- this.lastHit = {
100
- time: Date.now(),
101
- target: defender,
102
- damage: SETTINGS.DAMAGE
103
- };
104
- this.canCounter = true;
105
-
106
- setTimeout(() => {
107
- if (this.lastHit && !this.lastHit.countered) {
108
- defender.health -= SETTINGS.DAMAGE;
109
- this.updateHealthBars();
110
- }
111
- this.lastHit = null;
112
- this.canCounter = false;
113
- }, SETTINGS.COUNTER_WINDOW);
114
  }
115
 
116
- setTimeout(() => attackEl.remove(), 100);
117
- }
118
-
119
- useUltimate(attacker, defender) {
120
- const ultimateEl = document.createElement('div');
121
- ultimateEl.className = 'attack ultimate';
122
-
123
- const xOffset = attacker.direction === 'right' ? 45 : -300;
124
- ultimateEl.style.left = `${attacker.pos.x + xOffset}px`;
125
- ultimateEl.style.bottom = '0px';
126
-
127
- document.getElementById('gameArea').appendChild(ultimateEl);
128
-
129
- const distance = Math.abs(attacker.pos.x - defender.pos.x);
130
- if (distance < 300) {
131
- defender.health -= SETTINGS.SPECIAL_DAMAGE;
132
- this.updateHealthBars();
133
  }
134
 
135
- this.specialCooldown = Date.now() + SETTINGS.SPECIAL_COOLDOWN;
136
- setTimeout(() => ultimateEl.remove(), 300);
137
- }
138
-
139
- tryCounter() {
140
- if (Date.now() < this.counterCooldown) return;
141
-
142
- if (this.canCounter && this.lastHit &&
143
- Date.now() - this.lastHit.time <= SETTINGS.COUNTER_WINDOW) {
144
- const counterEffect = document.createElement('div');
145
- counterEffect.className = 'counter-effect';
146
- counterEffect.style.left = `${this.player.pos.x}px`;
147
- counterEffect.style.bottom = '0px';
148
- document.getElementById('gameArea').appendChild(counterEffect);
149
-
150
- setTimeout(() => counterEffect.remove(), 400);
151
- this.lastHit.countered = true;
152
- } else {
153
- this.counterCooldown = Date.now() + SETTINGS.COUNTER_COOLDOWN;
154
  }
155
- }
156
 
157
- updateAI() {
158
- if (Date.now() - this.enemy.lastAction < 300) return;
159
-
160
- const distance = Math.abs(this.player.pos.x - this.enemy.pos.x);
161
- const healthRatio = this.enemy.health / this.player.health;
162
-
163
- if (healthRatio < 0.7 || distance < 80) {
164
- this.enemy.vel.x = SETTINGS.MOVE_SPEED *
165
- (this.player.pos.x > this.enemy.pos.x ? -1 : 1);
166
- } else if (distance > 150) {
167
- this.enemy.vel.x = SETTINGS.MOVE_SPEED *
168
- (this.player.pos.x > this.enemy.pos.x ? 1 : -1);
169
- } else if (Math.random() < 0.05) {
170
- this.startAttack(this.enemy, this.player,
171
- Math.random() > 0.5 ? 'high' : 'mid');
172
  }
173
 
174
- this.enemy.direction = this.player.pos.x > this.enemy.pos.x ?
175
- 'right' : 'left';
176
- this.enemy.lastAction = Date.now();
177
- }
 
 
 
 
178
 
179
- update(timestamp) {
180
- if (timestamp - this.lastFrameTime >= SETTINGS.FRAME_TIME) {
181
- // 플레이어 입력 처리
182
- if (this.keys['w'] && !this.player.isJumping) {
183
- this.player.isJumping = true;
184
- this.player.vel.y = -SETTINGS.JUMP_FORCE;
185
- }
186
- if (this.keys['a']) {
187
- this.player.vel.x = -SETTINGS.MOVE_SPEED;
188
- this.player.direction = 'left';
189
- this.player.isMoving = true;
190
- this.player.element.classList.add('facing-left');
191
- } else if (this.keys['d']) {
192
- this.player.vel.x = SETTINGS.MOVE_SPEED;
193
- this.player.direction = 'right';
194
- this.player.isMoving = true;
195
- this.player.element.classList.remove('facing-left');
196
- } else {
197
- this.player.isMoving = false;
198
- }
199
 
200
- // 물리 업데이트
201
- [this.player, this.enemy].forEach(char => {
202
- // 중력
203
- if (char.isJumping) {
204
- char.vel.y += SETTINGS.GRAVITY;
205
- char.pos.y = Math.max(0, char.pos.y - char.vel.y);
206
- if (char.pos.y === 0) {
207
- char.isJumping = false;
208
- char.vel.y = 0;
209
- }
210
- }
 
 
 
 
211
 
212
- // 위치 업데이트
213
- char.pos.x += char.vel.x;
214
- char.pos.x = Math.max(0, Math.min(755, char.pos.x));
215
- char.vel.x *= 0.8;
216
 
217
- // 시각적 업데이트
218
- char.element.style.left = `${char.pos.x}px`;
219
- char.element.style.bottom = `${char.pos.y}px`;
 
 
 
220
 
221
- // 애니메이션 업데이트
222
- char.updateAnimation(timestamp);
223
- });
 
 
 
224
 
225
- this.updateAI();
226
- this.lastFrameTime = timestamp;
 
 
 
 
227
  }
228
 
229
- if (!this.isGameOver) {
230
- requestAnimationFrame(this.update.bind(this));
 
 
 
 
231
  }
232
- }
233
 
234
- updateHealthBars() {
235
- document.getElementById('playerHealthFill').style.width =
236
- `${(this.player.health/SETTINGS.INITIAL_HEALTH)*100}%`;
237
- document.getElementById('enemyHealthFill').style.width =
238
- `${(this.enemy.health/SETTINGS.INITIAL_HEALTH)*100}%`;
239
- }
 
 
 
 
240
 
241
- startGame() {
242
- this.updateHealthBars();
243
- requestAnimationFrame(this.update.bind(this));
 
 
 
 
 
 
244
 
245
- const timer = setInterval(() => {
246
- this.gameTime--;
247
- document.getElementById('timer').textContent = this.gameTime;
248
 
249
- if (this.gameTime <= 0) {
250
- clearInterval(timer);
251
- this.endGame();
252
- }
253
- }, 1000);
254
- }
255
 
256
- endGame() {
257
- this.isGameOver = true;
258
- const winner = this.player.health > this.enemy.health ? 'Player' : 'Enemy';
259
- alert(`Game Over! ${winner} wins!`);
260
- }
261
- }
262
 
263
- // 게임 시작
264
- new Game();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <style>
5
+ #gameArea {
6
+ width: 800px;
7
+ height: 400px;
8
+ border: 2px solid black;
9
+ position: relative;
10
+ overflow: hidden;
11
+ background: #2a2a2a;
12
+ margin: auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
 
15
+ .character {
16
+ width: 45px;
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;
 
 
 
 
 
 
 
 
24
  }
25
 
26
+ #player {
27
+ left: 100px;
28
+ background-image: url('kstand1.png');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
 
30
 
31
+ #enemy {
32
+ right: 100px;
33
+ background: red;
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
 
36
+ .healthBar {
37
+ width: 200px;
38
+ height: 20px;
39
+ background: #333;
40
+ position: fixed;
41
+ top: 20px;
42
+ border: 2px solid #fff;
43
+ }
44
 
45
+ .healthFill {
46
+ height: 100%;
47
+ width: 100%;
48
+ transition: width 0.1s;
49
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ #playerHealthBar { left: 20px; }
52
+ #enemyHealthBar { right: 20px; }
53
+ #playerHealthFill { background: linear-gradient(90deg, #44f, #88f); }
54
+ #enemyHealthFill { background: linear-gradient(90deg, #f44, #f88); }
55
+
56
+ #timer {
57
+ position: fixed;
58
+ top: 20px;
59
+ left: 50%;
60
+ transform: translateX(-50%);
61
+ font-size: 30px;
62
+ font-weight: bold;
63
+ color: #fff;
64
+ text-shadow: 2px 2px #000;
65
+ }
66
 
67
+ .attack {
68
+ position: absolute;
69
+ pointer-events: none;
70
+ }
71
 
72
+ .midAttack {
73
+ width: 30px;
74
+ height: 30px;
75
+ background: rgba(255,255,0,0.6);
76
+ border: 2px solid #ff0;
77
+ }
78
 
79
+ .highAttack {
80
+ width: 30px;
81
+ height: 30px;
82
+ background: rgba(255,128,0,0.6);
83
+ border: 2px solid #f80;
84
+ }
85
 
86
+ .ultimate {
87
+ width: 300px;
88
+ height: 100px;
89
+ background: rgba(255,0,0,0.6);
90
+ border: 3px solid #f00;
91
+ animation: ultimateEffect 0.3s linear;
92
  }
93
 
94
+ .counter-effect {
95
+ position: absolute;
96
+ width: 45px;
97
+ height: 100px;
98
+ border: 2px solid #0ff;
99
+ animation: counterAnim 0.4s linear;
100
  }
 
101
 
102
+ #instructions {
103
+ position: fixed;
104
+ right: 20px;
105
+ top: 60px;
106
+ padding: 15px;
107
+ background: rgba(0,0,0,0.8);
108
+ color: white;
109
+ border-radius: 5px;
110
+ font-family: monospace;
111
+ }
112
 
113
+ #status {
114
+ position: fixed;
115
+ left: 20px;
116
+ bottom: 20px;
117
+ padding: 10px;
118
+ background: rgba(0,0,0,0.8);
119
+ color: white;
120
+ font-family: monospace;
121
+ }
122
 
123
+ .facing-left {
124
+ transform: scaleX(-1);
125
+ }
126
 
127
+ .crouch {
128
+ height: 50px !important;
129
+ }
 
 
 
130
 
131
+ @keyframes ultimateEffect {
132
+ 0% { opacity: 0.3; }
133
+ 50% { opacity: 0.8; }
134
+ 100% { opacity: 0.3; }
135
+ }
 
136
 
137
+ @keyframes counterAnim {
138
+ 0% { transform: scale(1); opacity: 1; }
139
+ 100% { transform: scale(1.2); opacity: 0; }
140
+ }
141
+ </style>
142
+ </head>
143
+ <body>
144
+ <div id="gameArea">
145
+ <div id="timer">60</div>
146
+ <div id="playerHealthBar" class="healthBar">
147
+ <div id="playerHealthFill" class="healthFill"></div>
148
+ </div>
149
+ <div id="enemyHealthBar" class="healthBar">
150
+ <div id="enemyHealthFill" class="healthFill"></div>
151
+ </div>
152
+ <div id="player" class="character"></div>
153
+ <div id="enemy" class="character"></div>
154
+ <div id="status"></div>
155
+ <div id="instructions">
156
+ Controls:<br><br>
157
+ W - Jump<br>
158
+ A - Left<br>
159
+ D - Right<br>
160
+ S - Crouch<br>
161
+ J - Mid Attack (10dmg)<br>
162
+ K - High Attack (10dmg)<br>
163
+ Q - Ultimate (300dmg)<br>
164
+ L - Counter
165
+ </div>
166
+ </div>
167
+
168
+ <script>
169
+ // 상수 정의를 계속할까요?
170
+ </script>
171
+ </body>
172
+ </html>