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(); } }