cutechicken commited on
Commit
8792afc
ยท
verified ยท
1 Parent(s): 9179d15

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +16 -580
game.js CHANGED
@@ -461,230 +461,23 @@ class Fighter {
461
  this.stallEscapeProgress = 0; // ์Šคํ†จ ์ง„์ž… ์‹œ ์ง„ํ–‰๋„ ์ดˆ๊ธฐํ™”
462
  }
463
 
464
- // Uncaught SyntaxError ํ•ด๊ฒฐ์„ ์œ„ํ•ด ํ•จ์ˆ˜ ๋ ๋ถ€๋ถ„ ์ˆ˜์ •
465
- } else if (this.stallWarning && !this.escapeKeyPressed) {
466
- // Fํ‚ค๋ฅผ ๋†“์œผ๋ฉด ์ง„ํ–‰๋„ ๊ฐ์†Œ
467
- this.stallEscapeProgress = Math.max(0, this.stallEscapeProgress - deltaTime * 2);
468
- }
469
-
470
- // ์†๋„ ๋ณ€ํ™” ์ ์šฉ
471
  if (this.stallWarning) {
472
- // ์Šคํ†จ ์ƒํƒœ์—์„œ์˜ ์†๋„ ๋ณ€ํ™”
473
- if (pitchAngle > 0.1) { // ๊ธฐ์ˆ˜๊ฐ€ ์•„๋ž˜๋ฅผ ํ–ฅํ•  ๋•Œ
474
- // ๋‹ค์ด๋น™์œผ๋กœ ์ธํ•œ ์†๋„ ์ฆ๊ฐ€
475
- const diveSpeedGain = Math.min(pitchAngle * 300, 200); // ์ตœ๋Œ€ 200m/s ์ฆ๊ฐ€
476
- this.speed = Math.min(maxSpeed, this.speed + diveSpeedGain * deltaTime);
 
 
 
 
 
 
477
  } else {
478
- // ๊ธฐ์ˆ˜๊ฐ€ ์œ„๋ฅผ ํ–ฅํ•˜๊ฑฐ๋‚˜ ์ˆ˜ํ‰์ผ ๋•Œ๋Š” ์†๋„ ๊ฐ์†Œ
479
- this.speed = Math.max(0, this.speed - deltaTime * 100);
480
  }
481
- } else {
482
- // ์ •์ƒ ๋น„ํ–‰ ์‹œ ์†๋„ ๋ณ€ํ™”
483
- this.speed = THREE.MathUtils.lerp(this.speed, targetSpeed, deltaTime * 0.5);
484
- }
485
-
486
- // ์Šคํ†จ ์ƒํƒœ์—์„œ์˜ ๋ฌผ๋ฆฌ ํšจ๊ณผ
487
- if (this.stallWarning) {
488
- // ๋ฐ”๋‹ฅ์œผ๋กœ ์ถ”๋ฝํ•˜๋ฉฐ ๊ฐ€์†๋„๊ฐ€ ๋น ๋ฅด๊ฒŒ ๋ถ™์Œ
489
- this.targetPitch = Math.min(Math.PI / 2.5, this.targetPitch + deltaTime * 2.5); // ๊ธฐ์ˆ˜๊ฐ€ ๋” ๊ทน๋‹จ์ ์œผ๋กœ ์•„๋ž˜๋กœ (72๋„๊นŒ์ง€)
490
-
491
- // ์กฐ์ข… ๋ถˆ๋Šฅ ์ƒํƒœ - ๋” ์‹ฌํ•œ ํ”๋“ค๋ฆผ
492
- this.rotation.x += (Math.random() - 0.5) * deltaTime * 0.8;
493
- this.rotation.z += (Math.random() - 0.5) * deltaTime * 0.8;
494
-
495
- // ์ค‘๋ ฅ์— ์˜ํ•œ ๊ฐ€์†
496
- const gravityAcceleration = GAME_CONSTANTS.GRAVITY * deltaTime * 3.0; // 3๋ฐฐ ์ค‘๋ ฅ
497
- this.velocity.y -= gravityAcceleration;
498
- }
499
-
500
- // ์†๋„ ๋ฒกํ„ฐ ๊ณ„์‚ฐ
501
- const noseDirection = new THREE.Vector3(0, 0, 1);
502
- noseDirection.applyEuler(this.rotation);
503
-
504
- if (!this.stallWarning) {
505
- // ์ •์ƒ ๋น„ํ–‰ ์‹œ
506
- this.velocity = noseDirection.multiplyScalar(this.speed);
507
- } else {
508
- // ์Šคํ†จ ์‹œ์—๋Š” ์ค‘๋ ฅ์ด ์ฃผ๋„์ ์ด์ง€๋งŒ ๋‹ค์ด๋น™ ์†๋„๋„ ๋ฐ˜์˜
509
- this.velocity.x = noseDirection.x * this.speed * 0.5; // ์ „๋ฐฉ ์†๋„ ์ฆ๊ฐ€
510
- this.velocity.z = noseDirection.z * this.speed * 0.5;
511
- // y ์†๋„๋Š” ์œ„์—์„œ ์ค‘๋ ฅ์œผ๋กœ ์ฒ˜๋ฆฌ๋จ
512
- }
513
-
514
- // ์ •์ƒ ๋น„ํ–‰ ์‹œ ์ค‘๋ ฅ ํšจ๊ณผ
515
- if (!this.stallWarning) {
516
- const gravityEffect = GAME_CONSTANTS.GRAVITY * deltaTime * 0.15;
517
- this.velocity.y -= gravityEffect;
518
-
519
- // ์–‘๋ ฅ ํšจ๊ณผ (์†๋„์— ๋น„๋ก€)
520
- const liftFactor = (this.speed / maxSpeed) * 0.8;
521
- const lift = gravityEffect * liftFactor;
522
- this.velocity.y += lift;
523
- }
524
-
525
- // ์œ„์น˜ ์—…๋ฐ์ดํŠธ
526
- this.position.add(this.velocity.clone().multiplyScalar(deltaTime));
527
-
528
- // ์ง€ํ˜• ์ถฉ๋Œ ๊ฐ์ง€ (Game ํด๋ž˜์Šค์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์ˆ˜์ •)
529
-
530
- // ์ง€๋ฉด ์ถฉ๋Œ
531
- if (this.position.y <= GAME_CONSTANTS.MIN_ALTITUDE) {
532
- this.position.y = GAME_CONSTANTS.MIN_ALTITUDE;
533
- this.health = 0;
534
- return;
535
- }
536
-
537
- // ์ตœ๋Œ€ ๊ณ ๋„ ์ œํ•œ
538
- if (this.position.y > GAME_CONSTANTS.MAX_ALTITUDE) {
539
- this.position.y = GAME_CONSTANTS.MAX_ALTITUDE;
540
- this.altitudeWarning = true;
541
- if (this.velocity.y > 0) this.velocity.y = 0;
542
- } else {
543
- this.altitudeWarning = false;
544
- }
545
-
546
- // ๋งต ๊ฒฝ๊ณ„ ์ฒ˜๋ฆฌ
547
- const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
548
- if (this.position.x > mapLimit) this.position.x = -mapLimit;
549
- if (this.position.x < -mapLimit) this.position.x = mapLimit;
550
- if (this.position.z > mapLimit) this.position.z = -mapLimit;
551
- if (this.position.z < -mapLimit) this.position.z = mapLimit;
552
-
553
- // ๋ฉ”์‹œ ์œ„์น˜ ๋ฐ ํšŒ์ „ ์—…๋ฐ์ดํŠธ
554
- this.mesh.position.copy(this.position);
555
- this.mesh.rotation.x = this.rotation.x;
556
- this.mesh.rotation.y = this.rotation.y + 3 * Math.PI / 2;
557
- this.mesh.rotation.z = this.rotation.z;
558
-
559
- // ๊ฒฝ๊ณ  ๊นœ๋นก์ž„ ํƒ€์ด๋จธ
560
- this.warningBlinkTimer += deltaTime;
561
- if (this.warningBlinkTimer >= 1.0) {
562
- this.warningBlinkTimer = 0;
563
- this.warningBlinkState = !this.warningBlinkState;
564
- }
565
-
566
- // ๊ณ ๋„ ๊ณ„์‚ฐ
567
- this.altitude = this.position.y;
568
-
569
- // ๊ฒฝ๊ณ ์Œ ์—…๋ฐ์ดํŠธ (์—”์ง„ ์†Œ๋ฆฌ๋Š” ๊ณ„์† ์œ ์ง€)
570
- this.updateWarningAudios();
571
-
572
- // ์—”์ง„ ์†Œ๋ฆฌ ๋ณผ๋ฅจ์„ ์Šค๋กœํ‹€์— ์—ฐ๋™
573
- if (this.warningAudios.normal && !this.warningAudios.normal.paused) {
574
- this.warningAudios.normal.volume = 0.3 + this.throttle * 0.4; // 0.3~0.7
575
- }
576
- } Fํ‚ค๋ฅผ ๋†“์œผ๋ฉด ์ง„ํ–‰๋„ ๊ฐ์†Œ
577
- this.stallEscapeProgress = Math.max(0, this.stallEscapeProgress - deltaTime * 2);
578
- }
579
-
580
- // ์†๋„ ๋ณ€ํ™” ์ ์šฉ
581
- if (this.stallWarning) {
582
- // ์Šคํ†จ ์ƒํƒœ์—์„œ์˜ ์†๋„ ๋ณ€ํ™”
583
- if (pitchAngle > 0.1) { // ๊ธฐ์ˆ˜๊ฐ€ ์•„๋ž˜๋ฅผ ํ–ฅํ•  ๋•Œ
584
- // ๋‹ค์ด๋น™์œผ๋กœ ์ธํ•œ ์†๋„ ์ฆ๊ฐ€
585
- const diveSpeedGain = Math.min(pitchAngle * 300, 200); // ์ตœ๋Œ€ 200m/s ์ฆ๊ฐ€
586
- this.speed = Math.min(maxSpeed, this.speed + diveSpeedGain * deltaTime);
587
- } else {
588
- // ๊ธฐ์ˆ˜๊ฐ€ ์œ„๋ฅผ ํ–ฅํ•˜๊ฑฐ๋‚˜ ์ˆ˜ํ‰์ผ ๋•Œ๋Š” ์†๋„ ๊ฐ์†Œ
589
- this.speed = Math.max(0, this.speed - deltaTime * 100);
590
- }
591
- } else {
592
- // ์ •์ƒ ๋น„ํ–‰ ์‹œ ์†๋„ ๋ณ€ํ™”
593
- this.speed = THREE.MathUtils.lerp(this.speed, targetSpeed, deltaTime * 0.5);
594
- }
595
-
596
- // ์Šคํ†จ ์ƒํƒœ์—์„œ์˜ ๋ฌผ๋ฆฌ ํšจ๊ณผ
597
- if (this.stallWarning) {
598
- // ๋ฐ”๋‹ฅ์œผ๋กœ ์ถ”๋ฝํ•˜๋ฉฐ ๊ฐ€์†๋„๊ฐ€ ๋น ๋ฅด๊ฒŒ ๋ถ™์Œ
599
- this.targetPitch = Math.min(Math.PI / 2.5, this.targetPitch + deltaTime * 2.5); // ๊ธฐ์ˆ˜๊ฐ€ ๋” ๊ทน๋‹จ์ ์œผ๋กœ ์•„๋ž˜๋กœ (72๋„๊นŒ์ง€)
600
-
601
- // ์กฐ์ข… ๋ถˆ๋Šฅ ์ƒํƒœ - ๋” ์‹ฌํ•œ ํ”๋“ค๋ฆผ
602
- this.rotation.x += (Math.random() - 0.5) * deltaTime * 0.8;
603
- this.rotation.z += (Math.random() - 0.5) * deltaTime * 0.8;
604
-
605
- // ์ค‘๋ ฅ์— ์˜ํ•œ ๊ฐ€์†
606
- const gravityAcceleration = GAME_CONSTANTS.GRAVITY * deltaTime * 3.0; // 3๋ฐฐ ์ค‘๋ ฅ
607
- this.velocity.y -= gravityAcceleration;
608
- }
609
-
610
- // ์†๋„ ๋ฒกํ„ฐ ๊ณ„์‚ฐ
611
- const noseDirection = new THREE.Vector3(0, 0, 1);
612
- noseDirection.applyEuler(this.rotation);
613
-
614
- if (!this.stallWarning) {
615
- // ์ •์ƒ ๋น„ํ–‰ ์‹œ
616
- this.velocity = noseDirection.multiplyScalar(this.speed);
617
- } else {
618
- // ์Šคํ†จ ์‹œ์—๋Š” ์ค‘๋ ฅ์ด ์ฃผ๋„์ ์ด์ง€๋งŒ ๋‹ค์ด๋น™ ์†๋„๋„ ๋ฐ˜์˜
619
- this.velocity.x = noseDirection.x * this.speed * 0.5; // ์ „๋ฐฉ ์†๋„ ์ฆ๊ฐ€
620
- this.velocity.z = noseDirection.z * this.speed * 0.5;
621
- // y ์†๋„๋Š” ์œ„์—์„œ ์ค‘๋ ฅ์œผ๋กœ ์ฒ˜๋ฆฌ๋จ
622
- }
623
-
624
- // ์ •์ƒ ๋น„ํ–‰ ์‹œ ์ค‘๋ ฅ ํšจ๊ณผ
625
- if (!this.stallWarning) {
626
- const gravityEffect = GAME_CONSTANTS.GRAVITY * deltaTime * 0.15;
627
- this.velocity.y -= gravityEffect;
628
-
629
- // ์–‘๋ ฅ ํšจ๊ณผ (์†๋„์— ๋น„๋ก€)
630
- const liftFactor = (this.speed / maxSpeed) * 0.8;
631
- const lift = gravityEffect * liftFactor;
632
- this.velocity.y += lift;
633
- }
634
-
635
- // ์œ„์น˜ ์—…๋ฐ์ดํŠธ
636
- this.position.add(this.velocity.clone().multiplyScalar(deltaTime));
637
-
638
- // ์ง€ํ˜• ์ถฉ๋Œ ๊ฐ์ง€ (Game ํด๋ž˜์Šค์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์ˆ˜์ •)
639
-
640
- // ์ง€๋ฉด ์ถฉ๋Œ
641
- if (this.position.y <= GAME_CONSTANTS.MIN_ALTITUDE) {
642
- this.position.y = GAME_CONSTANTS.MIN_ALTITUDE;
643
- this.health = 0;
644
- return;
645
- }
646
-
647
- // ์ตœ๋Œ€ ๊ณ ๋„ ์ œํ•œ
648
- if (this.position.y > GAME_CONSTANTS.MAX_ALTITUDE) {
649
- this.position.y = GAME_CONSTANTS.MAX_ALTITUDE;
650
- this.altitudeWarning = true;
651
- if (this.velocity.y > 0) this.velocity.y = 0;
652
- } else {
653
- this.altitudeWarning = false;
654
- }
655
-
656
- // ๋งต ๊ฒฝ๊ณ„ ์ฒ˜๋ฆฌ
657
- const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
658
- if (this.position.x > mapLimit) this.position.x = -mapLimit;
659
- if (this.position.x < -mapLimit) this.position.x = mapLimit;
660
- if (this.position.z > mapLimit) this.position.z = -mapLimit;
661
- if (this.position.z < -mapLimit) this.position.z = mapLimit;
662
-
663
- // ๋ฉ”์‹œ ์œ„์น˜ ๋ฐ ํšŒ์ „ ์—…๋ฐ์ดํŠธ
664
- this.mesh.position.copy(this.position);
665
- this.mesh.rotation.x = this.rotation.x;
666
- this.mesh.rotation.y = this.rotation.y + 3 * Math.PI / 2;
667
- this.mesh.rotation.z = this.rotation.z;
668
-
669
- // ๊ฒฝ๊ณ  ๊นœ๋นก์ž„ ํƒ€์ด๋จธ
670
- this.warningBlinkTimer += deltaTime;
671
- if (this.warningBlinkTimer >= 1.0) {
672
- this.warningBlinkTimer = 0;
673
- this.warningBlinkState = !this.warningBlinkState;
674
- }
675
-
676
- // ๊ณ ๋„ ๊ณ„์‚ฐ
677
- this.altitude = this.position.y;
678
-
679
- // ๊ฒฝ๊ณ ์Œ ์—…๋ฐ์ดํŠธ (์—”์ง„ ์†Œ๋ฆฌ๋Š” ๊ณ„์† ์œ ์ง€)
680
- this.updateWarningAudios();
681
-
682
- // ์—”์ง„ ์†Œ๋ฆฌ ๋ณผ๋ฅจ์„ ์Šค๋กœํ‹€์— ์—ฐ๋™
683
- if (this.warningAudios.normal && !this.warningAudios.normal.paused) {
684
- this.warningAudios.normal.volume = 0.3 + this.throttle * 0.4; // 0.3~0.7
685
- }
686
- } Fํ‚ค๋ฅผ ๋†“์œผ๋ฉด ์ง„ํ–‰๋„ ๊ฐ์†Œ
687
- this.stallEscapeProgress = Math.max(0, this.stallEscapeProgress - deltaTime * 2);
688
  }
689
 
690
  // ์†๋„ ๋ณ€ํ™” ์ ์šฉ
@@ -1440,362 +1233,6 @@ class Game {
1440
  // ๊ฐœ์„ ๋œ ๊ตฌ๋ฆ„ ์ถ”๊ฐ€
1441
  this.addClouds();
1442
  }
1443
-
1444
- createProceduralTerrain() {
1445
- // ์ง€ํ˜• ์ƒ์„ฑ์„ ์œ„ํ•œ ์„ธ๊ทธ๋จผํŠธ
1446
- const segments = 100;
1447
- const terrainGeometry = new THREE.PlaneGeometry(
1448
- GAME_CONSTANTS.MAP_SIZE,
1449
- GAME_CONSTANTS.MAP_SIZE,
1450
- segments,
1451
- segments
1452
- );
1453
-
1454
- // ๋ฒ„ํ…์Šค์— ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€ํ•˜์—ฌ ์–ธ๋• ํšจ๊ณผ
1455
- const vertices = terrainGeometry.attributes.position.array;
1456
- const heightMap = [];
1457
-
1458
- for (let i = 0; i < vertices.length; i += 3) {
1459
- const x = vertices[i];
1460
- const y = vertices[i + 1];
1461
-
1462
- // ๋‹ค์ค‘ ์Šค์ผ€์ผ ๋…ธ์ด์ฆˆ๋กœ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ง€ํ˜• ์ƒ์„ฑ
1463
- let height = 0;
1464
-
1465
- // ํฐ ์Šค์ผ€์ผ ์–ธ๋• (์ฃผ์š” ์ง€ํ˜•)
1466
- height += Math.sin(x * 0.0001) * Math.cos(y * 0.0001) * 300;
1467
-
1468
- // ์ค‘๊ฐ„ ์Šค์ผ€์ผ ์–ธ๋•
1469
- height += Math.sin(x * 0.0003) * Math.cos(y * 0.0003) * 150;
1470
-
1471
- // ์ž‘์€ ์Šค์ผ€์ผ ๋””ํ…Œ์ผ
1472
- height += Math.sin(x * 0.001) * Math.cos(y * 0.001) * 50;
1473
-
1474
- // ๋žœ๋ค ๋…ธ์ด์ฆˆ
1475
- height += (Math.random() - 0.5) * 20;
1476
-
1477
- // ๋งต ๊ฐ€์žฅ์ž๋ฆฌ๋กœ ๊ฐˆ์ˆ˜๋ก ๋†’์ด ๊ฐ์†Œ (๊ฒฝ๊ณ„ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ)
1478
- const distanceFromCenter = Math.sqrt(x * x + y * y);
1479
- const maxDistance = GAME_CONSTANTS.MAP_SIZE * 0.4;
1480
- if (distanceFromCenter > maxDistance) {
1481
- const fade = 1 - (distanceFromCenter - maxDistance) / (GAME_CONSTANTS.MAP_SIZE * 0.1);
1482
- height *= Math.max(0, fade);
1483
- }
1484
-
1485
- vertices[i + 2] = height;
1486
- heightMap.push(height);
1487
- }
1488
-
1489
- terrainGeometry.computeVertexNormals();
1490
-
1491
- // ๋‹จ์ˆœํ•œ ์ดˆ๋ก์ƒ‰ ์ง€ํ˜• ๋จธํ‹ฐ๋ฆฌ์–ผ
1492
- const terrainMaterial = new THREE.MeshLambertMaterial({
1493
- color: 0x8FBC8F,
1494
- flatShading: false
1495
- });
1496
-
1497
- const terrain = new THREE.Mesh(terrainGeometry, terrainMaterial);
1498
- terrain.rotation.x = -Math.PI / 2;
1499
- terrain.receiveShadow = true;
1500
-
1501
- // ์ง€ํ˜• ์ •๋ณด ์ €์žฅ (์ดˆ๋ชฉ ๋ฐฐ์น˜ ๋ฐ ์ถฉ๋Œ ํŒ์ •์šฉ)
1502
- this.terrain = terrain;
1503
- this.terrainGeometry = terrainGeometry;
1504
- this.heightMap = heightMap;
1505
- this.terrainSegments = segments;
1506
-
1507
- this.scene.add(terrain);
1508
- }
1509
-
1510
- addVegetation() {
1511
- if (!this.terrain || !this.heightMap) return;
1512
-
1513
- // ๊ฐ„๋‹จํ•œ ๋‚˜๋ฌด ๋ฐฐ์น˜
1514
- const treeCount = 300;
1515
-
1516
- for (let i = 0; i < treeCount; i++) {
1517
- // ๋žœ๋ค ์œ„์น˜ ์„ ํƒ
1518
- const x = (Math.random() - 0.5) * GAME_CONSTANTS.MAP_SIZE * 0.8;
1519
- const z = (Math.random() - 0.5) * GAME_CONSTANTS.MAP_SIZE * 0.8;
1520
-
1521
- // ํ•ด๋‹น ์œ„์น˜์˜ ์ง€ํ˜• ๋†’์ด ๊ณ„์‚ฐ
1522
- const terrainHeight = this.getTerrainHeightAt(x, z);
1523
-
1524
- // ๋„ˆ๋ฌด ๋†’์€ ๊ณณ์—๋Š” ๋‚˜๋ฌด๋ฅผ ๋ฐฐ์น˜ํ•˜์ง€ ์•Š์Œ
1525
- if (terrainHeight > 200) continue;
1526
-
1527
- // ๊ฐ„๋‹จํ•œ ๋‚˜๋ฌด ์ƒ์„ฑ
1528
- const tree = new THREE.Group();
1529
-
1530
- // ๋ชธํ†ต
1531
- const trunkGeometry = new THREE.CylinderGeometry(1, 1.5, 15, 6);
1532
- const trunkMaterial = new THREE.MeshLambertMaterial({
1533
- color: 0x4a3c28
1534
- });
1535
- const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
1536
- trunk.position.y = 7.5;
1537
- trunk.castShadow = true;
1538
- trunk.receiveShadow = true;
1539
- tree.add(trunk);
1540
-
1541
- // ์žŽ
1542
- const leavesGeometry = new THREE.SphereGeometry(8, 6, 5);
1543
- const leavesMaterial = new THREE.MeshLambertMaterial({
1544
- color: 0x2d5016
1545
- });
1546
- const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
1547
- leaves.position.y = 20;
1548
- leaves.castShadow = true;
1549
- leaves.receiveShadow = true;
1550
- tree.add(leaves);
1551
-
1552
- // ๋‚˜๋ฌด ์œ„์น˜ ๋ฐ ํฌ๊ธฐ ์„ค์ •
1553
- tree.position.set(x, terrainHeight, z);
1554
-
1555
- // ํฌ๊ธฐ ๋ณ€ํ™”
1556
- const scale = 0.8 + Math.random() * 0.4;
1557
- tree.scale.set(scale, scale, scale);
1558
-
1559
- // ๋žœ๋ค ํšŒ์ „
1560
- tree.rotation.y = Math.random() * Math.PI * 2;
1561
-
1562
- this.scene.add(tree);
1563
- }
1564
-
1565
- // ๊ฐ„๋‹จํ•œ ๊ด€๋ชฉ ์ถ”๊ฐ€
1566
- const bushCount = 200;
1567
-
1568
- for (let i = 0; i < bushCount; i++) {
1569
- const x = (Math.random() - 0.5) * GAME_CONSTANTS.MAP_SIZE * 0.8;
1570
- const z = (Math.random() - 0.5) * GAME_CONSTANTS.MAP_SIZE * 0.8;
1571
- const terrainHeight = this.getTerrainHeightAt(x, z);
1572
-
1573
- if (terrainHeight > 150) continue;
1574
-
1575
- const bushGeometry = new THREE.SphereGeometry(3, 5, 4);
1576
- const bushMaterial = new THREE.MeshLambertMaterial({
1577
- color: 0x3a5f3a
1578
- });
1579
- const bush = new THREE.Mesh(bushGeometry, bushMaterial);
1580
-
1581
- bush.position.set(x, terrainHeight + 1.5, z);
1582
- bush.scale.set(
1583
- 1 + Math.random() * 0.5,
1584
- 0.6 + Math.random() * 0.3,
1585
- 1 + Math.random() * 0.5
1586
- );
1587
-
1588
- bush.castShadow = true;
1589
- bush.receiveShadow = true;
1590
-
1591
- this.scene.add(bush);
1592
- }
1593
- }
1594
-
1595
- getTerrainHeightAt(x, z) {
1596
- if (!this.terrainGeometry || !this.heightMap) return 0;
1597
-
1598
- // ์ง€ํ˜• ์ขŒํ‘œ๋ฅผ ์ •๊ทœํ™”
1599
- const normalizedX = (x + GAME_CONSTANTS.MAP_SIZE / 2) / GAME_CONSTANTS.MAP_SIZE;
1600
- const normalizedZ = (z + GAME_CONSTANTS.MAP_SIZE / 2) / GAME_CONSTANTS.MAP_SIZE;
1601
-
1602
- // ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ฒ„ํ…์Šค ์ธ๋ฑ์Šค ์ฐพ๊ธฐ
1603
- const segments = this.terrainSegments || 100; // terrainSegments๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ
1604
- const gridX = Math.floor(normalizedX * (segments - 1));
1605
- const gridZ = Math.floor(normalizedZ * (segments - 1));
1606
-
1607
- if (gridX < 0 || gridX >= segments - 1 || gridZ < 0 || gridZ >= segments - 1) {
1608
- return 0;
1609
- }
1610
-
1611
- const index = gridZ * segments + gridX;
1612
- return this.heightMap[index] || 0;
1613
- }
1614
-
1615
- addAtmosphericEffects() {
1616
- // ๊ฐœ์„ ๋œ ์‚ฐ ์ง€ํ˜• ์‹œ์Šคํ…œ
1617
- this.createMountainRanges();
1618
- }
1619
-
1620
- createMountainRanges() {
1621
- // ์‚ฐ๋งฅ ์ƒ์„ฑ์„ ์œ„ํ•œ ์„ค์ •
1622
- const mountainRanges = [
1623
- {
1624
- distance: GAME_CONSTANTS.MAP_SIZE * 0.6,
1625
- count: 25,
1626
- heightRange: { min: 2000, max: 5000 },
1627
- widthRange: { min: 1500, max: 3000 },
1628
- color: 0x5a6b7a
1629
- },
1630
- {
1631
- distance: GAME_CONSTANTS.MAP_SIZE * 0.8,
1632
- count: 20,
1633
- heightRange: { min: 3000, max: 7000 },
1634
- widthRange: { min: 2000, max: 4000 },
1635
- color: 0x4a5b6a
1636
- },
1637
- {
1638
- distance: GAME_CONSTANTS.MAP_SIZE * 1.0,
1639
- count: 15,
1640
- heightRange: { min: 4000, max: 9000 },
1641
- widthRange: { min: 3000, max: 5000 },
1642
- color: 0x3a4b5a
1643
- }
1644
- ];
1645
-
1646
- mountainRanges.forEach(range => {
1647
- for (let i = 0; i < range.count; i++) {
1648
- const angle = (i / range.count) * Math.PI * 2 + (Math.random() - 0.5) * 0.3;
1649
- const distance = range.distance + (Math.random() - 0.5) * 1000;
1650
-
1651
- // ์‚ฐ ๊ทธ๋ฃน ์ƒ์„ฑ (์—ฌ๋Ÿฌ ๋ด‰์šฐ๋ฆฌ๋กœ ๊ตฌ์„ฑ)
1652
- const mountainGroup = new THREE.Group();
1653
-
1654
- // ๋ฉ”์ธ ๋ด‰์šฐ๋ฆฌ
1655
- const mainPeakHeight = range.heightRange.min + Math.random() * (range.heightRange.max - range.heightRange.min);
1656
- const mainPeakWidth = range.widthRange.min + Math.random() * (range.widthRange.max - range.widthRange.min);
1657
-
1658
- // ๊ฐœ์„ ๋œ ์‚ฐ ํ˜•ํƒœ (ํŒ”๊ฐ๋ฟ” ๋Œ€์‹  ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ํ˜•ํƒœ)
1659
- const mainPeakGeometry = new THREE.ConeGeometry(mainPeakWidth, mainPeakHeight, 12);
1660
- const vertices = mainPeakGeometry.attributes.position.array;
1661
-
1662
- // ์ •์  ๋ณ€ํ˜•์œผ๋กœ ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ์‚ฐ ํ˜•ํƒœ ๋งŒ๋“ค๊ธฐ
1663
- for (let j = 0; j < vertices.length; j += 3) {
1664
- const x = vertices[j];
1665
- const y = vertices[j + 1];
1666
- const z = vertices[j + 2];
1667
-
1668
- // ๋†’์ด์— ๋”ฐ๋ฅธ ๋žœ๋ค ๋ณ€ํ˜•
1669
- const heightFactor = (y + mainPeakHeight * 0.5) / mainPeakHeight;
1670
- const noise = (Math.random() - 0.5) * mainPeakWidth * 0.3 * (1 - heightFactor);
1671
-
1672
- vertices[j] += noise;
1673
- vertices[j + 2] += noise;
1674
- }
1675
-
1676
- mainPeakGeometry.computeVertexNormals();
1677
-
1678
- const mainPeakMaterial = new THREE.MeshLambertMaterial({
1679
- color: range.color,
1680
- flatShading: true,
1681
- fog: true
1682
- });
1683
-
1684
- const mainPeak = new THREE.Mesh(mainPeakGeometry, mainPeakMaterial);
1685
- mountainGroup.add(mainPeak);
1686
-
1687
- // ์ฃผ๋ณ€ ์ž‘์€ ๋ด‰์šฐ๋ฆฌ๋“ค ์ถ”๊ฐ€
1688
- const subPeakCount = 2 + Math.floor(Math.random() * 3);
1689
- for (let j = 0; j < subPeakCount; j++) {
1690
- const subPeakHeight = mainPeakHeight * (0.5 + Math.random() * 0.3);
1691
- const subPeakWidth = mainPeakWidth * (0.6 + Math.random() * 0.3);
1692
-
1693
- const subPeakGeometry = new THREE.ConeGeometry(subPeakWidth, subPeakHeight, 8);
1694
- const subPeak = new THREE.Mesh(subPeakGeometry, mainPeakMaterial);
1695
-
1696
- // ๋ฉ”์ธ ๋ด‰์šฐ๋ฆฌ ์ฃผ๋ณ€์— ๋ฐฐ์น˜
1697
- const offsetAngle = (j / subPeakCount) * Math.PI * 2;
1698
- const offsetDistance = mainPeakWidth * (0.6 + Math.random() * 0.4);
1699
-
1700
- subPeak.position.set(
1701
- Math.cos(offsetAngle) * offsetDistance,
1702
- -mainPeakHeight * 0.3,
1703
- Math.sin(offsetAngle) * offsetDistance
1704
- );
1705
-
1706
- mountainGroup.add(subPeak);
1707
- }
1708
-
1709
- // ์‚ฐ ๊ธฐ๋ฐ˜๋ถ€ (๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ฒฝ์‚ฌ)
1710
- const baseGeometry = new THREE.CylinderGeometry(
1711
- mainPeakWidth * 1.5,
1712
- mainPeakWidth * 2.5,
1713
- mainPeakHeight * 0.3,
1714
- 12
1715
- );
1716
- const baseMaterial = new THREE.MeshLambertMaterial({
1717
- color: new THREE.Color(range.color).multiplyScalar(0.8),
1718
- flatShading: true,
1719
- fog: true
1720
- });
1721
- const base = new THREE.Mesh(baseGeometry, baseMaterial);
1722
- base.position.y = -mainPeakHeight * 0.35;
1723
- mountainGroup.add(base);
1724
-
1725
- // ์‚ฐ ๊ทธ๋ฃน ์œ„์น˜ ์„ค์ •
1726
- mountainGroup.position.set(
1727
- Math.cos(angle) * distance,
1728
- mainPeakHeight * 0.5,
1729
- Math.sin(angle) * distance
1730
- );
1731
-
1732
- // ์•ฝ๊ฐ„์˜ ๋žœ๋ค ํšŒ์ „
1733
- mountainGroup.rotation.y = Math.random() * Math.PI;
1734
-
1735
- // ๊ฑฐ๋ฆฌ๋ณ„ ์ƒ‰์ƒ: ๋ฉ€๋ฆฌ ์žˆ๋Š” ์‚ฐ์ผ์ˆ˜๋ก ๋” ํ‘ธ๋ฅธ์ƒ‰์œผ๋กœ ๋ณด์ด๋„๋ก ์„ค์ •
1736
- mountainGroup.layers.set(0);
1737
-
1738
- this.scene.add(mountainGroup);
1739
- }
1740
- });
1741
-
1742
- // ๊ฐ€์žฅ ๋จผ ๊ฑฐ๋ฆฌ์— ๊ฑฐ๋Œ€ํ•œ ์‚ฐ๋งฅ ์‹ค๋ฃจ์—ฃ ์ถ”๊ฐ€
1743
- this.createDistantMountainSilhouette();
1744
- }
1745
-
1746
- createDistantMountainSilhouette() {
1747
- // ์›๊ฑฐ๋ฆฌ ์‚ฐ๋งฅ ์‹ค๋ฃจ์—ฃ (2D ํ‰๋ฉด)
1748
- const silhouetteDistance = GAME_CONSTANTS.MAP_SIZE * 1.2;
1749
- const segments = 50;
1750
-
1751
- for (let side = 0; side < 4; side++) {
1752
- const curve = new THREE.CatmullRomCurve3([]);
1753
-
1754
- // ์‚ฐ๋งฅ ์‹ค๋ฃจ์—ฃ ๊ณก์„  ์ƒ์„ฑ
1755
- for (let i = 0; i <= segments; i++) {
1756
- const t = i / segments;
1757
- const x = (t - 0.5) * GAME_CONSTANTS.MAP_SIZE;
1758
- const baseHeight = 3000;
1759
- const variation = Math.sin(t * Math.PI * 3) * 2000 +
1760
- Math.sin(t * Math.PI * 7) * 1000 +
1761
- Math.sin(t * Math.PI * 13) * 500;
1762
- const y = baseHeight + variation + Math.random() * 500;
1763
-
1764
- curve.points.push(new THREE.Vector3(x, y, 0));
1765
- }
1766
-
1767
- // ์‹ค๋ฃจ์—ฃ ๋ฉ”์‹œ ์ƒ์„ฑ
1768
- const points = curve.getPoints(100);
1769
- const shape = new THREE.Shape();
1770
-
1771
- shape.moveTo(points[0].x, 0);
1772
- points.forEach(p => shape.lineTo(p.x, p.y));
1773
- shape.lineTo(points[points.length - 1].x, 0);
1774
- shape.lineTo(points[0].x, 0);
1775
-
1776
- const silhouetteGeometry = new THREE.ShapeGeometry(shape);
1777
- const silhouetteMaterial = new THREE.MeshBasicMaterial({
1778
- color: 0x2a3b4a,
1779
- side: THREE.DoubleSide,
1780
- fog: true,
1781
- transparent: true,
1782
- opacity: 0.7
1783
- });
1784
-
1785
- const silhouette = new THREE.Mesh(silhouetteGeometry, silhouetteMaterial);
1786
-
1787
- // ๊ฐ ๋ฉด์— ๋ฐฐ์น˜
1788
- const angle = (side / 4) * Math.PI * 2;
1789
- silhouette.position.set(
1790
- Math.cos(angle) * silhouetteDistance,
1791
- 0,
1792
- Math.sin(angle) * silhouetteDistance
1793
- );
1794
- silhouette.lookAt(0, 0, 0);
1795
-
1796
- this.scene.add(silhouette);
1797
- }
1798
- }
1799
 
1800
  addClouds() {
1801
  // ๋‹ค์ธต ๊ตฌ๋ฆ„ ์‹œ์Šคํ…œ
@@ -2051,11 +1488,11 @@ class Game {
2051
  const rollDegrees = this.fighter.rotation.z * (180 / Math.PI);
2052
  hudElement.style.transform = `translate(-50%, -50%) rotate(${-rollDegrees}deg)`;
2053
 
2054
- // ํ”ผ์น˜ ๋ž˜๋” ์—…๋ฐ์ดํŠธ - ์ˆ˜์ •๋œ ๋ถ€๋ถ„
2055
  const pitchLadder = document.getElementById('pitchLadder');
2056
  if (pitchLadder) {
2057
  const pitchDegrees = this.fighter.rotation.x * (180 / Math.PI);
2058
- // ์ˆ˜์ •: ์Œ์ˆ˜๋ฅผ ๊ณฑํ•ด์„œ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ, 10๋„๋‹น 20ํ”ฝ์…€
2059
  const pitchOffset = -pitchDegrees * 2;
2060
  pitchLadder.style.transform = `translateY(${pitchOffset}px)`;
2061
  }
@@ -2164,7 +1601,6 @@ class Game {
2164
  return { x, y };
2165
  }
2166
 
2167
- // Game ํด๋ž˜์Šค์˜ updateWarnings ๋ฉ”์„œ๋“œ ์ˆ˜์ •
2168
  updateWarnings() {
2169
  // ๊ธฐ์กด ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€ ์ œ๊ฑฐ
2170
  const existingWarnings = document.querySelectorAll('.warning-message');
 
461
  this.stallEscapeProgress = 0; // ์Šคํ†จ ์ง„์ž… ์‹œ ์ง„ํ–‰๋„ ์ดˆ๊ธฐํ™”
462
  }
463
 
464
+ // ์Šคํ†จ ํƒˆ์ถœ ์กฐ๊ฑด
 
 
 
 
 
 
465
  if (this.stallWarning) {
466
+ if (this.escapeKeyPressed) {
467
+ // Fํ‚ค๋ฅผ ๋ˆ„๋ฅด๊ณ  ์žˆ์œผ๋ฉด ์ง„ํ–‰๋„ ์ฆ๊ฐ€
468
+ this.stallEscapeProgress += deltaTime;
469
+
470
+ // 2์ดˆ ์ด์ƒ ๋ˆ„๋ฅด๋ฉด ์Šคํ†จ์—์„œ ํƒˆ์ถœ
471
+ if (this.stallEscapeProgress >= 2.0 && speedKnots >= 350) {
472
+ this.stallWarning = false;
473
+ this.stallEscapeProgress = 0;
474
+ // ์Šคํ†จ์—์„œ ๋ฒ—์–ด๋‚˜๋ฉด ์ž์„ธ๋ฅผ ์•ฝ๊ฐ„ ์•ˆ์ •ํ™”
475
+ this.targetPitch = Math.max(-0.2, Math.min(0.2, this.targetPitch));
476
+ }
477
  } else {
478
+ // Fํ‚ค๋ฅผ ๋†“์œผ๋ฉด ์ง„ํ–‰๋„ ๊ฐ์†Œ
479
+ this.stallEscapeProgress = Math.max(0, this.stallEscapeProgress - deltaTime * 2);
480
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  }
482
 
483
  // ์†๋„ ๋ณ€ํ™” ์ ์šฉ
 
1233
  // ๊ฐœ์„ ๋œ ๊ตฌ๋ฆ„ ์ถ”๊ฐ€
1234
  this.addClouds();
1235
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1236
 
1237
  addClouds() {
1238
  // ๋‹ค์ธต ๊ตฌ๋ฆ„ ์‹œ์Šคํ…œ
 
1488
  const rollDegrees = this.fighter.rotation.z * (180 / Math.PI);
1489
  hudElement.style.transform = `translate(-50%, -50%) rotate(${-rollDegrees}deg)`;
1490
 
1491
+ // ํ”ผ์น˜ ๋ž˜๋” ์—…๋ฐ์ดํŠธ
1492
  const pitchLadder = document.getElementById('pitchLadder');
1493
  if (pitchLadder) {
1494
  const pitchDegrees = this.fighter.rotation.x * (180 / Math.PI);
1495
+ // ์Œ์ˆ˜๋ฅผ ๊ณฑํ•ด์„œ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ, 10๋„๋‹น 20ํ”ฝ์…€
1496
  const pitchOffset = -pitchDegrees * 2;
1497
  pitchLadder.style.transform = `translateY(${pitchOffset}px)`;
1498
  }
 
1601
  return { x, y };
1602
  }
1603
 
 
1604
  updateWarnings() {
1605
  // ๊ธฐ์กด ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€ ์ œ๊ฑฐ
1606
  const existingWarnings = document.querySelectorAll('.warning-message');