cutechicken commited on
Commit
e4939a8
β€’
1 Parent(s): e43a395

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +177 -150
game.js CHANGED
@@ -744,6 +744,8 @@ class Game {
744
  this.renderer = new THREE.WebGLRenderer({ antialias: true });
745
  this.renderer.setSize(window.innerWidth, window.innerHeight);
746
  this.renderer.shadowMap.enabled = true;
 
 
747
  document.getElementById('gameContainer').appendChild(this.renderer.domElement);
748
 
749
 
@@ -781,163 +783,188 @@ class Game {
781
  }
782
 
783
  async initialize() {
784
- try {
785
- // μ‹œμž‘ μ‚¬μš΄λ“œ μž¬μƒ
786
  const startSounds = ['sounds/start1.ogg', 'sounds/start2.ogg', 'sounds/start3.ogg'];
787
  const randomStartSound = startSounds[Math.floor(Math.random() * startSounds.length)];
788
  const startAudio = new Audio(randomStartSound);
789
  startAudio.volume = 0.5;
790
  startAudio.play();
791
- // μ•ˆκ°œ 효과 제거
792
- this.scene.fog = null;
 
 
 
 
 
 
793
  this.scene.background = new THREE.Color(0x87CEEB);
794
 
795
- // μ£Όλ³€κ΄‘ μ„€μ • - 더 밝게
796
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
797
- this.scene.add(ambientLight);
798
-
799
- // νƒœμ–‘κ΄‘ μ„€μ •
800
- const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
801
- directionalLight.position.set(100, 100, 50);
802
- directionalLight.castShadow = true;
803
- directionalLight.shadow.mapSize.width = 1024;
804
- directionalLight.shadow.mapSize.height = 1024;
805
- this.scene.add(directionalLight);
806
-
807
- // μ§€ν˜• 생성 μˆ˜μ •
808
- const groundGeometry = new THREE.PlaneGeometry(MAP_SIZE, MAP_SIZE, 100, 100);
809
- const groundMaterial = new THREE.MeshStandardMaterial({
810
- color: 0xD2B48C,
811
- roughness: 0.8,
812
- metalness: 0.2,
813
- wireframe: false
814
- });
815
-
816
- const ground = new THREE.Mesh(groundGeometry, groundMaterial);
817
- ground.rotation.x = -Math.PI / 2;
818
- ground.receiveShadow = true;
819
-
820
- // μ§€ν˜• 높이 μ„€μ •
821
- const vertices = ground.geometry.attributes.position.array;
822
- const heightScale = 15;
823
- const baseFrequency = 0.008;
824
-
825
- // 평지 μ˜μ—­ μ •μ˜
826
- const flatlandRadius = MAP_SIZE * 0.3; // 평지 μ˜μ—­μ˜ 반경
827
- const transitionZone = MAP_SIZE * 0.1; // 평지와 언덕 μ‚¬μ΄μ˜ μ „ν™˜ ꡬ역
828
-
829
- for (let i = 0; i < vertices.length; i += 3) {
830
- const x = vertices[i];
831
- const y = vertices[i + 1];
832
-
833
- // μ€‘μ‹¬μ μœΌλ‘œλΆ€ν„°μ˜ 거리 계산
834
- const distanceFromCenter = Math.sqrt(x * x + y * y);
835
-
836
- // 평지 μ˜μ—­μ΄λ©΄ 높이λ₯Ό 0으둜 μ„€μ •
837
- if (distanceFromCenter < flatlandRadius) {
838
- vertices[i + 2] = 0;
839
- }
840
- // μ „ν™˜ ꡬ역이면 λΆ€λ“œλŸ½κ²Œ 높이 증가
841
- else if (distanceFromCenter < flatlandRadius + transitionZone) {
842
- const transitionFactor = (distanceFromCenter - flatlandRadius) / transitionZone;
843
- let height = 0;
844
-
845
- // 언덕 높이 계산
846
- height += Math.sin(x * baseFrequency) * Math.cos(y * baseFrequency) * heightScale;
847
- height += Math.sin(x * baseFrequency * 2) * Math.cos(y * baseFrequency * 2) * (heightScale * 0.5);
848
- height += Math.sin(x * baseFrequency * 4) * Math.cos(y * baseFrequency * 4) * (heightScale * 0.25);
849
-
850
- vertices[i + 2] = height * transitionFactor;
851
- }
852
- // 언덕 μ˜μ—­
853
- else {
854
- let height = 0;
855
- height += Math.sin(x * baseFrequency) * Math.cos(y * baseFrequency) * heightScale;
856
- height += Math.sin(x * baseFrequency * 2) * Math.cos(y * baseFrequency * 2) * (heightScale * 0.5);
857
- height += Math.sin(x * baseFrequency * 4) * Math.cos(y * baseFrequency * 4) * (heightScale * 0.25);
858
- vertices[i + 2] = height;
859
- }
860
- }
861
-
862
- ground.geometry.attributes.position.needsUpdate = true;
863
- ground.geometry.computeVertexNormals();
864
- this.ground = ground;
865
- this.scene.add(ground);
866
-
867
- // λ“±κ³ μ„  효과 (언덕 μ˜μ—­μ—λ§Œ 적용)
868
- const contourMaterial = new THREE.LineBasicMaterial({
869
- color: 0x000000,
870
- opacity: 0.15,
871
- transparent: true
872
- });
873
-
874
- const contourLines = new THREE.LineSegments(
875
- new THREE.EdgesGeometry(groundGeometry),
876
- contourMaterial
877
- );
878
- contourLines.rotation.x = -Math.PI / 2;
879
- contourLines.position.y = 0.1;
880
- this.scene.add(contourLines);
881
-
882
- // 격자 효과 (평지 μ˜μ—­μ—λ§Œ 적용)
883
- const gridHelper = new THREE.GridHelper(flatlandRadius * 2, 50, 0x000000, 0x000000);
884
- gridHelper.material.opacity = 0.1;
885
- gridHelper.material.transparent = true;
886
- gridHelper.position.y = 0.1;
887
- this.scene.add(gridHelper);
888
-
889
- // 사막 μž₯식 μΆ”κ°€
890
- await this.addDesertDecorations();
891
-
892
- // 탱크 μ΄ˆκΈ°ν™”
893
- await this.tank.initialize(this.scene, this.loader);
894
- if (!this.tank.isLoaded) {
895
- throw new Error('Tank loading failed');
896
- }
897
-
898
- // 슀폰 μœ„μΉ˜ 검증 및 μž¬μ‹œμž‘ 둜직 μΆ”κ°€
899
- const spawnPos = this.findValidSpawnPosition();
900
- const heightAtSpawn = this.getHeightAtPosition(spawnPos.x, spawnPos.z);
901
- const slopeCheckPoints = [
902
- { x: spawnPos.x + 2, z: spawnPos.z },
903
- { x: spawnPos.x - 2, z: spawnPos.z },
904
- { x: spawnPos.x, z: spawnPos.z + 2 },
905
- { x: spawnPos.x, z: spawnPos.z - 2 }
906
- ];
907
-
908
- const slopes = slopeCheckPoints.map(point => {
909
- const pointHeight = this.getHeightAtPosition(point.x, point.z);
910
- return Math.abs(pointHeight - heightAtSpawn) / 2;
911
- });
912
-
913
- const maxSlope = Math.max(...slopes);
914
- if (maxSlope > 0.3) { // 경사가 λ„ˆλ¬΄ κ°€νŒŒλ₯΄λ©΄
915
- location.reload(); // κ²Œμž„ μžλ™ μž¬μ‹œμž‘
916
- return;
917
- }
918
-
919
- // 카메라 초기 μœ„μΉ˜ μ„€μ •
920
- const tankPosition = this.tank.getPosition();
921
- this.camera.position.set(
922
- tankPosition.x,
923
- tankPosition.y + 15,
924
- tankPosition.z - 30
925
- );
926
- this.camera.lookAt(tankPosition);
927
-
928
- // λ‘œλ”© μ™„λ£Œ
929
- this.isLoading = false;
930
- document.getElementById('loading').style.display = 'none';
931
-
932
- // κ²Œμž„ μ‹œμž‘
933
- this.animate();
934
- this.spawnEnemies();
935
- this.startGameTimer();
936
-
937
- } catch (error) {
938
- console.error('Game initialization error:', error);
939
- this.handleLoadingError();
940
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
941
  }
942
 
943
  // λ ˆμ΄λ” μ—…λ°μ΄νŠΈ λ©”μ„œλ“œ μΆ”κ°€
 
744
  this.renderer = new THREE.WebGLRenderer({ antialias: true });
745
  this.renderer.setSize(window.innerWidth, window.innerHeight);
746
  this.renderer.shadowMap.enabled = true;
747
+ this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // λΆ€λ“œλŸ¬μš΄ 그림자
748
+ this.renderer.outputEncoding = THREE.sRGBEncoding; // 더 μ •ν™•ν•œ 색상 ν‘œν˜„
749
  document.getElementById('gameContainer').appendChild(this.renderer.domElement);
750
 
751
 
 
783
  }
784
 
785
  async initialize() {
786
+ try {
787
+ // μ‹œμž‘ μ‚¬μš΄λ“œ μž¬μƒ
788
  const startSounds = ['sounds/start1.ogg', 'sounds/start2.ogg', 'sounds/start3.ogg'];
789
  const randomStartSound = startSounds[Math.floor(Math.random() * startSounds.length)];
790
  const startAudio = new Audio(randomStartSound);
791
  startAudio.volume = 0.5;
792
  startAudio.play();
793
+
794
+ // λ Œλ”λŸ¬ μ„€μ • κ°œμ„ 
795
+ this.renderer.shadowMap.enabled = true;
796
+ this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
797
+ this.renderer.outputEncoding = THREE.sRGBEncoding;
798
+
799
+ // μ•ˆκ°œ 효과
800
+ this.scene.fog = new THREE.FogExp2(0x87CEEB, 0.0008);
801
  this.scene.background = new THREE.Color(0x87CEEB);
802
 
803
+ // μ£Όλ³€κ΄‘ μ„€μ •
804
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
805
+ this.scene.add(ambientLight);
806
+
807
+ // 메인 νƒœμ–‘κ΄‘ μ„€μ •
808
+ const mainLight = new THREE.DirectionalLight(0xffffff, 1.0);
809
+ mainLight.position.set(100, 100, 50);
810
+ mainLight.castShadow = true;
811
+
812
+ // 그림자 ν’ˆμ§ˆ ν–₯상
813
+ mainLight.shadow.mapSize.width = 2048;
814
+ mainLight.shadow.mapSize.height = 2048;
815
+ mainLight.shadow.camera.near = 0.5;
816
+ mainLight.shadow.camera.far = 500;
817
+ mainLight.shadow.camera.left = -100;
818
+ mainLight.shadow.camera.right = 100;
819
+ mainLight.shadow.camera.top = 100;
820
+ mainLight.shadow.camera.bottom = -100;
821
+ mainLight.shadow.bias = -0.001;
822
+ mainLight.shadow.radius = 2;
823
+
824
+ this.scene.add(mainLight);
825
+
826
+ // 보쑰 νƒœμ–‘κ΄‘ μΆ”κ°€
827
+ const secondaryLight = new THREE.DirectionalLight(0xffffff, 0.3);
828
+ secondaryLight.position.set(-50, 50, -50);
829
+ this.scene.add(secondaryLight);
830
+
831
+ // ν™˜κ²½κ΄‘ μΆ”κ°€
832
+ const hemisphereLight = new THREE.HemisphereLight(
833
+ 0x87CEEB, // ν•˜λŠ˜μƒ‰
834
+ 0xFFE87C, // λ”°λœ»ν•œ λ…Έλž€μƒ‰
835
+ 0.3
836
+ );
837
+ this.scene.add(hemisphereLight);
838
+
839
+ // μ§€ν˜• 생성 μˆ˜μ •
840
+ const groundGeometry = new THREE.PlaneGeometry(MAP_SIZE, MAP_SIZE, 100, 100);
841
+ const groundMaterial = new THREE.MeshStandardMaterial({
842
+ color: 0xD2B48C,
843
+ roughness: 0.8,
844
+ metalness: 0.2,
845
+ envMapIntensity: 1.0
846
+ });
847
+
848
+ const ground = new THREE.Mesh(groundGeometry, groundMaterial);
849
+ ground.rotation.x = -Math.PI / 2;
850
+ ground.receiveShadow = true;
851
+
852
+ // μ§€ν˜• 높이 μ„€μ •
853
+ const vertices = ground.geometry.attributes.position.array;
854
+ const heightScale = 15;
855
+ const baseFrequency = 0.008;
856
+
857
+ // 평지 μ˜μ—­ μ •μ˜
858
+ const flatlandRadius = MAP_SIZE * 0.3;
859
+ const transitionZone = MAP_SIZE * 0.1;
860
+
861
+ for (let i = 0; i < vertices.length; i += 3) {
862
+ const x = vertices[i];
863
+ const y = vertices[i + 1];
864
+
865
+ const distanceFromCenter = Math.sqrt(x * x + y * y);
866
+
867
+ if (distanceFromCenter < flatlandRadius) {
868
+ vertices[i + 2] = 0;
869
+ }
870
+ else if (distanceFromCenter < flatlandRadius + transitionZone) {
871
+ const transitionFactor = (distanceFromCenter - flatlandRadius) / transitionZone;
872
+ let height = 0;
873
+
874
+ height += Math.sin(x * baseFrequency) * Math.cos(y * baseFrequency) * heightScale;
875
+ height += Math.sin(x * baseFrequency * 2) * Math.cos(y * baseFrequency * 2) * (heightScale * 0.5);
876
+ height += Math.sin(x * baseFrequency * 4) * Math.cos(y * baseFrequency * 4) * (heightScale * 0.25);
877
+
878
+ vertices[i + 2] = height * transitionFactor;
879
+ }
880
+ else {
881
+ let height = 0;
882
+ height += Math.sin(x * baseFrequency) * Math.cos(y * baseFrequency) * heightScale;
883
+ height += Math.sin(x * baseFrequency * 2) * Math.cos(y * baseFrequency * 2) * (heightScale * 0.5);
884
+ height += Math.sin(x * baseFrequency * 4) * Math.cos(y * baseFrequency * 4) * (heightScale * 0.25);
885
+ vertices[i + 2] = height;
886
+ }
887
+ }
888
+
889
+ ground.geometry.attributes.position.needsUpdate = true;
890
+ ground.geometry.computeVertexNormals();
891
+ this.ground = ground;
892
+ this.scene.add(ground);
893
+
894
+ // λ“±κ³ μ„  효과
895
+ const contourMaterial = new THREE.LineBasicMaterial({
896
+ color: 0x000000,
897
+ opacity: 0.15,
898
+ transparent: true
899
+ });
900
+
901
+ const contourLines = new THREE.LineSegments(
902
+ new THREE.EdgesGeometry(groundGeometry),
903
+ contourMaterial
904
+ );
905
+ contourLines.rotation.x = -Math.PI / 2;
906
+ contourLines.position.y = 0.1;
907
+ this.scene.add(contourLines);
908
+
909
+ // 격자 효과
910
+ const gridHelper = new THREE.GridHelper(flatlandRadius * 2, 50, 0x000000, 0x000000);
911
+ gridHelper.material.opacity = 0.1;
912
+ gridHelper.material.transparent = true;
913
+ gridHelper.position.y = 0.1;
914
+ this.scene.add(gridHelper);
915
+
916
+ // 사막 μž₯식 μΆ”κ°€
917
+ await this.addDesertDecorations();
918
+
919
+ // 탱크 μ΄ˆκΈ°ν™”
920
+ await this.tank.initialize(this.scene, this.loader);
921
+ if (!this.tank.isLoaded) {
922
+ throw new Error('Tank loading failed');
923
+ }
924
+
925
+ // 슀폰 μœ„μΉ˜ 검증 및 μž¬μ‹œμž‘ 둜직
926
+ const spawnPos = this.findValidSpawnPosition();
927
+ const heightAtSpawn = this.getHeightAtPosition(spawnPos.x, spawnPos.z);
928
+ const slopeCheckPoints = [
929
+ { x: spawnPos.x + 2, z: spawnPos.z },
930
+ { x: spawnPos.x - 2, z: spawnPos.z },
931
+ { x: spawnPos.x, z: spawnPos.z + 2 },
932
+ { x: spawnPos.x, z: spawnPos.z - 2 }
933
+ ];
934
+
935
+ const slopes = slopeCheckPoints.map(point => {
936
+ const pointHeight = this.getHeightAtPosition(point.x, point.z);
937
+ return Math.abs(pointHeight - heightAtSpawn) / 2;
938
+ });
939
+
940
+ const maxSlope = Math.max(...slopes);
941
+ if (maxSlope > 0.3) {
942
+ location.reload();
943
+ return;
944
+ }
945
+
946
+ // 카메라 초기 μœ„μΉ˜ μ„€μ •
947
+ const tankPosition = this.tank.getPosition();
948
+ this.camera.position.set(
949
+ tankPosition.x,
950
+ tankPosition.y + 15,
951
+ tankPosition.z - 30
952
+ );
953
+ this.camera.lookAt(tankPosition);
954
+
955
+ // λ‘œλ”© μ™„λ£Œ
956
+ this.isLoading = false;
957
+ document.getElementById('loading').style.display = 'none';
958
+
959
+ // κ²Œμž„ μ‹œμž‘
960
+ this.animate();
961
+ this.spawnEnemies();
962
+ this.startGameTimer();
963
+
964
+ } catch (error) {
965
+ console.error('Game initialization error:', error);
966
+ this.handleLoadingError();
967
+ }
968
  }
969
 
970
  // λ ˆμ΄λ” μ—…λ°μ΄νŠΈ λ©”μ„œλ“œ μΆ”κ°€