tower-defense / src /entities /Projectile.js
victor's picture
victor HF Staff
Initial commit
b29710c
import * as THREE from "three";
export class Projectile {
constructor(pos, target, speed, scene, projectileEffect = null) {
this.position = pos.clone();
this.target = target;
this.speed = speed;
this.scene = scene;
this.damage = 0; // Will be set by tower
this.projectileEffect = projectileEffect;
const geo = new THREE.SphereGeometry(0.15, 8, 8);
const mat = new THREE.MeshStandardMaterial({
color:
projectileEffect && projectileEffect.color
? projectileEffect.color
: 0xffe082,
emissive:
projectileEffect && projectileEffect.emissive
? projectileEffect.emissive
: 0x553300,
});
const mesh = new THREE.Mesh(geo, mat);
mesh.castShadow = true;
mesh.position.copy(this.position);
this.mesh = mesh;
scene.add(mesh);
this.alive = true;
}
update(dt, spawnHitEffect) {
if (!this.alive) return "dead";
if (!this.target || this.target.isDead()) {
this.alive = false;
return "dead";
}
const toTarget = new THREE.Vector3().subVectors(
this.target.mesh.position,
this.position
);
const dist = toTarget.length();
if (dist < 0.4) {
this.target.takeDamage(this.damage);
// Apply on-hit effect if any
if (
this.projectileEffect &&
this.projectileEffect.type === "slow" &&
this.target.applySlow
) {
const mult = this.projectileEffect.mult ?? 1.0;
const duration = this.projectileEffect.duration ?? 0;
this.target.applySlow(mult, duration);
}
spawnHitEffect(this.position);
this.alive = false;
return "hit";
}
toTarget.normalize();
this.position.addScaledVector(toTarget, this.speed * dt);
this.mesh.position.copy(this.position);
return "ok";
}
destroy() {
this.scene.remove(this.mesh);
}
}