cutechicken commited on
Commit
080df83
โ€ข
1 Parent(s): 49edc42

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +238 -118
game.js CHANGED
@@ -41,41 +41,48 @@ class TankPlayer {
41
  }
42
 
43
  async initialize(scene, loader) {
44
- try {
45
- const bodyResult = await loader.loadAsync('/models/abramsBody.glb');
46
- this.body = bodyResult.scene;
47
- this.body.position.copy(this.position);
48
-
49
- const turretResult = await loader.loadAsync('/models/abramsTurret.glb');
50
- this.turret = turretResult.scene;
51
-
52
- this.turretGroup.position.y = 0.2;
53
- this.turretGroup.add(this.turret);
54
- this.body.add(this.turretGroup);
55
-
56
- this.body.traverse((child) => {
57
- if (child.isMesh) {
58
- child.castShadow = true;
59
- child.receiveShadow = true;
60
- }
61
- });
62
-
63
- this.turret.traverse((child) => {
64
- if (child.isMesh) {
65
- child.castShadow = true;
66
- child.receiveShadow = true;
67
- }
68
- });
69
 
70
- scene.add(this.body);
71
- this.isLoaded = true;
72
- this.updateAmmoDisplay(); // ์ถ”๊ฐ€: ์ดˆ๊ธฐ ํƒ„์•ฝ ํ‘œ์‹œ
73
-
74
- } catch (error) {
75
- console.error('Error loading tank models:', error);
76
- this.isLoaded = false;
77
  }
 
 
 
 
 
 
 
 
78
  }
 
79
 
80
  shoot(scene) {
81
  if (this.isReloading || this.ammo <= 0) return null;
@@ -488,73 +495,91 @@ class Game {
488
  }
489
 
490
  async initialize() {
491
- try {
492
- // ์•ˆ๊ฐœ ํšจ๊ณผ ์ œ๊ฑฐ
493
- this.scene.fog = null;
494
- this.scene.background = new THREE.Color(0x87CEEB);
495
-
496
- // ์ฃผ๋ณ€๊ด‘ ์„ค์ • - ๋” ๋ฐ๊ฒŒ
497
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
498
- this.scene.add(ambientLight);
499
-
500
- // ํƒœ์–‘๊ด‘ ์„ค์ •
501
- const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
502
- directionalLight.position.set(100, 100, 50);
503
- directionalLight.castShadow = true;
504
- directionalLight.shadow.mapSize.width = 1024;
505
- directionalLight.shadow.mapSize.height = 1024;
506
- this.scene.add(directionalLight);
507
-
508
- // ์‚ฌ๋ง‰ ์ง€ํ˜• ์ƒ์„ฑ
509
- const groundGeometry = new THREE.PlaneGeometry(MAP_SIZE, MAP_SIZE, 100, 100);
510
- const groundMaterial = new THREE.MeshStandardMaterial({
511
- color: 0xD2B48C,
512
- roughness: 0.8,
513
- metalness: 0.2
514
- });
515
-
516
- const ground = new THREE.Mesh(groundGeometry, groundMaterial);
517
- ground.rotation.x = -Math.PI / 2;
518
- ground.receiveShadow = true;
519
 
520
- // ์ง€ํ˜•์˜ ๊ธฐ๋ณต ์ถ”๊ฐ€
521
- const vertices = ground.geometry.attributes.position.array;
522
- let seed = Math.random() * 100;
523
- for (let i = 0; i < vertices.length; i += 3) {
524
- vertices[i + 2] = Math.sin(vertices[i] * 0.01) * Math.cos(vertices[i + 1] * 0.01) * 20;
525
- }
526
 
527
- ground.geometry.attributes.position.needsUpdate = true;
528
- ground.geometry.computeVertexNormals();
 
 
 
 
 
 
 
 
 
 
529
 
530
- this.scene.add(ground);
531
-
532
- await this.addDesertDecorations();
533
- await this.tank.initialize(this.scene, this.loader);
534
- if (!this.tank.isLoaded) {
535
- throw new Error('Tank loading failed');
536
- }
537
 
538
- const tankPosition = this.tank.getPosition();
539
- this.camera.position.set(
540
- tankPosition.x,
541
- tankPosition.y + 15,
542
- tankPosition.z - 30
543
- );
544
- this.camera.lookAt(tankPosition);
545
-
546
- this.isLoading = false;
547
- document.getElementById('loading').style.display = 'none';
548
-
549
- this.animate();
550
- this.spawnEnemies();
551
- this.startGameTimer();
552
 
553
- } catch (error) {
554
- console.error('Game initialization error:', error);
555
- this.handleLoadingError();
 
 
 
 
556
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  }
 
558
 
559
  // ๋ ˆ์ด๋” ์—…๋ฐ์ดํŠธ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
560
  updateRadar() {
@@ -669,6 +694,90 @@ class Game {
669
  }
670
  }
671
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
672
  setupEventListeners() {
673
  document.addEventListener('keydown', (event) => {
674
  if (this.isLoading || this.isGameOver) return;
@@ -886,37 +995,48 @@ class Game {
886
  }
887
 
888
  getValidEnemySpawnPosition() {
889
- const margin = 20;
890
- let position;
891
- let attempts = 0;
892
- const maxAttempts = 50;
893
-
894
- do {
895
- position = new THREE.Vector3(
896
- (Math.random() - 0.5) * (MAP_SIZE - margin * 2),
897
- ENEMY_GROUND_HEIGHT,
898
- (Math.random() - 0.5) * (MAP_SIZE - margin * 2)
899
- );
 
900
 
901
- const distanceToPlayer = position.distanceTo(this.tank.getPosition());
902
- if (distanceToPlayer < 100) continue;
903
 
904
- let collisionFound = false;
905
- for (const building of this.buildings) {
906
- const buildingBox = new THREE.Box3().setFromObject(building);
907
- if (buildingBox.containsPoint(position)) {
908
- collisionFound = true;
909
- break;
910
- }
911
- }
 
 
 
 
912
 
913
- if (!collisionFound) return position;
914
 
915
- attempts++;
916
- } while (attempts < maxAttempts);
 
 
 
917
 
918
- return null;
919
- }
 
 
 
920
  updateParticles() {
921
  for (let i = this.particles.length - 1; i >= 0; i--) {
922
  const particle = this.particles[i];
 
41
  }
42
 
43
  async initialize(scene, loader) {
44
+ try {
45
+ const bodyResult = await loader.loadAsync('/models/abramsBody.glb');
46
+ this.body = bodyResult.scene;
47
+
48
+ const turretResult = await loader.loadAsync('/models/abramsTurret.glb');
49
+ this.turret = turretResult.scene;
50
+
51
+ this.turretGroup.position.y = 0.2;
52
+ this.turretGroup.add(this.turret);
53
+ this.body.add(this.turretGroup);
54
+
55
+ this.body.traverse((child) => {
56
+ if (child.isMesh) {
57
+ child.castShadow = true;
58
+ child.receiveShadow = true;
59
+ }
60
+ });
61
+
62
+ this.turret.traverse((child) => {
63
+ if (child.isMesh) {
64
+ child.castShadow = true;
65
+ child.receiveShadow = true;
66
+ }
67
+ });
 
68
 
69
+ // ์—ฌ๊ธฐ์„œ ์œ ํšจํ•œ ์Šคํฐ ์œ„์น˜๋ฅผ ์ฐพ์•„ ์ ์šฉ
70
+ if (window.gameInstance) {
71
+ const spawnPos = window.gameInstance.findValidSpawnPosition();
72
+ this.body.position.copy(spawnPos);
73
+ } else {
74
+ this.body.position.copy(this.position);
 
75
  }
76
+
77
+ scene.add(this.body);
78
+ this.isLoaded = true;
79
+ this.updateAmmoDisplay();
80
+
81
+ } catch (error) {
82
+ console.error('Error loading tank models:', error);
83
+ this.isLoaded = false;
84
  }
85
+ }
86
 
87
  shoot(scene) {
88
  if (this.isReloading || this.ammo <= 0) return null;
 
495
  }
496
 
497
  async initialize() {
498
+ try {
499
+ // ์•ˆ๊ฐœ ํšจ๊ณผ ์ œ๊ฑฐ
500
+ this.scene.fog = null;
501
+ this.scene.background = new THREE.Color(0x87CEEB);
502
+
503
+ // ์ฃผ๋ณ€๊ด‘ ์„ค์ • - ๋” ๋ฐ๊ฒŒ
504
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
505
+ this.scene.add(ambientLight);
506
+
507
+ // ํƒœ์–‘๊ด‘ ์„ค์ •
508
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
509
+ directionalLight.position.set(100, 100, 50);
510
+ directionalLight.castShadow = true;
511
+ directionalLight.shadow.mapSize.width = 1024;
512
+ directionalLight.shadow.mapSize.height = 1024;
513
+ this.scene.add(directionalLight);
514
+
515
+ // ์ง€ํ˜• ์ƒ์„ฑ ์ˆ˜์ •
516
+ const groundGeometry = new THREE.PlaneGeometry(MAP_SIZE, MAP_SIZE, 100, 100);
517
+ const groundMaterial = new THREE.MeshStandardMaterial({
518
+ color: 0xD2B48C,
519
+ roughness: 0.8,
520
+ metalness: 0.2
521
+ });
 
 
 
 
522
 
523
+ const ground = new THREE.Mesh(groundGeometry, groundMaterial);
524
+ ground.rotation.x = -Math.PI / 2;
525
+ ground.receiveShadow = true;
 
 
 
526
 
527
+ // ๋” ์™„๋งŒํ•œ ์ง€ํ˜• ์ƒ์„ฑ
528
+ const vertices = ground.geometry.attributes.position.array;
529
+ const heightScale = 10; // ๋†’์ด ์Šค์ผ€์ผ ๊ฐ์†Œ
530
+ const frequency = 0.005; // ์ฃผํŒŒ์ˆ˜ ๊ฐ์†Œ๋กœ ๋” ์™„๋งŒํ•œ ๊ฒฝ์‚ฌ ์ƒ์„ฑ
531
+
532
+ for (let i = 0; i < vertices.length; i += 3) {
533
+ const x = vertices[i];
534
+ const y = vertices[i + 1];
535
+ // Perlin ๋…ธ์ด์ฆˆ์™€ ์œ ์‚ฌํ•œ ํšจ๊ณผ๋ฅผ ๋‚ด๋Š” ์ˆ˜์ •๋œ ์ˆ˜์‹
536
+ vertices[i + 2] =
537
+ (Math.sin(x * frequency) * Math.cos(y * frequency) * heightScale) +
538
+ (Math.sin(x * frequency * 2) * Math.cos(y * frequency * 2) * heightScale * 0.5);
539
 
540
+ // ๋งต ๊ฐ€์žฅ์ž๋ฆฌ๋กœ ๊ฐˆ์ˆ˜๋ก ๋†’์ด๋ฅผ ์ ์ง„์ ์œผ๋กœ ์ค„์ž„
541
+ const distanceFromCenter = Math.sqrt(x * x + y * y) / (MAP_SIZE * 0.5);
542
+ const edgeFactor = Math.max(0, 1 - distanceFromCenter);
543
+ vertices[i + 2] *= edgeFactor;
544
+ }
 
 
545
 
546
+ ground.geometry.attributes.position.needsUpdate = true;
547
+ ground.geometry.computeVertexNormals();
548
+ this.ground = ground; // ์ง€ํ˜• ์ฐธ์กฐ ์ €์žฅ
549
+ this.scene.add(ground);
 
 
 
 
 
 
 
 
 
 
550
 
551
+ // ์‚ฌ๋ง‰ ์žฅ์‹ ์ถ”๊ฐ€
552
+ await this.addDesertDecorations();
553
+
554
+ // ํƒฑํฌ ์ดˆ๊ธฐํ™”
555
+ await this.tank.initialize(this.scene, this.loader);
556
+ if (!this.tank.isLoaded) {
557
+ throw new Error('Tank loading failed');
558
  }
559
+
560
+ // ์นด๋ฉ”๋ผ ์ดˆ๊ธฐ ์œ„์น˜ ์„ค์ •
561
+ const tankPosition = this.tank.getPosition();
562
+ this.camera.position.set(
563
+ tankPosition.x,
564
+ tankPosition.y + 15,
565
+ tankPosition.z - 30
566
+ );
567
+ this.camera.lookAt(tankPosition);
568
+
569
+ // ๋กœ๋”ฉ ์™„๋ฃŒ
570
+ this.isLoading = false;
571
+ document.getElementById('loading').style.display = 'none';
572
+
573
+ // ๊ฒŒ์ž„ ์‹œ์ž‘
574
+ this.animate();
575
+ this.spawnEnemies();
576
+ this.startGameTimer();
577
+
578
+ } catch (error) {
579
+ console.error('Game initialization error:', error);
580
+ this.handleLoadingError();
581
  }
582
+ }
583
 
584
  // ๋ ˆ์ด๋” ์—…๋ฐ์ดํŠธ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
585
  updateRadar() {
 
694
  }
695
  }
696
 
697
+ getHeightAtPosition(x, z) {
698
+ if (!this.ground) return 0;
699
+
700
+ // ์ง€ํ˜•์˜ ์ •์  ๋ฐ์ดํ„ฐ
701
+ const vertices = this.ground.geometry.attributes.position.array;
702
+ const segmentsX = Math.sqrt(vertices.length / 3) - 1;
703
+ const segmentsZ = segmentsX;
704
+
705
+ // ๋งต ์ขŒํ‘œ๋ฅผ ์ง€ํ˜• ๊ฒฉ์ž ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜
706
+ const gridX = ((x + MAP_SIZE / 2) / MAP_SIZE) * segmentsX;
707
+ const gridZ = ((z + MAP_SIZE / 2) / MAP_SIZE) * segmentsZ;
708
+
709
+ // ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๊ฒฉ์ž์  ์ฐพ๊ธฐ
710
+ const x1 = Math.floor(gridX);
711
+ const z1 = Math.floor(gridZ);
712
+ const x2 = Math.min(x1 + 1, segmentsX);
713
+ const z2 = Math.min(z1 + 1, segmentsZ);
714
+
715
+ // ๊ฒฉ์ž์ ๋“ค์˜ ๋†’์ด ๊ฐ€์ ธ์˜ค๊ธฐ
716
+ const getHeight = (x, z) => {
717
+ if (x < 0 || x > segmentsX || z < 0 || z > segmentsZ) return 0;
718
+ const index = (z * (segmentsX + 1) + x) * 3 + 2;
719
+ return vertices[index];
720
+ };
721
+
722
+ const h11 = getHeight(x1, z1);
723
+ const h21 = getHeight(x2, z1);
724
+ const h12 = getHeight(x1, z2);
725
+ const h22 = getHeight(x2, z2);
726
+
727
+ // ๋ณด๊ฐ„์œผ๋กœ ์ •ํ™•ํ•œ ๋†’์ด ๊ณ„์‚ฐ
728
+ const fx = gridX - x1;
729
+ const fz = gridZ - z1;
730
+
731
+ const h1 = h11 * (1 - fx) + h21 * fx;
732
+ const h2 = h12 * (1 - fx) + h22 * fx;
733
+
734
+ return h1 * (1 - fz) + h2 * fz;
735
+ }
736
+
737
+ findValidSpawnPosition() {
738
+ const margin = 50;
739
+ let position;
740
+ let attempts = 0;
741
+ const maxAttempts = 50;
742
+ const maxSlope = 0.3; // ์ตœ๋Œ€ ํ—ˆ์šฉ ๊ฒฝ์‚ฌ
743
+
744
+ while (attempts < maxAttempts) {
745
+ position = new THREE.Vector3(
746
+ (Math.random() - 0.5) * (MAP_SIZE - margin * 2),
747
+ 0,
748
+ (Math.random() - 0.5) * (MAP_SIZE - margin * 2)
749
+ );
750
+
751
+ // ํ˜„์žฌ ์œ„์น˜์˜ ๋†’์ด ๊ฐ€์ ธ์˜ค๊ธฐ
752
+ const height = this.getHeightAtPosition(position.x, position.z);
753
+ position.y = height + TANK_HEIGHT;
754
+
755
+ // ์ฃผ๋ณ€ ์ง€ํ˜•์˜ ๊ฒฝ์‚ฌ ์ฒดํฌ
756
+ const checkPoints = [
757
+ { x: position.x + 2, z: position.z },
758
+ { x: position.x - 2, z: position.z },
759
+ { x: position.x, z: position.z + 2 },
760
+ { x: position.x, z: position.z - 2 }
761
+ ];
762
+
763
+ const slopes = checkPoints.map(point => {
764
+ const pointHeight = this.getHeightAtPosition(point.x, point.z);
765
+ return Math.abs(pointHeight - height) / 2;
766
+ });
767
+
768
+ const maxCurrentSlope = Math.max(...slopes);
769
+
770
+ if (maxCurrentSlope <= maxSlope) {
771
+ return position;
772
+ }
773
+
774
+ attempts++;
775
+ }
776
+
777
+ // ์‹คํŒจ ์‹œ ๊ธฐ๋ณธ ์œ„์น˜ ๋ฐ˜ํ™˜
778
+ return new THREE.Vector3(0, TANK_HEIGHT, 0);
779
+ }
780
+
781
  setupEventListeners() {
782
  document.addEventListener('keydown', (event) => {
783
  if (this.isLoading || this.isGameOver) return;
 
995
  }
996
 
997
  getValidEnemySpawnPosition() {
998
+ const margin = 50;
999
+ let position;
1000
+ let attempts = 0;
1001
+ const maxAttempts = 50;
1002
+ const maxSlope = 0.3;
1003
+
1004
+ do {
1005
+ position = new THREE.Vector3(
1006
+ (Math.random() - 0.5) * (MAP_SIZE - margin * 2),
1007
+ 0,
1008
+ (Math.random() - 0.5) * (MAP_SIZE - margin * 2)
1009
+ );
1010
 
1011
+ const height = this.getHeightAtPosition(position.x, position.z);
1012
+ position.y = height + TANK_HEIGHT;
1013
 
1014
+ // ์ฃผ๋ณ€ ๊ฒฝ์‚ฌ ์ฒดํฌ
1015
+ const checkPoints = [
1016
+ { x: position.x + 2, z: position.z },
1017
+ { x: position.x - 2, z: position.z },
1018
+ { x: position.x, z: position.z + 2 },
1019
+ { x: position.x, z: position.z - 2 }
1020
+ ];
1021
+
1022
+ const slopes = checkPoints.map(point => {
1023
+ const pointHeight = this.getHeightAtPosition(point.x, point.z);
1024
+ return Math.abs(pointHeight - height) / 2;
1025
+ });
1026
 
1027
+ const maxCurrentSlope = Math.max(...slopes);
1028
 
1029
+ // ํ”Œ๋ ˆ์ด์–ด์™€์˜ ๊ฑฐ๋ฆฌ ์ฒดํฌ
1030
+ const distanceToPlayer = position.distanceTo(this.tank.getPosition());
1031
+ if (distanceToPlayer > 100 && maxCurrentSlope <= maxSlope) {
1032
+ return position;
1033
+ }
1034
 
1035
+ attempts++;
1036
+ } while (attempts < maxAttempts);
1037
+
1038
+ return null;
1039
+ }
1040
  updateParticles() {
1041
  for (let i = this.particles.length - 1; i >= 0; i--) {
1042
  const particle = this.particles[i];