cutechicken commited on
Commit
2ba793e
ยท
verified ยท
1 Parent(s): be285e6

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +220 -48
game.js CHANGED
@@ -1297,10 +1297,7 @@ class Game {
1297
 
1298
  async loadFieldTerrain() {
1299
  try {
1300
- const fieldTileSize = 1000; // ๊ฐ field ํƒ€์ผ์˜ ํฌ๊ธฐ
1301
- const tilesPerSide = Math.ceil(GAME_CONSTANTS.MAP_SIZE / fieldTileSize);
1302
-
1303
- // field.glb๋ฅผ ํ•œ ๋ฒˆ๋งŒ ๋กœ๋“œ
1304
  const result = await this.loader.loadAsync('models/field.glb');
1305
  const fieldModel = result.scene;
1306
 
@@ -1308,36 +1305,29 @@ class Game {
1308
  const box = new THREE.Box3().setFromObject(fieldModel);
1309
  const size = box.getSize(new THREE.Vector3());
1310
 
1311
- // ๋งต ์ „์ฒด๋ฅผ ์ฑ„์šฐ๊ธฐ ์œ„ํ•ด ํƒ€์ผ ๋ฐฐ์น˜
1312
- for (let x = 0; x < tilesPerSide; x++) {
1313
- for (let z = 0; z < tilesPerSide; z++) {
1314
- const fieldClone = fieldModel.clone();
1315
-
1316
- // ์œ„์น˜ ์„ค์ •
1317
- const posX = (x - tilesPerSide / 2) * fieldTileSize;
1318
- const posZ = (z - tilesPerSide / 2) * fieldTileSize;
1319
- fieldClone.position.set(posX, 0, posZ);
1320
-
1321
- // ํฌ๊ธฐ ์กฐ์ • (ํ•„์š”ํ•œ ๊ฒฝ์šฐ)
1322
- const scale = fieldTileSize / Math.max(size.x, size.z);
1323
- fieldClone.scale.set(scale, scale, scale);
1324
-
1325
- // ๋žœ๋ค ํšŒ์ „์œผ๋กœ ๋ฐ˜๋ณต ํŒจํ„ด ๋ฐฉ์ง€
1326
- fieldClone.rotation.y = Math.floor(Math.random() * 4) * Math.PI / 2;
1327
-
1328
- // ๊ทธ๋ฆผ์ž ์„ค์ •
1329
- fieldClone.traverse((child) => {
1330
- if (child.isMesh) {
1331
- child.receiveShadow = true;
1332
- child.castShadow = true;
1333
- }
1334
- });
1335
 
1336
- this.scene.add(fieldClone);
 
 
 
1337
  }
1338
- }
1339
 
1340
- console.log(`Field terrain loaded: ${tilesPerSide}x${tilesPerSide} tiles`);
 
1341
 
1342
  } catch (error) {
1343
  console.error('Field terrain loading failed:', error);
@@ -1379,27 +1369,209 @@ class Game {
1379
  }
1380
 
1381
  addAtmosphericEffects() {
1382
- // ๋จผ ์‚ฐ ์‹ค๋ฃจ์—ฃ ์ถ”๊ฐ€
1383
- const mountainCount = 20;
1384
- for (let i = 0; i < mountainCount; i++) {
1385
- const angle = (i / mountainCount) * Math.PI * 2;
1386
- const distance = GAME_CONSTANTS.MAP_SIZE * 0.7;
1387
-
1388
- const mountainGeometry = new THREE.ConeGeometry(2000 + Math.random() * 1000, 3000 + Math.random() * 2000, 8);
1389
- const mountainMaterial = new THREE.MeshLambertMaterial({
1390
- color: 0x4a5d6a,
1391
- fog: true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1392
  });
1393
 
1394
- const mountain = new THREE.Mesh(mountainGeometry, mountainMaterial);
1395
- mountain.position.set(
1396
- Math.cos(angle) * distance,
1397
- 1500 + Math.random() * 500,
1398
- Math.sin(angle) * distance
 
 
 
1399
  );
1400
- mountain.rotation.y = Math.random() * Math.PI;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1401
 
1402
- this.scene.add(mountain);
 
1403
  }
1404
  }
1405
 
 
1297
 
1298
  async loadFieldTerrain() {
1299
  try {
1300
+ // field.glb๋ฅผ ํ•œ ๋ฒˆ๋งŒ ๋กœ๋“œํ•˜์—ฌ ์ „์ฒด ๋งต ํฌ๊ธฐ๋กœ ์Šค์ผ€์ผ
 
 
 
1301
  const result = await this.loader.loadAsync('models/field.glb');
1302
  const fieldModel = result.scene;
1303
 
 
1305
  const box = new THREE.Box3().setFromObject(fieldModel);
1306
  const size = box.getSize(new THREE.Vector3());
1307
 
1308
+ // ์ „์ฒด ๋งต ํฌ๊ธฐ์— ๋งž๊ฒŒ ์Šค์ผ€์ผ ๊ณ„์‚ฐ
1309
+ const scaleX = GAME_CONSTANTS.MAP_SIZE / size.x;
1310
+ const scaleZ = GAME_CONSTANTS.MAP_SIZE / size.z;
1311
+ const scale = Math.max(scaleX, scaleZ); // ๋งต์„ ์™„์ „ํžˆ ์ฑ„์šฐ๋„๋ก ๋” ํฐ ์Šค์ผ€์ผ ์‚ฌ์šฉ
1312
+
1313
+ fieldModel.scale.set(scale, scale, scale);
1314
+ fieldModel.position.set(0, 0, 0);
1315
+
1316
+ // ๊ทธ๋ฆผ์ž ์„ค์ •
1317
+ fieldModel.traverse((child) => {
1318
+ if (child.isMesh) {
1319
+ child.receiveShadow = true;
1320
+ child.castShadow = true;
 
 
 
 
 
 
 
 
 
 
 
1321
 
1322
+ // ์ง€ํ˜• ๋จธํ‹ฐ๋ฆฌ์–ผ ๊ฐœ์„ 
1323
+ if (child.material) {
1324
+ child.material.side = THREE.DoubleSide;
1325
+ }
1326
  }
1327
+ });
1328
 
1329
+ this.scene.add(fieldModel);
1330
+ console.log(`Field terrain loaded and scaled to ${scale}x`);
1331
 
1332
  } catch (error) {
1333
  console.error('Field terrain loading failed:', error);
 
1369
  }
1370
 
1371
  addAtmosphericEffects() {
1372
+ // ๊ฐœ์„ ๋œ ์‚ฐ ์ง€ํ˜• ์‹œ์Šคํ…œ
1373
+ this.createMountainRanges();
1374
+
1375
+ // ๋Œ€๊ธฐ ์‚ฐ๋ž€ ํšจ๊ณผ
1376
+ this.addAtmosphericScattering();
1377
+ }
1378
+
1379
+ createMountainRanges() {
1380
+ // ์‚ฐ๋งฅ ์ƒ์„ฑ์„ ์œ„ํ•œ ์„ค์ •
1381
+ const mountainRanges = [
1382
+ {
1383
+ distance: GAME_CONSTANTS.MAP_SIZE * 0.6,
1384
+ count: 25,
1385
+ heightRange: { min: 2000, max: 5000 },
1386
+ widthRange: { min: 1500, max: 3000 },
1387
+ color: 0x5a6b7a
1388
+ },
1389
+ {
1390
+ distance: GAME_CONSTANTS.MAP_SIZE * 0.8,
1391
+ count: 20,
1392
+ heightRange: { min: 3000, max: 7000 },
1393
+ widthRange: { min: 2000, max: 4000 },
1394
+ color: 0x4a5b6a
1395
+ },
1396
+ {
1397
+ distance: GAME_CONSTANTS.MAP_SIZE * 1.0,
1398
+ count: 15,
1399
+ heightRange: { min: 4000, max: 9000 },
1400
+ widthRange: { min: 3000, max: 5000 },
1401
+ color: 0x3a4b5a
1402
+ }
1403
+ ];
1404
+
1405
+ mountainRanges.forEach(range => {
1406
+ for (let i = 0; i < range.count; i++) {
1407
+ const angle = (i / range.count) * Math.PI * 2 + (Math.random() - 0.5) * 0.3;
1408
+ const distance = range.distance + (Math.random() - 0.5) * 1000;
1409
+
1410
+ // ์‚ฐ ๊ทธ๋ฃน ์ƒ์„ฑ (์—ฌ๋Ÿฌ ๋ด‰์šฐ๋ฆฌ๋กœ ๊ตฌ์„ฑ)
1411
+ const mountainGroup = new THREE.Group();
1412
+
1413
+ // ๋ฉ”์ธ ๋ด‰์šฐ๋ฆฌ
1414
+ const mainPeakHeight = range.heightRange.min + Math.random() * (range.heightRange.max - range.heightRange.min);
1415
+ const mainPeakWidth = range.widthRange.min + Math.random() * (range.widthRange.max - range.widthRange.min);
1416
+
1417
+ // ๊ฐœ์„ ๋œ ์‚ฐ ํ˜•ํƒœ (ํŒ”๊ฐ๋ฟ” ๋Œ€์‹  ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ํ˜•ํƒœ)
1418
+ const mainPeakGeometry = new THREE.ConeGeometry(mainPeakWidth, mainPeakHeight, 12);
1419
+ const vertices = mainPeakGeometry.attributes.position.array;
1420
+
1421
+ // ์ •์  ๋ณ€ํ˜•์œผ๋กœ ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ์‚ฐ ํ˜•ํƒœ ๋งŒ๋“ค๊ธฐ
1422
+ for (let j = 0; j < vertices.length; j += 3) {
1423
+ const x = vertices[j];
1424
+ const y = vertices[j + 1];
1425
+ const z = vertices[j + 2];
1426
+
1427
+ // ๋†’์ด์— ๋”ฐ๋ฅธ ๋žœ๋ค ๋ณ€ํ˜•
1428
+ const heightFactor = (y + mainPeakHeight * 0.5) / mainPeakHeight;
1429
+ const noise = (Math.random() - 0.5) * mainPeakWidth * 0.3 * (1 - heightFactor);
1430
+
1431
+ vertices[j] += noise;
1432
+ vertices[j + 2] += noise;
1433
+ }
1434
+
1435
+ mainPeakGeometry.computeVertexNormals();
1436
+
1437
+ const mainPeakMaterial = new THREE.MeshLambertMaterial({
1438
+ color: range.color,
1439
+ flatShading: true,
1440
+ fog: true
1441
+ });
1442
+
1443
+ const mainPeak = new THREE.Mesh(mainPeakGeometry, mainPeakMaterial);
1444
+ mountainGroup.add(mainPeak);
1445
+
1446
+ // ์ฃผ๋ณ€ ์ž‘์€ ๋ด‰์šฐ๋ฆฌ๋“ค ์ถ”๊ฐ€
1447
+ const subPeakCount = 2 + Math.floor(Math.random() * 3);
1448
+ for (let j = 0; j < subPeakCount; j++) {
1449
+ const subPeakHeight = mainPeakHeight * (0.5 + Math.random() * 0.3);
1450
+ const subPeakWidth = mainPeakWidth * (0.6 + Math.random() * 0.3);
1451
+
1452
+ const subPeakGeometry = new THREE.ConeGeometry(subPeakWidth, subPeakHeight, 8);
1453
+ const subPeak = new THREE.Mesh(subPeakGeometry, mainPeakMaterial);
1454
+
1455
+ // ๋ฉ”์ธ ๋ด‰์šฐ๋ฆฌ ์ฃผ๋ณ€์— ๋ฐฐ์น˜
1456
+ const offsetAngle = (j / subPeakCount) * Math.PI * 2;
1457
+ const offsetDistance = mainPeakWidth * (0.6 + Math.random() * 0.4);
1458
+
1459
+ subPeak.position.set(
1460
+ Math.cos(offsetAngle) * offsetDistance,
1461
+ -mainPeakHeight * 0.3,
1462
+ Math.sin(offsetAngle) * offsetDistance
1463
+ );
1464
+
1465
+ mountainGroup.add(subPeak);
1466
+ }
1467
+
1468
+ // ์‚ฐ ๊ธฐ๋ฐ˜๋ถ€ (๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ฒฝ์‚ฌ)
1469
+ const baseGeometry = new THREE.CylinderGeometry(
1470
+ mainPeakWidth * 1.5,
1471
+ mainPeakWidth * 2.5,
1472
+ mainPeakHeight * 0.3,
1473
+ 12
1474
+ );
1475
+ const baseMaterial = new THREE.MeshLambertMaterial({
1476
+ color: new THREE.Color(range.color).multiplyScalar(0.8),
1477
+ flatShading: true,
1478
+ fog: true
1479
+ });
1480
+ const base = new THREE.Mesh(baseGeometry, baseMaterial);
1481
+ base.position.y = -mainPeakHeight * 0.35;
1482
+ mountainGroup.add(base);
1483
+
1484
+ // ์‚ฐ ๊ทธ๋ฃน ์œ„์น˜ ์„ค์ •
1485
+ mountainGroup.position.set(
1486
+ Math.cos(angle) * distance,
1487
+ mainPeakHeight * 0.5,
1488
+ Math.sin(angle) * distance
1489
+ );
1490
+
1491
+ // ์•ฝ๊ฐ„์˜ ๋žœ๋ค ํšŒ์ „
1492
+ mountainGroup.rotation.y = Math.random() * Math.PI;
1493
+
1494
+ // ๊ฑฐ๋ฆฌ์— ๋”ฐ๋ฅธ ์•ˆ๊ฐœ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ ๋ ˆ์ด์–ด ์„ค์ •
1495
+ mountainGroup.layers.set(0);
1496
+
1497
+ this.scene.add(mountainGroup);
1498
+ }
1499
+ });
1500
+
1501
+ // ๊ฐ€์žฅ ๋จผ ๊ฑฐ๋ฆฌ์— ๊ฑฐ๋Œ€ํ•œ ์‚ฐ๋งฅ ์‹ค๋ฃจ์—ฃ ์ถ”๊ฐ€
1502
+ this.createDistantMountainSilhouette();
1503
+ }
1504
+
1505
+ createDistantMountainSilhouette() {
1506
+ // ์›๊ฑฐ๋ฆฌ ์‚ฐ๋งฅ ์‹ค๋ฃจ์—ฃ (2D ํ‰๋ฉด)
1507
+ const silhouetteDistance = GAME_CONSTANTS.MAP_SIZE * 1.2;
1508
+ const segments = 50;
1509
+
1510
+ for (let side = 0; side < 4; side++) {
1511
+ const curve = new THREE.CatmullRomCurve3([]);
1512
+
1513
+ // ์‚ฐ๋งฅ ์‹ค๋ฃจ์—ฃ ๊ณก์„  ์ƒ์„ฑ
1514
+ for (let i = 0; i <= segments; i++) {
1515
+ const t = i / segments;
1516
+ const x = (t - 0.5) * GAME_CONSTANTS.MAP_SIZE;
1517
+ const baseHeight = 3000;
1518
+ const variation = Math.sin(t * Math.PI * 3) * 2000 +
1519
+ Math.sin(t * Math.PI * 7) * 1000 +
1520
+ Math.sin(t * Math.PI * 13) * 500;
1521
+ const y = baseHeight + variation + Math.random() * 500;
1522
+
1523
+ curve.points.push(new THREE.Vector3(x, y, 0));
1524
+ }
1525
+
1526
+ // ์‹ค๋ฃจ์—ฃ ๋ฉ”์‹œ ์ƒ์„ฑ
1527
+ const points = curve.getPoints(100);
1528
+ const shape = new THREE.Shape();
1529
+
1530
+ shape.moveTo(points[0].x, 0);
1531
+ points.forEach(p => shape.lineTo(p.x, p.y));
1532
+ shape.lineTo(points[points.length - 1].x, 0);
1533
+ shape.lineTo(points[0].x, 0);
1534
+
1535
+ const silhouetteGeometry = new THREE.ShapeGeometry(shape);
1536
+ const silhouetteMaterial = new THREE.MeshBasicMaterial({
1537
+ color: 0x2a3b4a,
1538
+ side: THREE.DoubleSide,
1539
+ fog: true,
1540
+ transparent: true,
1541
+ opacity: 0.7
1542
  });
1543
 
1544
+ const silhouette = new THREE.Mesh(silhouetteGeometry, silhouetteMaterial);
1545
+
1546
+ // ๊ฐ ๋ฉด์— ๋ฐฐ์น˜
1547
+ const angle = (side / 4) * Math.PI * 2;
1548
+ silhouette.position.set(
1549
+ Math.cos(angle) * silhouetteDistance,
1550
+ 0,
1551
+ Math.sin(angle) * silhouetteDistance
1552
  );
1553
+ silhouette.lookAt(0, 0, 0);
1554
+
1555
+ this.scene.add(silhouette);
1556
+ }
1557
+ }
1558
+
1559
+ addAtmosphericScattering() {
1560
+ // ๋Œ€๊ธฐ ์‚ฐ๋ž€ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ ๋ฐ˜ํˆฌ๋ช… ๊ตฌ์ฒด๋“ค
1561
+ const scatteringLayers = 5;
1562
+ for (let i = 0; i < scatteringLayers; i++) {
1563
+ const radius = 20000 + i * 5000;
1564
+ const geometry = new THREE.SphereGeometry(radius, 32, 32);
1565
+ const material = new THREE.MeshBasicMaterial({
1566
+ color: 0x87CEEB,
1567
+ transparent: true,
1568
+ opacity: 0.02,
1569
+ side: THREE.BackSide,
1570
+ depthWrite: false
1571
+ });
1572
 
1573
+ const atmosphere = new THREE.Mesh(geometry, material);
1574
+ this.scene.add(atmosphere);
1575
  }
1576
  }
1577