Implement advanced pathfinding and combat visual effects
- Add monster turn visual feedback (green ring on attacker, red ring on victim) - Implement proper attack sequence with timing and animations - Add room boundary and height level pathfinding system - Monsters now respect room walls and can only pass through doors - Add height level support (1-8) with stairs (9) for level transitions - Fix attack validation to prevent attacks through walls - Speed up hero movement animation (300ms per tile) - Fix exploration phase message to not show on initial tile placement - Disable hero movement during exploration phase (doors only)
This commit is contained in:
@@ -217,6 +217,79 @@ export class GameRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
setEntityActive(entityId, isActive) {
|
||||
const mesh = this.entities.get(entityId);
|
||||
if (!mesh) return;
|
||||
|
||||
// Remove existing active ring if any
|
||||
const oldRing = mesh.getObjectByName("ActiveRing");
|
||||
if (oldRing) mesh.remove(oldRing);
|
||||
|
||||
if (isActive) {
|
||||
// Phosphorescent Green Ring - MATCHING SIZE (0.3 - 0.4)
|
||||
const ringGeom = new THREE.RingGeometry(0.3, 0.4, 32);
|
||||
|
||||
// Basic Material does not support emissive. Use color + opacity for "glow" feel.
|
||||
const ringMat = new THREE.MeshBasicMaterial({
|
||||
color: 0x00ff00, // Green
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
opacity: 0.8
|
||||
});
|
||||
|
||||
const ring = new THREE.Mesh(ringGeom, ringMat);
|
||||
ring.rotation.x = -Math.PI / 2;
|
||||
|
||||
// Align with floor (relative to mesh center)
|
||||
const h = 1.56;
|
||||
ring.position.y = -h / 2 + 0.05;
|
||||
|
||||
ring.name = "ActiveRing";
|
||||
mesh.add(ring);
|
||||
}
|
||||
}
|
||||
|
||||
triggerDamageEffect(entityId) {
|
||||
const mesh = this.entities.get(entityId);
|
||||
if (!mesh) return;
|
||||
|
||||
// 1. Red Halo (Temporary) - MATCHING ATTACKER SIZE (0.3 - 0.4)
|
||||
const hitRingGeom = new THREE.RingGeometry(0.3, 0.4, 32);
|
||||
const hitRingMat = new THREE.MeshBasicMaterial({
|
||||
color: 0xff0000,
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
opacity: 0.9
|
||||
});
|
||||
const hitRing = new THREE.Mesh(hitRingGeom, hitRingMat);
|
||||
hitRing.rotation.x = -Math.PI / 2;
|
||||
|
||||
// Align with floor
|
||||
const h = 1.56;
|
||||
hitRing.position.y = -h / 2 + 0.05;
|
||||
|
||||
hitRing.name = "HitRing";
|
||||
|
||||
mesh.add(hitRing);
|
||||
|
||||
// Remove Red Halo after 1200ms (matching the timing in MonsterAI)
|
||||
setTimeout(() => {
|
||||
if (mesh && hitRing) mesh.remove(hitRing);
|
||||
}, 1200);
|
||||
|
||||
// 2. Shake Animation (800ms)
|
||||
const originalPos = mesh.position.clone();
|
||||
const startTime = performance.now();
|
||||
const duration = 800; // ms
|
||||
|
||||
mesh.userData.shake = {
|
||||
startTime: startTime,
|
||||
duration: duration,
|
||||
magnitude: 0.1,
|
||||
originalPos: originalPos
|
||||
};
|
||||
}
|
||||
|
||||
moveEntityAlongPath(entity, path) {
|
||||
const mesh = this.entities.get(entity.id);
|
||||
if (mesh) {
|
||||
@@ -249,7 +322,7 @@ export class GameRenderer {
|
||||
}
|
||||
|
||||
if (data.isMoving) {
|
||||
const duration = 300; // Faster jump (300ms)
|
||||
const duration = 300; // Hero movement speed (300ms per tile)
|
||||
const elapsed = time - data.startTime;
|
||||
const progress = Math.min(elapsed / duration, 1);
|
||||
|
||||
@@ -278,6 +351,25 @@ export class GameRenderer {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (data.shake) {
|
||||
// HANDLE SHAKE
|
||||
const elapsed = time - data.shake.startTime;
|
||||
if (elapsed < data.shake.duration) {
|
||||
const progress = elapsed / data.shake.duration;
|
||||
// Dampen over time
|
||||
const mag = data.shake.magnitude * (1 - progress);
|
||||
|
||||
// Random jitter
|
||||
const offsetX = (Math.random() - 0.5) * mag * 2;
|
||||
const offsetZ = (Math.random() - 0.5) * mag * 2;
|
||||
|
||||
mesh.position.x = data.shake.originalPos.x + offsetX;
|
||||
mesh.position.z = data.shake.originalPos.z + offsetZ;
|
||||
} else {
|
||||
// Reset
|
||||
mesh.position.copy(data.shake.originalPos);
|
||||
delete data.shake;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user