Spaces:
Sleeping
Sleeping
File size: 3,620 Bytes
565f6e7 | 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 | import { WeaponType, Pilot } from "../../types";
import { getTerrainHeight } from "../terrainModel";
import { Vector3 } from "three";
import { getPlaneHitRadius } from "../math";
export class ProjectileSystem {
public updateProjectiles(
projectiles: any[],
dt: number,
mapId: string,
pilots: Map<string, Pilot>,
triggerSplashDamage: (pos: Vector3, ownerId: string, team: number, type: WeaponType) => void,
applyDamage: (pilot: Pilot, amount: number, hitZone: string, weapon: string, ownerId: string) => void
) {
for (let i = projectiles.length - 1; i >= 0; i--) {
const p = projectiles[i];
p.life -= dt;
if (p.life <= 0) {
if (p.isRocket || p.type === WeaponType.BOMB) {
triggerSplashDamage(new Vector3(p.x, p.y, p.z), p.ownerId, p.ownerTeam, p.type as WeaponType);
}
projectiles.splice(i, 1);
continue;
}
const p0x = p.x; const p0y = p.y; const p0z = p.z;
if (p.isRocket || p.type === WeaponType.BOMB) {
p.vy -= 9.8 * dt; // gravity
}
p.x += p.vx * dt;
p.y += p.vy * dt;
p.z += p.vz * dt;
// Terrain collision
const terr = getTerrainHeight(p.x, p.z, mapId);
if (p.y <= terr.height) {
if (p.isRocket || p.type === WeaponType.BOMB) {
triggerSplashDamage(new Vector3(p.x, terr.height, p.z), p.ownerId, p.ownerTeam, p.type as WeaponType);
}
projectiles.splice(i, 1);
continue;
}
// Fast Raycast against planes
let hit = false;
const moveVec = new Vector3(p.x - p0x, p.y - p0y, p.z - p0z);
const moveDist = moveVec.length();
const moveDir = moveVec.clone().normalize();
for (const targetPilot of pilots.values()) {
if (targetPilot.team === p.ownerTeam) continue;
if ((targetPilot.entity.components.get("destructible") as any).isDead) continue;
if (targetPilot.invulnerableTimer && targetPilot.invulnerableTimer > 0) continue;
const targetPos = new Vector3(targetPilot.x, targetPilot.y, targetPilot.z);
const p0Vec = new Vector3(p0x, p0y, p0z);
const toTarget = targetPos.clone().sub(p0Vec);
const dot = toTarget.dot(moveDir);
if (dot < 0 || dot > moveDist) continue;
const closestPoint = p0Vec.clone().add(moveDir.clone().multiplyScalar(dot));
const distToCenter = closestPoint.distanceTo(targetPos);
const hitRadius = getPlaneHitRadius(targetPilot.specs);
if (distToCenter <= hitRadius) {
if (p.isRocket || p.type === WeaponType.BOMB) {
triggerSplashDamage(closestPoint, p.ownerId, p.ownerTeam, p.type as WeaponType);
} else {
const localHit = closestPoint.clone().sub(targetPos);
const relativeOffset = localHit.clone().divideScalar(hitRadius);
// Belt multiplier
let dmgMult = 1.0;
if (p.belt === "Armor-Piercing") dmgMult = 1.25;
if (p.belt === "High-Explosive") dmgMult = 1.4;
applyDamage(targetPilot, dmgMult, this.determineHitZone(relativeOffset), p.type, p.ownerId);
}
projectiles.splice(i, 1);
hit = true;
break;
}
}
if (hit) continue;
}
}
private determineHitZone(spot: Vector3) {
if (spot.z > 0.4) return "engine";
if (spot.z < -0.5) return "tail";
if (Math.abs(spot.x) > 0.28) return spot.x < 0 ? "leftWing" : "rightWing";
if (spot.y > 0.4) return "cockpit";
if (spot.y < -0.3) return "fuelTank";
return "fuselage";
}
}
|