cutechicken commited on
Commit
6fdf7cb
Β·
verified Β·
1 Parent(s): 10ec5d5

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +94 -22
game.js CHANGED
@@ -12,7 +12,7 @@ const GAME_CONSTANTS = {
12
  MAX_ALTITUDE: 15000,
13
  MIN_ALTITUDE: 0,
14
  MAX_SPEED: 800,
15
- STALL_SPEED: 120,
16
  GRAVITY: 9.8,
17
  MOUSE_SENSITIVITY: 0.001,
18
  MAX_G_FORCE: 12.0,
@@ -29,14 +29,13 @@ class Fighter {
29
 
30
  // 물리 속성
31
  this.position = new THREE.Vector3(0, 2000, 0);
32
- this.velocity = new THREE.Vector3(0, 0, 150);
33
  this.acceleration = new THREE.Vector3(0, 0, 0);
34
  this.rotation = new THREE.Euler(0, 0, 0);
35
 
36
  // λΉ„ν–‰ μ œμ–΄
37
- this.baseSpeed = 150;
38
- this.throttle = 0.5;
39
- this.speed = 150;
40
  this.altitude = 2000;
41
  this.gForce = 1.0;
42
  this.health = 100;
@@ -81,7 +80,8 @@ class Fighter {
81
  altitude: null,
82
  pullup: null,
83
  overg: null,
84
- stall: null
 
85
  };
86
  this.initializeWarningAudios();
87
  }
@@ -100,8 +100,14 @@ class Fighter {
100
  this.warningAudios.stall = new Audio('sounds/alert.ogg');
101
  this.warningAudios.stall.volume = 0.75;
102
 
 
 
 
 
 
 
103
  Object.keys(this.warningAudios).forEach(key => {
104
- if (this.warningAudios[key]) {
105
  this.warningAudios[key].addEventListener('ended', () => {
106
  this.updateWarningAudios();
107
  });
@@ -112,6 +118,15 @@ class Fighter {
112
  }
113
  }
114
 
 
 
 
 
 
 
 
 
 
115
  updateWarningAudios() {
116
  let currentWarning = null;
117
 
@@ -128,8 +143,9 @@ class Fighter {
128
  currentWarning = 'stall';
129
  }
130
 
 
131
  Object.keys(this.warningAudios).forEach(key => {
132
- if (key !== currentWarning && this.warningAudios[key] && !this.warningAudios[key].paused) {
133
  this.warningAudios[key].pause();
134
  this.warningAudios[key].currentTime = 0;
135
  }
@@ -143,6 +159,7 @@ class Fighter {
143
  }
144
 
145
  stopAllWarningAudios() {
 
146
  Object.values(this.warningAudios).forEach(audio => {
147
  if (audio && !audio.paused) {
148
  audio.pause();
@@ -215,24 +232,30 @@ class Fighter {
215
  updateMouseInput(deltaX, deltaY) {
216
  const sensitivity = GAME_CONSTANTS.MOUSE_SENSITIVITY * 2.0;
217
 
 
218
  this.targetRoll += deltaX * sensitivity;
 
 
219
  this.targetPitch -= deltaY * sensitivity;
220
 
221
- const maxPitchAngle = Math.PI / 3;
222
- const maxRollAngle = Math.PI;
 
223
 
224
  this.targetPitch = Math.max(-maxPitchAngle, Math.min(maxPitchAngle, this.targetPitch));
225
  this.targetRoll = Math.max(-maxRollAngle, Math.min(maxRollAngle, this.targetRoll));
226
  }
227
 
228
  updateControls(keys, deltaTime) {
 
229
  if (keys.w) {
230
- this.throttle = Math.min(1.0, this.throttle + deltaTime * 0.8);
231
  }
232
  if (keys.s) {
233
- this.throttle = Math.max(0.1, this.throttle - deltaTime * 0.8);
234
  }
235
 
 
236
  if (keys.a) {
237
  this.targetYaw -= deltaTime * 0.8;
238
  }
@@ -244,48 +267,81 @@ class Fighter {
244
  updatePhysics(deltaTime) {
245
  if (!this.mesh) return;
246
 
 
247
  const rotationSpeed = deltaTime * 3.0;
248
  this.rotation.x = THREE.MathUtils.lerp(this.rotation.x, this.targetPitch, rotationSpeed);
249
  this.rotation.z = THREE.MathUtils.lerp(this.rotation.z, this.targetRoll, rotationSpeed);
250
 
 
251
  let bankTurnRate = 0;
252
  if (Math.abs(this.rotation.z) > 0.1) {
253
  const bankAngle = this.rotation.z;
254
- bankTurnRate = Math.sin(bankAngle) * deltaTime * 0.7;
 
255
  this.targetYaw += bankTurnRate;
256
  }
257
 
 
258
  this.rotation.y = THREE.MathUtils.lerp(this.rotation.y, this.targetYaw, rotationSpeed);
259
 
260
- const minSpeed = 100;
261
- const maxSpeed = 300;
 
262
  let targetSpeed = minSpeed + (maxSpeed - minSpeed) * this.throttle;
263
 
264
- const pitchAngle = Math.abs(this.rotation.x);
265
- if (pitchAngle > Math.PI / 6) {
266
- const stallFactor = Math.max(0.3, 1 - (pitchAngle - Math.PI / 6) * 2);
267
- targetSpeed *= stallFactor;
 
 
 
 
268
  }
269
 
270
- this.speed = THREE.MathUtils.lerp(this.speed, targetSpeed, deltaTime * 2);
 
271
 
272
- this.stallWarning = this.speed < GAME_CONSTANTS.STALL_SPEED;
 
 
273
 
 
 
 
 
 
 
 
 
 
 
274
  const noseDirection = new THREE.Vector3(0, 0, 1);
275
  noseDirection.applyEuler(this.rotation);
276
  this.velocity = noseDirection.multiplyScalar(this.speed);
277
 
278
- const gravityEffect = GAME_CONSTANTS.GRAVITY * deltaTime * 0.1;
 
279
  this.velocity.y -= gravityEffect;
280
 
 
 
 
 
 
 
 
 
281
  this.position.add(this.velocity.clone().multiplyScalar(deltaTime));
282
 
 
283
  if (this.position.y <= GAME_CONSTANTS.MIN_ALTITUDE) {
284
  this.position.y = GAME_CONSTANTS.MIN_ALTITUDE;
285
  this.health = 0;
286
  return;
287
  }
288
 
 
289
  if (this.position.y > GAME_CONSTANTS.MAX_ALTITUDE) {
290
  this.position.y = GAME_CONSTANTS.MAX_ALTITUDE;
291
  this.altitudeWarning = true;
@@ -294,32 +350,44 @@ class Fighter {
294
  this.altitudeWarning = false;
295
  }
296
 
 
297
  const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
298
  if (this.position.x > mapLimit) this.position.x = -mapLimit;
299
  if (this.position.x < -mapLimit) this.position.x = mapLimit;
300
  if (this.position.z > mapLimit) this.position.z = -mapLimit;
301
  if (this.position.z < -mapLimit) this.position.z = mapLimit;
302
 
 
303
  this.mesh.position.copy(this.position);
304
  this.mesh.rotation.x = this.rotation.x;
305
  this.mesh.rotation.y = this.rotation.y + 3 * Math.PI / 2;
306
  this.mesh.rotation.z = this.rotation.z;
307
 
 
308
  this.warningBlinkTimer += deltaTime;
309
  if (this.warningBlinkTimer >= 1.0) {
310
  this.warningBlinkTimer = 0;
311
  this.warningBlinkState = !this.warningBlinkState;
312
  }
313
 
 
314
  this.altitude = this.position.y;
315
 
 
316
  const turnRate = Math.abs(bankTurnRate) * 100;
317
  const pitchRate = Math.abs(this.rotation.x - this.targetPitch) * 10;
318
  this.gForce = 1.0 + turnRate + pitchRate + (Math.abs(this.rotation.z) * 3);
319
 
 
320
  this.overG = this.gForce > this.maxGForce;
321
 
 
322
  this.updateWarningAudios();
 
 
 
 
 
323
  }
324
 
325
  shoot(scene) {
@@ -821,6 +889,9 @@ class Game {
821
  this.isStarted = true;
822
  this.startGameTimer();
823
 
 
 
 
824
  console.log('κ²Œμž„ μ‹œμž‘!');
825
  }
826
 
@@ -936,6 +1007,7 @@ class Game {
936
 
937
  if (this.fighter.stallWarning) {
938
  warningText += 'STALL WARNING\n';
 
939
  }
940
 
941
  if (this.fighter.overG) {
 
12
  MAX_ALTITUDE: 15000,
13
  MIN_ALTITUDE: 0,
14
  MAX_SPEED: 800,
15
+ STALL_SPEED: 300, // 300kt μ΄ν•˜μ—μ„œ μŠ€ν†¨ μœ„ν—˜
16
  GRAVITY: 9.8,
17
  MOUSE_SENSITIVITY: 0.001,
18
  MAX_G_FORCE: 12.0,
 
29
 
30
  // 물리 속성
31
  this.position = new THREE.Vector3(0, 2000, 0);
32
+ this.velocity = new THREE.Vector3(0, 0, 350); // 초기 속도 350kt
33
  this.acceleration = new THREE.Vector3(0, 0, 0);
34
  this.rotation = new THREE.Euler(0, 0, 0);
35
 
36
  // λΉ„ν–‰ μ œμ–΄
37
+ this.throttle = 0.6; // 초기 μŠ€λ‘œν‹€ 60%
38
+ this.speed = 350; // 초기 속도 350kt
 
39
  this.altitude = 2000;
40
  this.gForce = 1.0;
41
  this.health = 100;
 
80
  altitude: null,
81
  pullup: null,
82
  overg: null,
83
+ stall: null,
84
+ normal: null // μ—”μ§„ μ†Œλ¦¬ μΆ”κ°€
85
  };
86
  this.initializeWarningAudios();
87
  }
 
100
  this.warningAudios.stall = new Audio('sounds/alert.ogg');
101
  this.warningAudios.stall.volume = 0.75;
102
 
103
+ // μ—”μ§„ μ†Œλ¦¬ μ„€μ •
104
+ this.warningAudios.normal = new Audio('sounds/normal.ogg');
105
+ this.warningAudios.normal.volume = 0.5;
106
+ this.warningAudios.normal.loop = true; // μ—”μ§„ μ†Œλ¦¬λŠ” 계속 반볡
107
+
108
+ // κ²½κ³ μŒμ—λ§Œ ended 이벀트 λ¦¬μŠ€λ„ˆ μΆ”κ°€ (μ—”μ§„ μ†Œλ¦¬ μ œμ™Έ)
109
  Object.keys(this.warningAudios).forEach(key => {
110
+ if (key !== 'normal' && this.warningAudios[key]) {
111
  this.warningAudios[key].addEventListener('ended', () => {
112
  this.updateWarningAudios();
113
  });
 
118
  }
119
  }
120
 
121
+ startEngineSound() {
122
+ // μ—”μ§„ μ†Œλ¦¬ μ‹œμž‘
123
+ if (this.warningAudios.normal) {
124
+ this.warningAudios.normal.play().catch(e => {
125
+ console.log('Engine sound failed to start:', e);
126
+ });
127
+ }
128
+ }
129
+
130
  updateWarningAudios() {
131
  let currentWarning = null;
132
 
 
143
  currentWarning = 'stall';
144
  }
145
 
146
+ // 경고음만 관리 (μ—”μ§„ μ†Œλ¦¬λŠ” μ œμ™Έ)
147
  Object.keys(this.warningAudios).forEach(key => {
148
+ if (key !== 'normal' && key !== currentWarning && this.warningAudios[key] && !this.warningAudios[key].paused) {
149
  this.warningAudios[key].pause();
150
  this.warningAudios[key].currentTime = 0;
151
  }
 
159
  }
160
 
161
  stopAllWarningAudios() {
162
+ // λͺ¨λ“  μ˜€λ””μ˜€ μ •μ§€ (μ—”μ§„ μ†Œλ¦¬ 포함)
163
  Object.values(this.warningAudios).forEach(audio => {
164
  if (audio && !audio.paused) {
165
  audio.pause();
 
232
  updateMouseInput(deltaX, deltaY) {
233
  const sensitivity = GAME_CONSTANTS.MOUSE_SENSITIVITY * 2.0;
234
 
235
+ // 마우슀 XμΆ•: 순수 λ‘€(λ‚ κ°œ 기울이기)만 μ‘°μ •
236
  this.targetRoll += deltaX * sensitivity;
237
+
238
+ // 마우슀 YμΆ•: ν”ΌμΉ˜(기수 μƒν•˜)
239
  this.targetPitch -= deltaY * sensitivity;
240
 
241
+ // 각도 μ œν•œ
242
+ const maxPitchAngle = Math.PI / 3; // 60도
243
+ const maxRollAngle = Math.PI; // 180도
244
 
245
  this.targetPitch = Math.max(-maxPitchAngle, Math.min(maxPitchAngle, this.targetPitch));
246
  this.targetRoll = Math.max(-maxRollAngle, Math.min(maxRollAngle, this.targetRoll));
247
  }
248
 
249
  updateControls(keys, deltaTime) {
250
+ // W/S: μŠ€λ‘œν‹€λ§Œ μ œμ–΄ (가속/감속)
251
  if (keys.w) {
252
+ this.throttle = Math.min(1.0, this.throttle + deltaTime * 0.5); // 천천히 가속
253
  }
254
  if (keys.s) {
255
+ this.throttle = Math.max(0.1, this.throttle - deltaTime * 0.5); // 천천히 감속
256
  }
257
 
258
+ // A/D: λŸ¬λ” μ œμ–΄ (μš” νšŒμ „)
259
  if (keys.a) {
260
  this.targetYaw -= deltaTime * 0.8;
261
  }
 
267
  updatePhysics(deltaTime) {
268
  if (!this.mesh) return;
269
 
270
+ // λΆ€λ“œλŸ¬μš΄ νšŒμ „ 보간
271
  const rotationSpeed = deltaTime * 3.0;
272
  this.rotation.x = THREE.MathUtils.lerp(this.rotation.x, this.targetPitch, rotationSpeed);
273
  this.rotation.z = THREE.MathUtils.lerp(this.rotation.z, this.targetRoll, rotationSpeed);
274
 
275
+ // ν˜„μ‹€μ μΈ λΉ„ν–‰ 물리: 둀에 λ”°λ₯Έ μžμ—°μŠ€λŸ¬μš΄ μ„ νšŒ
276
  let bankTurnRate = 0;
277
  if (Math.abs(this.rotation.z) > 0.1) {
278
  const bankAngle = this.rotation.z;
279
+ // λ‚ κ°œκ°€ κΈ°μšΈμ–΄μ§ˆ λ•Œλ§Œ μ„ νšŒ (ν˜„μ‹€μ μΈ λΉ„ν–‰)
280
+ bankTurnRate = Math.sin(bankAngle) * deltaTime * 0.5; // μ„ νšŒμœ¨ κ°μ†Œ
281
  this.targetYaw += bankTurnRate;
282
  }
283
 
284
+ // μš” νšŒμ „ 적용
285
  this.rotation.y = THREE.MathUtils.lerp(this.rotation.y, this.targetYaw, rotationSpeed);
286
 
287
+ // ν˜„μ‹€μ μΈ 속도 계산
288
+ const minSpeed = 150; // μ΅œμ†Œ 속도 150kt
289
+ const maxSpeed = 600; // μ΅œλŒ€ 속도 600kt
290
  let targetSpeed = minSpeed + (maxSpeed - minSpeed) * this.throttle;
291
 
292
+ // ν”ΌμΉ˜ 각도에 λ”°λ₯Έ 속도 λ³€ν™” (μƒμŠΉμ‹œ 감속, ν•˜κ°•μ‹œ 가속)
293
+ const pitchAngle = this.rotation.x;
294
+ if (pitchAngle < -0.1) { // κΈ°μˆ˜κ°€ μœ„λ‘œ (μƒμŠΉ)
295
+ const climbFactor = Math.abs(pitchAngle) / (Math.PI / 3);
296
+ targetSpeed *= (1 - climbFactor * 0.3); // μ΅œλŒ€ 30% 감속
297
+ } else if (pitchAngle > 0.1) { // κΈ°μˆ˜κ°€ μ•„λž˜λ‘œ (ν•˜κ°•)
298
+ const diveFactor = pitchAngle / (Math.PI / 3);
299
+ targetSpeed *= (1 + diveFactor * 0.2); // μ΅œλŒ€ 20% 가속
300
  }
301
 
302
+ // 속도 λ³€ν™”λ₯Ό 천천히 적용
303
+ this.speed = THREE.MathUtils.lerp(this.speed, targetSpeed, deltaTime * 0.5);
304
 
305
+ // μŠ€ν†¨ κ²½κ³ : 300kt μ΄ν•˜μ—μ„œ μŠ€ν†¨ μœ„ν—˜
306
+ const speedKnots = this.speed * 1.94384; // m/s to knots
307
+ this.stallWarning = speedKnots < GAME_CONSTANTS.STALL_SPEED;
308
 
309
+ // μŠ€ν†¨ μƒνƒœμ—μ„œμ˜ 물리 효과
310
+ if (this.stallWarning) {
311
+ // κΈ°μˆ˜κ°€ μ•„λž˜λ‘œ 떨어짐
312
+ this.targetPitch += deltaTime * 0.5;
313
+ // μ‘°μ’…μ„± κ°μ†Œ
314
+ this.rotation.x += (Math.random() - 0.5) * deltaTime * 0.2;
315
+ this.rotation.z += (Math.random() - 0.5) * deltaTime * 0.2;
316
+ }
317
+
318
+ // 속도 벑터 계산
319
  const noseDirection = new THREE.Vector3(0, 0, 1);
320
  noseDirection.applyEuler(this.rotation);
321
  this.velocity = noseDirection.multiplyScalar(this.speed);
322
 
323
+ // ν˜„μ‹€μ μΈ 쀑λ ₯ 효과
324
+ const gravityEffect = GAME_CONSTANTS.GRAVITY * deltaTime * 0.15;
325
  this.velocity.y -= gravityEffect;
326
 
327
+ // μ–‘λ ₯ 효과 (속도에 λΉ„λ‘€)
328
+ if (!this.stallWarning) {
329
+ const liftFactor = (this.speed / maxSpeed) * 0.8;
330
+ const lift = gravityEffect * liftFactor;
331
+ this.velocity.y += lift;
332
+ }
333
+
334
+ // μœ„μΉ˜ μ—…λ°μ΄νŠΈ
335
  this.position.add(this.velocity.clone().multiplyScalar(deltaTime));
336
 
337
+ // μ§€λ©΄ 좩돌
338
  if (this.position.y <= GAME_CONSTANTS.MIN_ALTITUDE) {
339
  this.position.y = GAME_CONSTANTS.MIN_ALTITUDE;
340
  this.health = 0;
341
  return;
342
  }
343
 
344
+ // μ΅œλŒ€ 고도 μ œν•œ
345
  if (this.position.y > GAME_CONSTANTS.MAX_ALTITUDE) {
346
  this.position.y = GAME_CONSTANTS.MAX_ALTITUDE;
347
  this.altitudeWarning = true;
 
350
  this.altitudeWarning = false;
351
  }
352
 
353
+ // λ§΅ 경계 처리
354
  const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
355
  if (this.position.x > mapLimit) this.position.x = -mapLimit;
356
  if (this.position.x < -mapLimit) this.position.x = mapLimit;
357
  if (this.position.z > mapLimit) this.position.z = -mapLimit;
358
  if (this.position.z < -mapLimit) this.position.z = mapLimit;
359
 
360
+ // λ©”μ‹œ μœ„μΉ˜ 및 νšŒμ „ μ—…λ°μ΄νŠΈ
361
  this.mesh.position.copy(this.position);
362
  this.mesh.rotation.x = this.rotation.x;
363
  this.mesh.rotation.y = this.rotation.y + 3 * Math.PI / 2;
364
  this.mesh.rotation.z = this.rotation.z;
365
 
366
+ // κ²½κ³  κΉœλΉ‘μž„ 타이머
367
  this.warningBlinkTimer += deltaTime;
368
  if (this.warningBlinkTimer >= 1.0) {
369
  this.warningBlinkTimer = 0;
370
  this.warningBlinkState = !this.warningBlinkState;
371
  }
372
 
373
+ // 고도 및 G-Force 계산
374
  this.altitude = this.position.y;
375
 
376
+ // G-Force 계산
377
  const turnRate = Math.abs(bankTurnRate) * 100;
378
  const pitchRate = Math.abs(this.rotation.x - this.targetPitch) * 10;
379
  this.gForce = 1.0 + turnRate + pitchRate + (Math.abs(this.rotation.z) * 3);
380
 
381
+ // Over-G 체크
382
  this.overG = this.gForce > this.maxGForce;
383
 
384
+ // 경고음 μ—…λ°μ΄νŠΈ (μ—”μ§„ μ†Œλ¦¬λŠ” 계속 μœ μ§€)
385
  this.updateWarningAudios();
386
+
387
+ // μ—”μ§„ μ†Œλ¦¬ λ³Όλ₯¨μ„ μŠ€λ‘œν‹€μ— 연동
388
+ if (this.warningAudios.normal && !this.warningAudios.normal.paused) {
389
+ this.warningAudios.normal.volume = 0.3 + this.throttle * 0.4; // 0.3~0.7
390
+ }
391
  }
392
 
393
  shoot(scene) {
 
889
  this.isStarted = true;
890
  this.startGameTimer();
891
 
892
+ // μ—”μ§„ μ†Œλ¦¬ μ‹œμž‘
893
+ this.fighter.startEngineSound();
894
+
895
  console.log('κ²Œμž„ μ‹œμž‘!');
896
  }
897
 
 
1007
 
1008
  if (this.fighter.stallWarning) {
1009
  warningText += 'STALL WARNING\n';
1010
+ warningText += '<span style="font-size: 16px;">INCREASE THROTTLE</span>\n';
1011
  }
1012
 
1013
  if (this.fighter.overG) {