cutechicken commited on
Commit
2112778
โ€ข
1 Parent(s): 485200d

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +231 -190
game.js CHANGED
@@ -586,192 +586,94 @@ class Enemy {
586
  }
587
 
588
  async initialize(loader) {
589
- console.log('Starting enemy tank initialization...');
590
- try {
591
- // Load body
592
- console.log('Loading t90Body.glb...');
593
- const bodyResult = await loader.loadAsync('/models/t90Body.glb');
594
- console.log('t90Body.glb loaded successfully');
595
- this.body = bodyResult.scene;
596
-
597
- // Load turret
598
- console.log('Loading t90Turret.glb...');
599
- const turretResult = await loader.loadAsync('/models/t90Turret.glb');
600
- console.log('t90Turret.glb loaded successfully');
601
- this.turret = turretResult.scene;
602
-
603
- console.log('Setting up turret group...');
604
- this.turretGroup.position.y = 0.2;
605
- this.turretGroup.add(this.turret);
606
- this.body.add(this.turretGroup);
607
-
608
- console.log('Applying transforms...');
609
- this.body.position.copy(this.position);
610
- this.body.scale.set(ENEMY_SCALE, ENEMY_SCALE, ENEMY_SCALE);
611
-
612
- // Setup shadows
613
- console.log('Setting up shadows...');
614
- this.body.traverse((child) => {
615
- if (child.isMesh) {
616
- child.castShadow = true;
617
- child.receiveShadow = true;
618
- child.material.shadowSide = THREE.BackSide;
619
- }
620
- });
621
-
622
- this.turret.traverse((child) => {
623
- if (child.isMesh) {
624
- child.castShadow = true;
625
- child.receiveShadow = true;
626
- child.material.shadowSide = THREE.BackSide;
627
- }
628
- });
629
-
630
- console.log('Adding to scene...');
631
- this.scene.add(this.body);
632
- this.isLoaded = true;
633
- console.log('Enemy tank initialization complete!');
634
- } catch (error) {
635
- console.error('Error loading enemy tank model:', error);
636
- console.error('Error details:', {
637
- message: error.message,
638
- stack: error.stack,
639
- name: error.name
640
- });
641
- this.isLoaded = false;
 
642
  }
643
- }
644
-
645
- update(playerPosition) {
646
  if (!this.body || !this.isLoaded) return;
647
 
 
648
  const direction = new THREE.Vector3()
649
  .subVectors(playerPosition, this.body.position)
650
  .normalize();
651
 
 
652
  const distanceToPlayer = this.body.position.distanceTo(playerPosition);
653
- const minDistance = 50;
654
-
655
- // Store previous position
656
- const previousPosition = this.body.position.clone();
657
 
 
658
  if (distanceToPlayer > minDistance) {
659
  const moveVector = direction.multiplyScalar(this.moveSpeed);
660
  const newPosition = this.body.position.clone().add(moveVector);
661
 
662
- // Get terrain height
663
  const heightAtNewPos = window.gameInstance.getHeightAtPosition(
664
  newPosition.x,
665
  newPosition.z
666
  );
667
  newPosition.y = heightAtNewPos + TANK_HEIGHT;
668
 
669
- // Move tank body
670
- const originalPosition = this.body.position.clone();
671
  this.body.position.copy(newPosition);
672
 
673
- // Collision checks
674
- const enemyBox = new THREE.Box3().setFromObject(this.body);
675
- let hasCollision = false;
676
-
677
- // Check collisions with obstacles
678
- for (const obstacle of window.gameInstance.obstacles) {
679
- const obstacleBox = new THREE.Box3().setFromObject(obstacle);
680
- if (enemyBox.intersectsBox(obstacleBox)) {
681
- hasCollision = true;
682
- break;
683
- }
684
- }
685
-
686
- // Check collisions with other enemies
687
- if (!hasCollision) {
688
- for (const otherEnemy of window.gameInstance.enemies) {
689
- if (otherEnemy !== this && otherEnemy.body) {
690
- const otherEnemyBox = new THREE.Box3().setFromObject(otherEnemy.body);
691
- if (enemyBox.intersectsBox(otherEnemyBox)) {
692
- hasCollision = true;
693
- break;
694
- }
695
- }
696
- }
697
- }
698
-
699
- // Check map boundaries
700
- const mapBoundary = MAP_SIZE / 2;
701
- if (Math.abs(newPosition.x) > mapBoundary ||
702
- Math.abs(newPosition.z) > mapBoundary) {
703
- hasCollision = true;
704
- }
705
-
706
- // Handle collision response
707
- if (hasCollision) {
708
- this.body.position.copy(previousPosition);
709
-
710
- // Try alternate paths when collision occurs
711
- const alternateDirections = [
712
- new THREE.Vector3(-direction.z, 0, direction.x), // Left 90 degrees
713
- new THREE.Vector3(direction.z, 0, -direction.x), // Right 90 degrees
714
- new THREE.Vector3(-direction.x, 0, -direction.z) // 180 degrees
715
- ];
716
-
717
- for (const altDirection of alternateDirections) {
718
- const altMoveVector = altDirection.multiplyScalar(this.moveSpeed);
719
- const altNewPosition = previousPosition.clone().add(altMoveVector);
720
-
721
- this.body.position.copy(altNewPosition);
722
- const altEnemyBox = new THREE.Box3().setFromObject(this.body);
723
-
724
- let altHasCollision = false;
725
-
726
- // Check alternate path collisions
727
- for (const obstacle of window.gameInstance.obstacles) {
728
- const obstacleBox = new THREE.Box3().setFromObject(obstacle);
729
- if (altEnemyBox.intersectsBox(obstacleBox)) {
730
- altHasCollision = true;
731
- break;
732
- }
733
- }
734
-
735
- if (!altHasCollision) {
736
- // Use alternate path if no collision
737
- break;
738
- } else {
739
- // Revert to previous position if alternate path also collides
740
- this.body.position.copy(previousPosition);
741
- }
742
- }
743
- }
744
-
745
- // Adjust tank orientation based on terrain
746
- const forwardVector = new THREE.Vector3(0, 0, 1).applyQuaternion(this.body.quaternion);
747
- const rightVector = new THREE.Vector3(1, 0, 0).applyQuaternion(this.body.quaternion);
748
-
749
- const frontHeight = window.gameInstance.getHeightAtPosition(
750
- this.body.position.x + forwardVector.x,
751
- this.body.position.z + forwardVector.z
752
- );
753
- const backHeight = window.gameInstance.getHeightAtPosition(
754
- this.body.position.x - forwardVector.x,
755
- this.body.position.z - forwardVector.z
756
- );
757
- const rightHeight = window.gameInstance.getHeightAtPosition(
758
- this.body.position.x + rightVector.x,
759
- this.body.position.z + rightVector.z
760
- );
761
- const leftHeight = window.gameInstance.getHeightAtPosition(
762
- this.body.position.x - rightVector.x,
763
- this.body.position.z - rightVector.z
764
- );
765
-
766
- const pitch = Math.atan2(frontHeight - backHeight, 2);
767
- const roll = Math.atan2(rightHeight - leftHeight, 2);
768
-
769
- // Apply rotation while maintaining current heading
770
- const currentRotation = this.body.rotation.y;
771
- this.body.rotation.set(pitch, currentRotation, roll);
772
  }
773
 
774
- // Update turret rotation to face player
775
  const turretDirection = new THREE.Vector2(
776
  playerPosition.x - this.body.position.x,
777
  playerPosition.z - this.body.position.z
@@ -779,30 +681,16 @@ class Enemy {
779
  const turretAngle = Math.atan2(turretDirection.x, turretDirection.y);
780
  this.turretGroup.rotation.y = turretAngle - this.body.rotation.y;
781
 
782
- // Update bullets
783
- if (this.bullets) {
784
- for (let i = this.bullets.length - 1; i >= 0; i--) {
785
- const bullet = this.bullets[i];
786
- bullet.position.add(bullet.velocity);
787
-
788
- // Check bullet bounds and collisions
789
- if (Math.abs(bullet.position.x) > MAP_SIZE / 2 ||
790
- Math.abs(bullet.position.z) > MAP_SIZE / 2) {
791
- this.scene.remove(bullet);
792
- this.bullets.splice(i, 1);
793
- continue;
794
- }
795
-
796
- // Check bullet collisions with obstacles
797
- const bulletBox = new THREE.Box3().setFromObject(bullet);
798
- for (const obstacle of window.gameInstance.obstacles) {
799
- const obstacleBox = new THREE.Box3().setFromObject(obstacle);
800
- if (bulletBox.intersectsBox(obstacleBox)) {
801
- this.scene.remove(bullet);
802
- this.bullets.splice(i, 1);
803
- break;
804
- }
805
- }
806
  }
807
  }
808
  }
@@ -817,14 +705,14 @@ class Enemy {
817
 
818
  if (currentTime - this.lastAttackTime < attackInterval) return;
819
 
820
- // Create bullet
821
- const bulletGeometry = new THREE.SphereGeometry(this.type === 'tank' ? 0.2 : 0.3);
822
  const bulletMaterial = new THREE.MeshBasicMaterial({
823
  color: this.type === 'tank' ? 0xff0000 : 0xff6600
824
  });
825
  const bullet = new THREE.Mesh(bulletGeometry, bulletMaterial);
826
 
827
- // Get turret world position for bullet spawn
828
  const muzzleOffset = new THREE.Vector3(0, 0.5, 4);
829
  const muzzlePosition = new THREE.Vector3();
830
  const turretWorldQuaternion = new THREE.Quaternion();
@@ -837,6 +725,7 @@ class Enemy {
837
 
838
  bullet.position.copy(muzzlePosition);
839
 
 
840
  const direction = new THREE.Vector3()
841
  .subVectors(playerPosition, muzzlePosition)
842
  .normalize();
@@ -847,6 +736,11 @@ class Enemy {
847
 
848
  bullet.velocity = direction.multiplyScalar(bulletSpeed);
849
 
 
 
 
 
 
850
  this.scene.add(bullet);
851
  this.bullets.push(bullet);
852
  this.lastAttackTime = currentTime;
@@ -866,6 +760,153 @@ class Enemy {
866
  }
867
  }
868
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
869
 
870
  // Particle ํด๋ž˜์Šค
871
  class Particle {
 
586
  }
587
 
588
  async initialize(loader) {
589
+ console.log('Starting enemy tank initialization...');
590
+ try {
591
+ // Load body
592
+ console.log('Loading t90Body.glb...');
593
+ const bodyResult = await loader.loadAsync('/models/t90Body.glb');
594
+ console.log('t90Body.glb loaded successfully');
595
+ this.body = bodyResult.scene;
596
+
597
+ // Load turret
598
+ console.log('Loading t90Turret.glb...');
599
+ const turretResult = await loader.loadAsync('/models/t90Turret.glb');
600
+ console.log('t90Turret.glb loaded successfully');
601
+ this.turret = turretResult.scene;
602
+
603
+ console.log('Setting up turret group...');
604
+ this.turretGroup.position.y = 0.2;
605
+ this.turretGroup.add(this.turret);
606
+ this.body.add(this.turretGroup);
607
+
608
+ console.log('Applying transforms...');
609
+ this.body.position.copy(this.position);
610
+ this.body.scale.set(ENEMY_SCALE, ENEMY_SCALE, ENEMY_SCALE);
611
+
612
+ // Setup shadows
613
+ console.log('Setting up shadows...');
614
+ this.body.traverse((child) => {
615
+ if (child.isMesh) {
616
+ child.castShadow = true;
617
+ child.receiveShadow = true;
618
+ child.material.shadowSide = THREE.BackSide;
619
+ }
620
+ });
621
+
622
+ this.turret.traverse((child) => {
623
+ if (child.isMesh) {
624
+ child.castShadow = true;
625
+ child.receiveShadow = true;
626
+ child.material.shadowSide = THREE.BackSide;
627
+ }
628
+ });
629
+
630
+ console.log('Adding to scene...');
631
+ this.scene.add(this.body);
632
+ this.isLoaded = true;
633
+ console.log('Enemy tank initialization complete!');
634
+ } catch (error) {
635
+ console.error('Error loading enemy tank model:', error);
636
+ console.error('Error details:', {
637
+ message: error.message,
638
+ stack: error.stack,
639
+ name: error.name
640
+ });
641
+ this.isLoaded = false;
642
+ }
643
  }
644
+ update(playerPosition) {
 
 
645
  if (!this.body || !this.isLoaded) return;
646
 
647
+ // ํ”Œ๋ ˆ์ด์–ด ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™ ๋ฒกํ„ฐ ๊ณ„์‚ฐ
648
  const direction = new THREE.Vector3()
649
  .subVectors(playerPosition, this.body.position)
650
  .normalize();
651
 
652
+ // ํ”Œ๋ ˆ์ด์–ด์™€์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
653
  const distanceToPlayer = this.body.position.distanceTo(playerPosition);
654
+ const minDistance = 50; // ์ตœ์†Œ ๊ฑฐ๋ฆฌ ์œ ์ง€
 
 
 
655
 
656
+ // ์ตœ์†Œ ๊ฑฐ๋ฆฌ๋ณด๋‹ค ๋ฉ€๋ฆฌ ์žˆ์„ ๋•Œ๋งŒ ์ด๋™
657
  if (distanceToPlayer > minDistance) {
658
  const moveVector = direction.multiplyScalar(this.moveSpeed);
659
  const newPosition = this.body.position.clone().add(moveVector);
660
 
661
+ // ์ง€ํ˜• ๋†’์ด์— ๋งž์ถฐ ์œ„์น˜ ์กฐ์ •
662
  const heightAtNewPos = window.gameInstance.getHeightAtPosition(
663
  newPosition.x,
664
  newPosition.z
665
  );
666
  newPosition.y = heightAtNewPos + TANK_HEIGHT;
667
 
668
+ // ์ฐจ์ฒด ์ด๋™
 
669
  this.body.position.copy(newPosition);
670
 
671
+ // ์ด๋™ ๋ฐฉํ–ฅ์œผ๋กœ ์ฐจ์ฒด ํšŒ์ „
672
+ const targetRotation = Math.atan2(direction.x, direction.z);
673
+ this.body.rotation.y = targetRotation;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
  }
675
 
676
+ // ํฌํƒ‘ ํšŒ์ „ (ํ•ญ์ƒ ํ”Œ๋ ˆ์ด์–ด๋ฅผ ํ–ฅํ•˜๋„๋ก)
677
  const turretDirection = new THREE.Vector2(
678
  playerPosition.x - this.body.position.x,
679
  playerPosition.z - this.body.position.z
 
681
  const turretAngle = Math.atan2(turretDirection.x, turretDirection.y);
682
  this.turretGroup.rotation.y = turretAngle - this.body.rotation.y;
683
 
684
+ // ์ด์•Œ ์—…๋ฐ์ดํŠธ
685
+ for (let i = this.bullets.length - 1; i >= 0; i--) {
686
+ const bullet = this.bullets[i];
687
+ bullet.position.add(bullet.velocity);
688
+
689
+ // ๋งต ๊ฒฝ๊ณ„ ์ฒดํฌ
690
+ if (Math.abs(bullet.position.x) > MAP_SIZE / 2 ||
691
+ Math.abs(bullet.position.z) > MAP_SIZE / 2) {
692
+ this.scene.remove(bullet);
693
+ this.bullets.splice(i, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
694
  }
695
  }
696
  }
 
705
 
706
  if (currentTime - this.lastAttackTime < attackInterval) return;
707
 
708
+ // ์ด์•Œ ์ƒ์„ฑ
709
+ const bulletGeometry = new THREE.SphereGeometry(0.3);
710
  const bulletMaterial = new THREE.MeshBasicMaterial({
711
  color: this.type === 'tank' ? 0xff0000 : 0xff6600
712
  });
713
  const bullet = new THREE.Mesh(bulletGeometry, bulletMaterial);
714
 
715
+ // ํฌ๊ตฌ ์œ„์น˜ ๊ณ„์‚ฐ
716
  const muzzleOffset = new THREE.Vector3(0, 0.5, 4);
717
  const muzzlePosition = new THREE.Vector3();
718
  const turretWorldQuaternion = new THREE.Quaternion();
 
725
 
726
  bullet.position.copy(muzzlePosition);
727
 
728
+ // ๋ฐœ์‚ฌ ๋ฐฉํ–ฅ ๊ณ„์‚ฐ
729
  const direction = new THREE.Vector3()
730
  .subVectors(playerPosition, muzzlePosition)
731
  .normalize();
 
736
 
737
  bullet.velocity = direction.multiplyScalar(bulletSpeed);
738
 
739
+ // ๋ฐœ์‚ฌ์Œ ํšจ๊ณผ
740
+ const shootSound = new Audio('sounds/enemyfire.ogg');
741
+ shootSound.volume = 0.3;
742
+ shootSound.play();
743
+
744
  this.scene.add(bullet);
745
  this.bullets.push(bullet);
746
  this.lastAttackTime = currentTime;
 
760
  }
761
  }
762
  }
763
+ // ์  ํƒฑํฌ์˜ ๋ฐœ์‚ฌ ์ดํŽ™ํŠธ ์ƒ์„ฑ
764
+ createMuzzleFlash() {
765
+ if (!this.turret) return;
766
+
767
+ const flashGroup = new THREE.Group();
768
+
769
+ // ํ™”์—ผ ํšจ๊ณผ
770
+ const flameGeometry = new THREE.SphereGeometry(0.8);
771
+ const flameMaterial = new THREE.MeshBasicMaterial({
772
+ color: 0xff4500,
773
+ transparent: true,
774
+ opacity: 0.8
775
+ });
776
+ const flame = new THREE.Mesh(flameGeometry, flameMaterial);
777
+ flame.scale.set(1.5, 1.5, 2);
778
+ flashGroup.add(flame);
779
+
780
+ // ์—ฐ๊ธฐ ํšจ๊ณผ
781
+ const smokeGeometry = new THREE.SphereGeometry(0.6);
782
+ const smokeMaterial = new THREE.MeshBasicMaterial({
783
+ color: 0x666666,
784
+ transparent: true,
785
+ opacity: 0.4
786
+ });
787
+
788
+ for (let i = 0; i < 3; i++) {
789
+ const smoke = new THREE.Mesh(smokeGeometry, smokeMaterial);
790
+ smoke.position.set(
791
+ Math.random() * 0.5 - 0.25,
792
+ Math.random() * 0.5 - 0.25,
793
+ -0.5 - Math.random()
794
+ );
795
+ smoke.scale.set(1.2, 1.2, 1.2);
796
+ flashGroup.add(smoke);
797
+ }
798
+
799
+ // ํฌ๊ตฌ ์œ„์น˜ ๊ณ„์‚ฐ
800
+ const muzzleOffset = new THREE.Vector3(0, 0.5, 4);
801
+ const muzzlePosition = new THREE.Vector3();
802
+ const turretWorldQuaternion = new THREE.Quaternion();
803
+
804
+ this.turret.getWorldPosition(muzzlePosition);
805
+ this.turret.getWorldQuaternion(turretWorldQuaternion);
806
+
807
+ muzzleOffset.applyQuaternion(turretWorldQuaternion);
808
+ muzzlePosition.add(muzzleOffset);
809
+
810
+ flashGroup.position.copy(muzzlePosition);
811
+ flashGroup.quaternion.copy(turretWorldQuaternion);
812
+
813
+ this.scene.add(flashGroup);
814
+
815
+ // ์ดํŽ™ํŠธ ์ œ๊ฑฐ
816
+ setTimeout(() => {
817
+ this.scene.remove(flashGroup);
818
+ }, 100);
819
+ }
820
+
821
+ // ํ”ผ๊ฒฉ ํšจ๊ณผ ์ƒ์„ฑ
822
+ createHitEffect(position) {
823
+ const particleCount = 10;
824
+ const particles = [];
825
+
826
+ for (let i = 0; i < particleCount; i++) {
827
+ const geometry = new THREE.SphereGeometry(0.1);
828
+ const material = new THREE.MeshBasicMaterial({
829
+ color: 0xff6600,
830
+ transparent: true,
831
+ opacity: 1
832
+ });
833
+ const particle = new THREE.Mesh(geometry, material);
834
+
835
+ particle.position.copy(position);
836
+
837
+ const speed = Math.random() * 0.2 + 0.1;
838
+ const angle = Math.random() * Math.PI * 2;
839
+ const elevation = Math.random() * Math.PI - Math.PI / 2;
840
+
841
+ particle.velocity = new THREE.Vector3(
842
+ Math.cos(angle) * Math.cos(elevation) * speed,
843
+ Math.sin(elevation) * speed,
844
+ Math.sin(angle) * Math.cos(elevation) * speed
845
+ );
846
+
847
+ particle.gravity = -0.01;
848
+ particle.life = Math.random() * 20 + 20;
849
+ particle.fadeRate = 1 / particle.life;
850
+
851
+ this.scene.add(particle);
852
+ particles.push(particle);
853
+ }
854
+
855
+ // ํŒŒํ‹ฐํด ์—…๋ฐ์ดํŠธ ๋ฐ ์ œ๊ฑฐ
856
+ const updateParticles = () => {
857
+ for (let i = particles.length - 1; i >= 0; i--) {
858
+ const particle = particles[i];
859
+ particle.velocity.y += particle.gravity;
860
+ particle.position.add(particle.velocity);
861
+ particle.material.opacity -= particle.fadeRate;
862
+
863
+ if (particle.material.opacity <= 0) {
864
+ this.scene.remove(particle);
865
+ particles.splice(i, 1);
866
+ }
867
+ }
868
+
869
+ if (particles.length > 0) {
870
+ requestAnimationFrame(updateParticles);
871
+ }
872
+ };
873
+
874
+ updateParticles();
875
+ }
876
+
877
+ // ์  ํƒฑํฌ AI ์—…๋ฐ์ดํŠธ
878
+ updateAI(playerPosition, obstacles) {
879
+ if (!this.isLoaded || !this.body) return;
880
+
881
+ // ์žฅ์• ๋ฌผ ํšŒํ”ผ ๋กœ์ง
882
+ const avoidanceForce = new THREE.Vector3();
883
+ const avoidanceRadius = 20;
884
+
885
+ obstacles.forEach(obstacle => {
886
+ if (obstacle.userData.isCollidable) {
887
+ const toObstacle = new THREE.Vector3()
888
+ .subVectors(obstacle.position, this.body.position);
889
+ const distance = toObstacle.length();
890
+
891
+ if (distance < avoidanceRadius) {
892
+ avoidanceForce.add(
893
+ toObstacle.normalize().multiplyScalar(-1 * (avoidanceRadius - distance))
894
+ );
895
+ }
896
+ }
897
+ });
898
+
899
+ // ์ตœ์ข… ์ด๋™ ๋ฐฉํ–ฅ ๊ณ„์‚ฐ
900
+ const targetDirection = new THREE.Vector3()
901
+ .subVectors(playerPosition, this.body.position)
902
+ .normalize();
903
+
904
+ targetDirection.add(avoidanceForce.multiplyScalar(0.5));
905
+ targetDirection.normalize();
906
+
907
+ return targetDirection;
908
+ }
909
+ }
910
 
911
  // Particle ํด๋ž˜์Šค
912
  class Particle {