cutechicken commited on
Commit
d71ef0b
โ€ข
1 Parent(s): 96cd899

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +66 -299
game.js CHANGED
@@ -553,330 +553,97 @@ class Enemy {
553
  this.isLoaded = false;
554
  this.moveSpeed = type === 'tank' ? ENEMY_MOVE_SPEED : ENEMY_MOVE_SPEED * 0.7;
555
  }
556
- createCollisionBox() {
557
- const dimensions = new THREE.Vector3(4, 2, 7);
558
- const geometry = new THREE.BoxGeometry(dimensions.x, dimensions.y, dimensions.z);
559
- const material = new THREE.MeshBasicMaterial({
560
- color: 0xff0000,
561
- wireframe: true,
562
- visible: false
563
- });
564
-
565
- this.collisionBox = new THREE.Mesh(geometry, material);
566
- this.mesh.add(this.collisionBox);
567
- this.collisionBox.position.set(0, dimensions.y / 2, 0);
568
- }
569
 
570
  async initialize(loader) {
571
- await super.initialize(loader);
572
- this.createCollisionBox();
573
- }
574
- }
575
- createMuzzleFlash() {
576
- if (!this.mesh) return;
577
-
578
- const flashGroup = new THREE.Group();
579
-
580
- // ํ™”์—ผ ํฌ๊ธฐ ์ฆ๊ฐ€ ๋ฐ ์ƒ‰์ƒ ๋ณ€๊ฒฝ
581
- const flameGeometry = new THREE.SphereGeometry(1.0, 8, 8);
582
- const flameMaterial = new THREE.MeshBasicMaterial({
583
- color: 0xffa500, // ๋…ธ๋ž€์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ
584
- transparent: true,
585
- opacity: 0.8
586
- });
587
- const flame = new THREE.Mesh(flameGeometry, flameMaterial);
588
- flame.scale.set(2, 2, 3);
589
- flashGroup.add(flame);
590
-
591
- // ์—ฐ๊ธฐ ํšจ๊ณผ ํฌ๊ธฐ ์ฆ๊ฐ€
592
- const smokeGeometry = new THREE.SphereGeometry(0.8, 8, 8);
593
- const smokeMaterial = new THREE.MeshBasicMaterial({
594
- color: 0x555555,
595
- transparent: true,
596
- opacity: 0.5
597
- });
598
-
599
- for (let i = 0; i < 5; i++) {
600
- const smoke = new THREE.Mesh(smokeGeometry, smokeMaterial);
601
- smoke.position.set(
602
- Math.random() * 1 - 0.5,
603
- Math.random() * 1 - 0.5,
604
- -1 - Math.random()
605
- );
606
- smoke.scale.set(1.5, 1.5, 1.5);
607
- flashGroup.add(smoke);
608
  }
609
 
610
- // ํฌ๊ตฌ ์œ„์น˜ ๊ณ„์‚ฐ
611
- const muzzleOffset = new THREE.Vector3(0, 0.5, 4);
612
- const muzzlePosition = new THREE.Vector3();
613
- const meshWorldQuaternion = new THREE.Quaternion();
614
-
615
- this.mesh.getWorldPosition(muzzlePosition);
616
- this.mesh.getWorldQuaternion(meshWorldQuaternion);
617
-
618
- muzzleOffset.applyQuaternion(meshWorldQuaternion);
619
- muzzlePosition.add(muzzleOffset);
620
-
621
- flashGroup.position.copy(muzzlePosition);
622
- flashGroup.quaternion.copy(meshWorldQuaternion);
623
-
624
- this.scene.add(flashGroup);
625
-
626
- // ์ดํŽ™ํŠธ ์ง€์† ์‹œ๊ฐ„ ์ฆ๊ฐ€
627
- setTimeout(() => {
628
- this.scene.remove(flashGroup);
629
- }, 500);
630
- }
631
-
632
- async initialize(loader) {
633
- try {
634
- const modelPath = this.type === 'tank' ? '/models/t90.glb' : '/models/t90.glb';
635
- const result = await loader.loadAsync(modelPath);
636
- this.mesh = result.scene;
637
- this.mesh.position.copy(this.position);
638
- this.mesh.scale.set(ENEMY_SCALE, ENEMY_SCALE, ENEMY_SCALE);
639
-
640
- this.mesh.traverse((child) => {
641
  if (child.isMesh) {
642
  child.castShadow = true;
643
  child.receiveShadow = true;
644
  }
645
  });
646
-
647
  this.createCollisionBox();
648
  this.scene.add(this.mesh);
649
- this.isLoaded = true;
650
- } catch (error) {
651
- console.error('Error loading enemy model:', error);
652
- this.isLoaded = false;
653
  }
654
- }
 
 
 
 
 
 
 
 
 
 
 
655
 
656
  update(playerPosition) {
657
- if (!this.mesh || !this.isLoaded) return;
 
 
 
658
 
659
- const direction = new THREE.Vector3()
660
- .subVectors(playerPosition, this.mesh.position)
661
- .normalize();
662
-
663
- const distanceToPlayer = this.mesh.position.distanceTo(playerPosition);
664
- const minDistance = 50;
665
-
666
- // ์ด์ „ ์œ„์น˜ ์ €์žฅ
667
- const previousPosition = this.mesh.position.clone();
668
-
669
- if (distanceToPlayer > minDistance) {
670
- const moveVector = direction.multiplyScalar(this.moveSpeed);
671
- const newPosition = this.mesh.position.clone().add(moveVector);
672
-
673
- // ์ง€ํ˜• ๋†’์ด ๊ฐ€์ ธ์˜ค๊ธฐ
674
- const heightAtNewPos = window.gameInstance.getHeightAtPosition(
675
- newPosition.x,
676
- newPosition.z
677
- );
678
- newPosition.y = heightAtNewPos + TANK_HEIGHT;
679
 
680
- // ์ž„์‹œ๋กœ ์œ„์น˜ ์ด๋™ํ•˜์—ฌ ์ถฉ๋Œ ์ฒดํฌ
681
- const originalPosition = this.mesh.position.clone();
682
- this.mesh.position.copy(newPosition);
683
-
684
- // ์žฅ์• ๋ฌผ๊ณผ ์ถฉ๋Œ ์ฒดํฌ
685
- const enemyBox = new THREE.Box3().setFromObject(this.mesh);
686
- let hasCollision = false;
687
-
688
- // ๋ชจ๋“  ์žฅ์• ๋ฌผ์— ๋Œ€ํ•ด ์ถฉ๋Œ ๊ฒ€์‚ฌ
689
- for (const obstacle of window.gameInstance.obstacles) {
690
- const obstacleBox = new THREE.Box3().setFromObject(obstacle);
691
- if (enemyBox.intersectsBox(obstacleBox)) {
692
- hasCollision = true;
693
- break;
694
- }
695
- }
696
-
697
- // ๋‹ค๋ฅธ ์  ํƒฑํฌ์™€์˜ ์ถฉ๋Œ ๊ฒ€์‚ฌ
698
- if (!hasCollision) {
699
- for (const otherEnemy of window.gameInstance.enemies) {
700
- if (otherEnemy !== this && otherEnemy.mesh) {
701
- const otherEnemyBox = new THREE.Box3().setFromObject(otherEnemy.mesh);
702
- if (enemyBox.intersectsBox(otherEnemyBox)) {
703
- hasCollision = true;
704
- break;
705
- }
706
- }
707
- }
708
- }
709
-
710
- // ๋งต ๊ฒฝ๊ณ„ ์ฒดํฌ
711
- const mapBoundary = MAP_SIZE / 2;
712
- if (Math.abs(newPosition.x) > mapBoundary ||
713
- Math.abs(newPosition.z) > mapBoundary) {
714
- hasCollision = true;
715
- }
716
-
717
- // ์ถฉ๋Œ์ด ์žˆ์œผ๋ฉด ์ด์ „ ์œ„์น˜๋กœ ๋ณต๊ท€, ์—†์œผ๋ฉด ์ƒˆ ์œ„์น˜ ์œ ์ง€
718
- if (hasCollision) {
719
- this.mesh.position.copy(previousPosition);
720
-
721
- // ์ถฉ๋Œ ์‹œ ์šฐํšŒ ๊ฒฝ๋กœ ์‹œ๋„
722
- const alternateDirections = [
723
- new THREE.Vector3(-direction.z, 0, direction.x), // ์™ผ์ชฝ์œผ๋กœ 90๋„
724
- new THREE.Vector3(direction.z, 0, -direction.x), // ์˜ค๋ฅธ์ชฝ์œผ๋กœ 90๋„
725
- new THREE.Vector3(-direction.x, 0, -direction.z) // 180๋„ ํšŒ์ „
726
- ];
727
-
728
- for (const altDirection of alternateDirections) {
729
- const altMoveVector = altDirection.multiplyScalar(this.moveSpeed);
730
- const altNewPosition = previousPosition.clone().add(altMoveVector);
731
-
732
- this.mesh.position.copy(altNewPosition);
733
- const altEnemyBox = new THREE.Box3().setFromObject(this.mesh);
734
-
735
- let altHasCollision = false;
736
-
737
- // ์ƒˆ๋กœ์šด ๋ฐฉํ–ฅ์— ๋Œ€ํ•œ ์ถฉ๋Œ ๊ฒ€์‚ฌ
738
- for (const obstacle of window.gameInstance.obstacles) {
739
- const obstacleBox = new THREE.Box3().setFromObject(obstacle);
740
- if (altEnemyBox.intersectsBox(obstacleBox)) {
741
- altHasCollision = true;
742
- break;
743
- }
744
- }
745
-
746
- if (!altHasCollision) {
747
- // ์šฐํšŒ ๊ฒฝ๋กœ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉด ๊ทธ ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™
748
- break;
749
- } else {
750
- // ์šฐํšŒ๋„ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ์ด์ „ ์œ„์น˜๋กœ ๋ณต๊ท€
751
- this.mesh.position.copy(previousPosition);
752
- }
753
- }
754
  }
755
-
756
- // ์ง€ํ˜•์— ๋”ฐ๋ฅธ ๊ธฐ์šธ๊ธฐ ์กฐ์ •
757
- const forwardVector = new THREE.Vector3(0, 0, 1).applyQuaternion(this.mesh.quaternion);
758
- const rightVector = new THREE.Vector3(1, 0, 0).applyQuaternion(this.mesh.quaternion);
759
-
760
- const frontHeight = window.gameInstance.getHeightAtPosition(
761
- this.mesh.position.x + forwardVector.x,
762
- this.mesh.position.z + forwardVector.z
763
- );
764
- const backHeight = window.gameInstance.getHeightAtPosition(
765
- this.mesh.position.x - forwardVector.x,
766
- this.mesh.position.z - forwardVector.z
767
- );
768
- const rightHeight = window.gameInstance.getHeightAtPosition(
769
- this.mesh.position.x + rightVector.x,
770
- this.mesh.position.z + rightVector.z
771
- );
772
- const leftHeight = window.gameInstance.getHeightAtPosition(
773
- this.mesh.position.x - rightVector.x,
774
- this.mesh.position.z - rightVector.z
775
- );
776
-
777
- const pitch = Math.atan2(frontHeight - backHeight, 2);
778
- const roll = Math.atan2(rightHeight - leftHeight, 2);
779
-
780
- // ํ˜„์žฌ ํšŒ์ „ ์œ ์ง€ํ•˜๋ฉด์„œ ๊ธฐ์šธ๊ธฐ๋งŒ ์ ์šฉ
781
- const currentRotation = this.mesh.rotation.y;
782
- this.mesh.rotation.set(pitch, currentRotation, roll);
783
  }
784
-
785
- // ํ”Œ๋ ˆ๏ฟฝ๏ฟฝ์–ด๋ฅผ ํ–ฅํ•ด ํฌํƒ‘ ํšŒ์ „
786
- this.mesh.lookAt(playerPosition);
787
-
788
- // ์ด์•Œ ์—…๋ฐ์ดํŠธ
789
- if (this.bullets) {
790
- for (let i = this.bullets.length - 1; i >= 0; i--) {
791
- const bullet = this.bullets[i];
792
- bullet.position.add(bullet.velocity);
793
-
794
- // ์ด์•Œ์ด ๋งต ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๊ฑฐ๋‚˜ ์žฅ์• ๋ฌผ๊ณผ ์ถฉ๋Œํ•˜๋ฉด ์ œ๊ฑฐ
795
- if (Math.abs(bullet.position.x) > MAP_SIZE / 2 ||
796
- Math.abs(bullet.position.z) > MAP_SIZE / 2) {
797
- this.scene.remove(bullet);
798
- this.bullets.splice(i, 1);
799
- continue;
800
- }
801
-
802
- // ์ด์•Œ๊ณผ ์žฅ์• ๋ฌผ ์ถฉ๋Œ ์ฒดํฌ
803
- const bulletBox = new THREE.Box3().setFromObject(bullet);
804
- for (const obstacle of window.gameInstance.obstacles) {
805
- const obstacleBox = new THREE.Box3().setFromObject(obstacle);
806
- if (bulletBox.intersectsBox(obstacleBox)) {
807
- this.scene.remove(bullet);
808
- this.bullets.splice(i, 1);
809
- break;
810
- }
811
- }
812
- }
813
- }
814
- }
815
-
816
 
817
  shoot(playerPosition) {
818
- const currentTime = Date.now();
819
- const attackInterval = this.type === 'tank' ?
820
- ENEMY_CONFIG.ATTACK_INTERVAL :
821
- ENEMY_CONFIG.ATTACK_INTERVAL * 1.5;
822
 
823
- if (currentTime - this.lastAttackTime < attackInterval) return;
 
 
 
824
 
825
- // ๋ฐœ์‚ฌ ์ดํŽ™ํŠธ ์ƒ์„ฑ
826
- this.createMuzzleFlash();
827
 
828
- // ๋ฐœ์‚ฌ ์‚ฌ์šด๋“œ ์žฌ์ƒ
829
- const enemyFireSound = new Audio('sounds/mbtfire5.ogg');
830
- enemyFireSound.volume = 0.3;
831
- enemyFireSound.play();
 
832
 
833
- // ํฌํƒ„ ์ƒ์„ฑ (ํ”Œ๋ ˆ์ด์–ด์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์ˆ˜์ •)
834
- const bulletGeometry = new THREE.CylinderGeometry(0.2, 0.2, 2, 8);
835
- const bulletMaterial = new THREE.MeshBasicMaterial({
836
- color: 0xff0000, // ๋นจ๊ฐ„์ƒ‰ ํฌํƒ„
837
- emissive: 0xff0000,
838
- emissiveIntensity: 0.5
839
- });
840
- const bullet = new THREE.Mesh(bulletGeometry, bulletMaterial);
 
 
841
 
842
- // ํฌ๊ตฌ ์œ„์น˜์—์„œ ๋ฐœ์‚ฌ
843
- const muzzleOffset = new THREE.Vector3(0, 0.5, 4);
844
- const muzzlePosition = new THREE.Vector3();
845
- this.mesh.getWorldPosition(muzzlePosition);
846
- muzzleOffset.applyQuaternion(this.mesh.quaternion);
847
- muzzlePosition.add(muzzleOffset);
848
-
849
- bullet.position.copy(muzzlePosition);
850
-
851
- // ํฌํƒ„ ํšŒ์ „ ์„ค์ •
852
- bullet.quaternion.copy(this.mesh.quaternion);
853
-
854
- const direction = new THREE.Vector3()
855
- .subVectors(playerPosition, muzzlePosition)
856
- .normalize();
857
-
858
- const bulletSpeed = this.type === 'tank' ?
859
- ENEMY_CONFIG.BULLET_SPEED :
860
- ENEMY_CONFIG.BULLET_SPEED * 0.8;
861
-
862
- bullet.velocity = direction.multiplyScalar(bulletSpeed);
863
-
864
- // ํฌํƒ„ ํŠธ๋ ˆ์ผ ํšจ๊ณผ ์ถ”๊ฐ€
865
- const trailGeometry = new THREE.CylinderGeometry(0.1, 0.1, 1, 8);
866
- const trailMaterial = new THREE.MeshBasicMaterial({
867
- color: 0xff4444,
868
- transparent: true,
869
- opacity: 0.5
870
- });
871
-
872
- const trail = new THREE.Mesh(trailGeometry, trailMaterial);
873
- trail.position.z = -1;
874
- bullet.add(trail);
875
-
876
- this.scene.add(bullet);
877
- this.bullets.push(bullet);
878
- this.lastAttackTime = currentTime;
879
- }
880
 
881
  takeDamage(damage) {
882
  this.health -= damage;
 
553
  this.isLoaded = false;
554
  this.moveSpeed = type === 'tank' ? ENEMY_MOVE_SPEED : ENEMY_MOVE_SPEED * 0.7;
555
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
556
 
557
  async initialize(loader) {
558
+ try {
559
+ const result = await loader.loadAsync('/models/t90.glb');
560
+ this.mesh = result.scene;
561
+ this.mesh.position.copy(this.position);
562
+ this.mesh.scale.set(ENEMY_SCALE, ENEMY_SCALE, ENEMY_SCALE);
563
+ this.setupMesh();
564
+ this.isLoaded = true;
565
+ } catch (error) {
566
+ console.error('Error loading enemy model:', error);
567
+ this.isLoaded = false;
568
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  }
570
 
571
+ setupMesh() {
572
+ this.mesh.traverse(child => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
  if (child.isMesh) {
574
  child.castShadow = true;
575
  child.receiveShadow = true;
576
  }
577
  });
 
578
  this.createCollisionBox();
579
  this.scene.add(this.mesh);
 
 
 
 
580
  }
581
+
582
+ createCollisionBox() {
583
+ const geometry = new THREE.BoxGeometry(4, 2, 7);
584
+ const material = new THREE.MeshBasicMaterial({
585
+ color: 0xff0000,
586
+ wireframe: true,
587
+ visible: false
588
+ });
589
+ this.collisionBox = new THREE.Mesh(geometry, material);
590
+ this.mesh.add(this.collisionBox);
591
+ this.collisionBox.position.set(0, 1, 0);
592
+ }
593
 
594
  update(playerPosition) {
595
+ if (!this.isLoaded) return;
596
+ this.moveTowardsPlayer(playerPosition);
597
+ this.updateBullets();
598
+ }
599
 
600
+ moveTowardsPlayer(playerPosition) {
601
+ const direction = new THREE.Vector3()
602
+ .subVectors(playerPosition, this.mesh.position)
603
+ .normalize();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
604
 
605
+ const distanceToPlayer = this.mesh.position.distanceTo(playerPosition);
606
+ if (distanceToPlayer > 50) {
607
+ this.tryMove(direction);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
608
  }
609
+ this.mesh.lookAt(playerPosition);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
610
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
611
 
612
  shoot(playerPosition) {
613
+ if (Date.now() - this.lastAttackTime < ENEMY_CONFIG.ATTACK_INTERVAL) return;
 
 
 
614
 
615
+ const bullet = this.createBullet(playerPosition);
616
+ this.scene.add(bullet);
617
+ this.bullets.push(bullet);
618
+ this.lastAttackTime = Date.now();
619
 
620
+ new Audio('sounds/mbtfire5.ogg').play();
621
+ }
622
 
623
+ createBullet(targetPosition) {
624
+ const bullet = new THREE.Mesh(
625
+ new THREE.CylinderGeometry(0.2, 0.2, 2, 8),
626
+ new THREE.MeshBasicMaterial({ color: 0xff0000 })
627
+ );
628
 
629
+ const muzzlePosition = this.getMuzzlePosition();
630
+ bullet.position.copy(muzzlePosition);
631
+
632
+ const direction = new THREE.Vector3()
633
+ .subVectors(targetPosition, muzzlePosition)
634
+ .normalize();
635
+
636
+ bullet.velocity = direction.multiplyScalar(ENEMY_CONFIG.BULLET_SPEED);
637
+ return bullet;
638
+ }
639
 
640
+ getMuzzlePosition() {
641
+ const muzzleOffset = new THREE.Vector3(0, 0.5, 4);
642
+ const position = new THREE.Vector3();
643
+ this.mesh.getWorldPosition(position);
644
+ muzzleOffset.applyQuaternion(this.mesh.quaternion);
645
+ return position.add(muzzleOffset);
646
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
647
 
648
  takeDamage(damage) {
649
  this.health -= damage;