mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
Add wall escape functionality for NPCs: implement checks and escape logic for NPCs stuck in walls, enhancing collision handling and movement responsiveness.
This commit is contained in:
@@ -179,6 +179,14 @@ class NPCBehavior {
|
||||
this.homeReturnThreshold = 32; // Distance in pixels before returning home
|
||||
this.returningHome = false;
|
||||
|
||||
// Wall collision escape tracking
|
||||
// When NPCs get pushed through walls, they can get unstuck
|
||||
this.stuckInWall = false;
|
||||
this.unstuckAttempts = 0;
|
||||
this.lastUnstuckCheck = 0;
|
||||
this.unstuckCheckInterval = 200; // Check for stuck every 200ms
|
||||
this.escapeWallBox = null; // Reference to the wall we're escaping from
|
||||
|
||||
// Apply initial hostile visual if needed
|
||||
if (this.hostile) {
|
||||
this.setHostile(true);
|
||||
@@ -454,6 +462,9 @@ class NPCBehavior {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if NPC is stuck in a wall and needs to escape
|
||||
this.checkAndEscapeWall(time);
|
||||
|
||||
// Check if NPC has been pushed from home position (for stationary NPCs)
|
||||
this.checkAndHandleHomePush();
|
||||
|
||||
@@ -571,6 +582,11 @@ class NPCBehavior {
|
||||
updatePatrol(time, delta) {
|
||||
if (!this.config.patrol.enabled) return;
|
||||
|
||||
// If we just finished returning home, don't continue patrol
|
||||
if (this.returningHome && !this.config.patrol.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if path needs recalculation (e.g., after NPC-to-NPC collision avoidance)
|
||||
if (this._needsPathRecalc && this.patrolTarget) {
|
||||
this._needsPathRecalc = false;
|
||||
@@ -680,6 +696,11 @@ class NPCBehavior {
|
||||
}
|
||||
|
||||
chooseNewPatrolTarget(time) {
|
||||
// Don't choose new targets if we just disabled patrol (e.g., finished returning home)
|
||||
if (!this.config.patrol.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if using waypoint patrol
|
||||
if (this.config.patrol.waypoints && this.config.patrol.waypoints.length > 0) {
|
||||
this.chooseWaypointTarget(time);
|
||||
@@ -1096,6 +1117,97 @@ class NPCBehavior {
|
||||
this.sprite.setDepth(depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if NPC is stuck in a wall and attempt to escape
|
||||
* When an NPC gets pushed through a wall collision box, this detects it
|
||||
* and gradually pushes the NPC back out to freedom
|
||||
*/
|
||||
checkAndEscapeWall(time) {
|
||||
// Only check periodically to avoid performance issues
|
||||
if (time - this.lastUnstuckCheck < this.unstuckCheckInterval) {
|
||||
if (!this.stuckInWall) {
|
||||
return; // Not stuck, no need to escape
|
||||
}
|
||||
// Continue trying to escape if already stuck
|
||||
} else {
|
||||
this.lastUnstuckCheck = time;
|
||||
}
|
||||
|
||||
const room = window.rooms ? window.rooms[this.roomId] : null;
|
||||
if (!room || !room.wallCollisionBoxes) {
|
||||
return; // No walls to check
|
||||
}
|
||||
|
||||
// Check if NPC is overlapping with any wall collision box
|
||||
let isOverlappingWall = false;
|
||||
let overlappingWall = null;
|
||||
|
||||
for (const wallBox of room.wallCollisionBoxes) {
|
||||
if (!wallBox.body) continue;
|
||||
|
||||
// Check if NPC body overlaps with wall using scene physics
|
||||
if (this.scene.physics.overlap(this.sprite, wallBox)) {
|
||||
isOverlappingWall = true;
|
||||
overlappingWall = wallBox;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isOverlappingWall && overlappingWall) {
|
||||
// NPC is stuck! Try to escape
|
||||
if (!this.stuckInWall) {
|
||||
console.log(`🚨 [${this.npcId}] Detected stuck in wall at (${this.sprite.x.toFixed(0)}, ${this.sprite.y.toFixed(0)})`);
|
||||
this.stuckInWall = true;
|
||||
this.unstuckAttempts = 0;
|
||||
this.escapeWallBox = overlappingWall; // Remember which wall we're escaping from
|
||||
}
|
||||
|
||||
this.unstuckAttempts++;
|
||||
|
||||
// Push NPC away from wall center
|
||||
const wallCenterX = overlappingWall.body.center.x;
|
||||
const wallCenterY = overlappingWall.body.center.y;
|
||||
|
||||
const dx = this.sprite.x - wallCenterX;
|
||||
const dy = this.sprite.y - wallCenterY;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance > 0.1) {
|
||||
// Normalize and apply escape velocity - very forceful to break free quickly
|
||||
const escapeSpeed = 300; // Pixels per second (increased from 200)
|
||||
const escapeX = (dx / distance) * escapeSpeed;
|
||||
const escapeY = (dy / distance) * escapeSpeed;
|
||||
|
||||
this.sprite.body.setVelocity(escapeX, escapeY);
|
||||
}
|
||||
|
||||
// Stop trying after 50 attempts (~10 seconds at 200ms intervals)
|
||||
if (this.unstuckAttempts > 50) {
|
||||
console.warn(`⚠️ [${this.npcId}] Failed to escape wall after ${this.unstuckAttempts} attempts, giving up`);
|
||||
this.stuckInWall = false;
|
||||
this.unstuckAttempts = 0;
|
||||
this.escapeWallBox = null;
|
||||
this.sprite.body.setVelocity(0, 0);
|
||||
}
|
||||
} else {
|
||||
// Check if we've actually escaped
|
||||
if (this.stuckInWall && this.escapeWallBox) {
|
||||
// If overlap has cleared, consider it escaped
|
||||
if (this.scene.physics.overlap(this.sprite, this.escapeWallBox)) {
|
||||
// Still stuck in the wall, keep trying
|
||||
return;
|
||||
}
|
||||
|
||||
// Not overlapping anymore - escaped!
|
||||
console.log(`✅ [${this.npcId}] Escaped from wall after ${this.unstuckAttempts} attempts`);
|
||||
this.stuckInWall = false;
|
||||
this.unstuckAttempts = 0;
|
||||
this.escapeWallBox = null;
|
||||
this.sprite.body.setVelocity(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if NPC has been pushed away from home and trigger return if needed
|
||||
* For stationary NPCs (no patrol configured), automatically return home if pushed
|
||||
@@ -1122,6 +1234,8 @@ class NPCBehavior {
|
||||
this.patrolTarget = null;
|
||||
this.currentPath = [];
|
||||
this.pathIndex = 0;
|
||||
// IMPORTANT: Set velocity to 0 to stop movement
|
||||
this.sprite.body.setVelocity(0, 0);
|
||||
return false;
|
||||
}
|
||||
return true; // Still returning
|
||||
|
||||
Reference in New Issue
Block a user