Spaces:
Running
Running
File size: 3,770 Bytes
9e6ef9c 0ee2f3f 9e6ef9c 0ee2f3f 9e6ef9c 0ee2f3f 9e6ef9c 0ee2f3f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
import * as THREE from "three";
import { Projectile } from "../../Projectile.js";
import { findNearestWithinRange } from "../common/targeting.js";
const VISUAL_TOP_INCREMENT = 0.08;
const VISUAL_TOP_CAP = 0.4;
export default {
key: "basic",
buildHead(tower) {
const headGeo = new THREE.BoxGeometry(0.8, 0.4, 0.8);
const headMat = new THREE.MeshStandardMaterial({
color: 0x90caf9,
metalness: 0.18,
roughness: 0.45,
emissive: 0x000000,
emissiveIntensity: 0.6,
side: THREE.DoubleSide,
});
const head = new THREE.Mesh(headGeo, headMat);
head.castShadow = true;
head.position.set(0, 0.8, 0);
tower.baseMesh.add(head);
tower.headMesh = head;
tower.head = head;
tower.headTopY = tower.mesh.position.y + head.position.y + 0.4;
},
tryFire(tower, dt, enemies, projectiles, projectileSpeed) {
tower.fireCooldown -= dt;
if (tower.fireCooldown > 0) return;
const target = findNearestWithinRange(tower, enemies);
if (!target) return;
const dir = new THREE.Vector3().subVectors(
target.mesh.position,
tower.position
);
const yaw = Math.atan2(dir.x, dir.z);
tower.mesh.rotation.y = yaw;
tower.fireCooldown = 1 / tower.rate;
const spawnY =
typeof tower.headTopY === "number" ? tower.headTopY - 0.1 : 0.9;
const proj = new Projectile(
tower.position.clone().add(new THREE.Vector3(0, spawnY, 0)),
target,
projectileSpeed,
tower.scene,
tower.projectileEffect || null
);
proj.damage = tower.damage;
projectiles.push(proj);
tower.playShootSound();
},
applyVisualLevel(tower) {
const lvl = tower.level;
const head = tower.headMesh;
if (!head) return;
const baseMat = tower.baseMesh?.material;
const headMat = head.material;
if (tower.levelRing) {
tower.scene.remove(tower.levelRing);
tower.levelRing.geometry.dispose();
if (tower.levelRing.material?.dispose) tower.levelRing.material.dispose();
tower.levelRing = null;
}
// No height increment on level gain — only rings should reflect level
if (lvl <= 1) {
if (baseMat) {
baseMat.color?.set?.(0x5c6bc0);
baseMat.emissive?.set?.(0x000000);
baseMat.emissiveIntensity = 0.0;
}
// Keep original head height/position; recompute top using current head position
tower.headTopY = (tower.mesh?.position.y ?? 0.25) + head.position.y + 0.4;
headMat.color?.set?.(0x90caf9);
headMat.emissive?.set?.(0x4a0a2a);
headMat.emissiveIntensity = 0.2;
} else {
if (baseMat) {
baseMat.color?.set?.(0x6f7bd6);
baseMat.emissive?.set?.(0x2a0a1a);
baseMat.emissiveIntensity = 0.08;
}
// Keep original head height/position; recompute top using current head position
tower.headTopY = (tower.mesh?.position.y ?? 0.25) + head.position.y + 0.4;
headMat.color?.set?.(0xa5d6ff);
headMat.emissive?.set?.(0x9a135a);
headMat.emissiveIntensity = 0.35;
const ringGeom = new THREE.TorusGeometry(0.45, 0.035, 8, 24);
const ringMat = new THREE.MeshStandardMaterial({
color: 0x3aa6ff,
emissive: 0xe01a6b,
emissiveIntensity: 0.55,
metalness: 0.3,
roughness: 0.45,
});
const ring = new THREE.Mesh(ringGeom, ringMat);
ring.castShadow = false;
ring.receiveShadow = false;
const topY = tower.headTopY ?? head.position.y + 0.8;
ring.position.set(
tower.mesh.position.x,
topY + 0.02,
tower.mesh.position.z
);
ring.rotation.x = Math.PI / 2;
ring.name = "tower_level_ring";
tower.levelRing = ring;
tower.scene.add(ring);
}
},
};
|