102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
import * as THREE from 'three';
|
|
import type { Game } from './Game';
|
|
import { auraRadius, auraDamage, auraPush } from './Skills';
|
|
|
|
const TICK = 0.5;
|
|
|
|
export class Aura {
|
|
private group: THREE.Group;
|
|
private fill: THREE.Mesh;
|
|
private ring: THREE.Mesh;
|
|
private tickTimer = 0;
|
|
private pulse = 0;
|
|
|
|
constructor(scene: THREE.Scene) {
|
|
this.group = new THREE.Group();
|
|
|
|
this.fill = new THREE.Mesh(
|
|
new THREE.CircleGeometry(1, 48),
|
|
new THREE.MeshBasicMaterial({
|
|
color: 0x66ccff,
|
|
transparent: true,
|
|
opacity: 0.12,
|
|
depthWrite: false,
|
|
})
|
|
);
|
|
this.fill.rotation.x = -Math.PI / 2;
|
|
this.fill.position.y = 0.05;
|
|
this.fill.renderOrder = 998;
|
|
this.group.add(this.fill);
|
|
|
|
this.ring = new THREE.Mesh(
|
|
new THREE.RingGeometry(0.93, 1, 48),
|
|
new THREE.MeshBasicMaterial({
|
|
color: 0x88ddff,
|
|
transparent: true,
|
|
opacity: 0.5,
|
|
side: THREE.DoubleSide,
|
|
depthWrite: false,
|
|
})
|
|
);
|
|
this.ring.rotation.x = -Math.PI / 2;
|
|
this.ring.position.y = 0.06;
|
|
this.ring.renderOrder = 999;
|
|
this.group.add(this.ring);
|
|
|
|
scene.add(this.group);
|
|
}
|
|
|
|
update(dt: number, game: Game) {
|
|
const level = game.skillSystem.getLevel('aura');
|
|
if (level <= 0) return;
|
|
|
|
const radius = auraRadius(level);
|
|
this.group.position.x = game.player.body.position.x;
|
|
this.group.position.z = game.player.body.position.z;
|
|
this.group.scale.setScalar(radius);
|
|
|
|
if (this.pulse > 0) {
|
|
this.pulse -= dt * 2.5;
|
|
const p = Math.max(0, this.pulse);
|
|
const s = 1 + p * 0.12;
|
|
this.fill.scale.setScalar(s);
|
|
this.ring.scale.setScalar(s);
|
|
(this.ring.material as THREE.MeshBasicMaterial).opacity = 0.5 + p * 0.4;
|
|
}
|
|
|
|
this.tickTimer -= dt;
|
|
if (this.tickTimer > 0) return;
|
|
this.tickTimer = TICK;
|
|
|
|
const damage = auraDamage(level);
|
|
const push = auraPush(level);
|
|
const center = game.player.body.position;
|
|
for (const enemy of game.enemies) {
|
|
if (enemy.dead) continue;
|
|
const dist = enemy.body.position.distanceTo(center);
|
|
if (dist > radius + 0.4) continue;
|
|
enemy.takeDamage(damage, game, false, center);
|
|
// Stationaere Gegner (Bosse, Tuerme) werden nur geschaedigt, nicht geschoben
|
|
if (enemy.immovable) continue;
|
|
const dir = new THREE.Vector3()
|
|
.subVectors(enemy.body.position, center);
|
|
dir.y = 0;
|
|
if (dir.lengthSq() < 0.01) {
|
|
dir.set(Math.random() - 0.5, 0, Math.random() - 0.5);
|
|
}
|
|
dir.normalize();
|
|
enemy.body.position.addScaledVector(dir, push);
|
|
game.clampToArena(enemy.body.position);
|
|
}
|
|
this.pulse = 1;
|
|
}
|
|
|
|
dispose(scene: THREE.Scene) {
|
|
scene.remove(this.group);
|
|
this.fill.geometry.dispose();
|
|
(this.fill.material as THREE.Material).dispose();
|
|
this.ring.geometry.dispose();
|
|
(this.ring.material as THREE.Material).dispose();
|
|
}
|
|
}
|