mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
Refactor player and room depth management: Simplify depth calculations for player and room elements by using world Y position plus layer offsets. Update door sprite depth settings for consistency and improve door transition detection logic. Enhance comments for clarity and maintainability across the codebase.
This commit is contained in:
@@ -150,21 +150,11 @@ export function movePlayerToPoint(x, y) {
|
||||
}
|
||||
|
||||
function updatePlayerDepth(x, y) {
|
||||
// Calculate dynamic depth based on Y position
|
||||
// This creates the effect where player appears behind objects when north of them
|
||||
// and in front when south of them
|
||||
|
||||
// Get the bottom of the player sprite (feet position)
|
||||
// Since player origin is at center, bottom is y + half the scaled height
|
||||
const playerBottomY = y + (player.height * player.scaleY) / 2;
|
||||
|
||||
// Calculate room depth based on player position with finer granularity
|
||||
// Use 50-pixel boundaries instead of 100 for smoother depth transitions
|
||||
const roomDepth = Math.floor(playerBottomY / 50) * 50;
|
||||
|
||||
// Player should use the same depth calculation as objects for proper layering
|
||||
// This allows player and objects to layer relative to each other based on Y position
|
||||
const playerDepth = roomDepth + 500; // Same as objects - above all room layers
|
||||
// Simple depth calculation: world Y position + layer offset
|
||||
const playerDepth = playerBottomY + 0.5; // World Y + sprite layer offset
|
||||
|
||||
// Set the player depth (always update, no threshold)
|
||||
if (player) {
|
||||
@@ -173,9 +163,8 @@ function updatePlayerDepth(x, y) {
|
||||
// Debug logging - only show when depth actually changes significantly
|
||||
const lastDepth = player.lastDepth || 0;
|
||||
if (Math.abs(playerDepth - lastDepth) > 25) { // Reduced threshold for finer granularity
|
||||
console.log(`Player depth: ${playerDepth} (Y: ${y}, BottomY: ${playerBottomY}, RoomDepth: ${roomDepth})`);
|
||||
console.log(` Player uses same depth calculation as objects: roomDepth + 500`);
|
||||
console.log(` Room layer depths: floor=${roomDepth + 100}, collision=${roomDepth + 150}, walls=${roomDepth + 200}, props=${roomDepth + 300}, other=${roomDepth + 400}`);
|
||||
console.log(`Player depth: ${playerDepth} (World Y: ${playerBottomY})`);
|
||||
console.log(` Player layers: worldY(${playerBottomY}) + 0.5`);
|
||||
player.lastDepth = playerDepth;
|
||||
}
|
||||
}
|
||||
|
||||
239
js/core/rooms.js
239
js/core/rooms.js
@@ -1,3 +1,46 @@
|
||||
/**
|
||||
* ROOM MANAGEMENT SYSTEM - SIMPLIFIED DEPTH LAYERING APPROACH
|
||||
* ===========================================================
|
||||
*
|
||||
* This system implements a simplified depth-based layering approach where all elements
|
||||
* use their world Y position + layer offset for depth calculation.
|
||||
*
|
||||
* DEPTH CALCULATION PHILOSOPHY:
|
||||
* -----------------------------
|
||||
* 1. **World Y Position**: All depth calculations are based on the world Y position
|
||||
* of the element (bottom of sprites, room ground level).
|
||||
*
|
||||
* 2. **Layer Offsets**: Each element type has a fixed layer offset added to its Y position
|
||||
* to create proper layering hierarchy.
|
||||
*
|
||||
* 3. **Room Y Offset**: Room Y position is considered to be 2 tiles south of the actual
|
||||
* room position (where door sprites are positioned).
|
||||
*
|
||||
* DEPTH HIERARCHY:
|
||||
* ----------------
|
||||
* Room Layers (world Y + layer offset):
|
||||
* - Floor: roomWorldY + 0.1
|
||||
* - Collision: roomWorldY + 0.15
|
||||
* - Walls: roomWorldY + 0.2
|
||||
* - Props: roomWorldY + 0.3
|
||||
* - Other: roomWorldY + 0.4
|
||||
*
|
||||
* Interactive Elements (world Y + layer offset):
|
||||
* - Doors: doorY + 0.45 (between room tiles and sprites)
|
||||
* - Door Tops: doorY + 0.55 (above doors, below sprites)
|
||||
* - Animated Doors: doorBottomY + 0.45 (bottom Y + door layer offset)
|
||||
* - Animated Door Tops: doorBottomY + 0.55 (bottom Y + door top layer offset)
|
||||
* - Player: playerBottomY + 0.5 (dynamic based on Y position)
|
||||
* - Objects: objectBottomY + 0.5 (dynamic based on Y position)
|
||||
*
|
||||
* DEPTH CALCULATION CONSISTENCY:
|
||||
* ------------------------------
|
||||
* ✅ All elements use world Y position + layer offset
|
||||
* ✅ Room Y is 2 tiles south of room position
|
||||
* ✅ Player and objects use bottom Y position
|
||||
* ✅ Simple and consistent across all elements
|
||||
*/
|
||||
|
||||
// Room management system
|
||||
import { TILE_SIZE, DOOR_ALIGN_OVERLAP, GRID_SIZE, INTERACTION_RANGE_SQ, INTERACTION_CHECK_INTERVAL } from '../utils/constants.js?v=7';
|
||||
|
||||
@@ -9,6 +52,10 @@ export let discoveredRooms = new Set();
|
||||
window.discoveredRooms = discoveredRooms;
|
||||
let gameRef = null;
|
||||
|
||||
// Door transition cooldown system
|
||||
let lastDoorTransitionTime = 0;
|
||||
const DOOR_TRANSITION_COOLDOWN = 1000; // 1 second cooldown between transitions
|
||||
|
||||
// Helper function to check if two rectangles overlap
|
||||
function boundsOverlap(rect1, rect2) {
|
||||
return rect1.x < rect2.x + rect2.width &&
|
||||
@@ -186,7 +233,7 @@ function createDoorSpritesForRoom(roomId, position) {
|
||||
doorSprite = graphics;
|
||||
}
|
||||
doorSprite.setOrigin(0.5, 0.5);
|
||||
doorSprite.setDepth(position.y * 100 + 1000); // Much higher depth to render on top
|
||||
doorSprite.setDepth(doorY + 0.45); // World Y + door layer offset
|
||||
doorSprite.setAlpha(1); // Visible by default
|
||||
doorSprite.setVisible(true); // Ensure visibility
|
||||
|
||||
@@ -202,7 +249,7 @@ function createDoorSpritesForRoom(roomId, position) {
|
||||
displayWidth: doorSprite.displayWidth,
|
||||
displayHeight: doorSprite.displayHeight
|
||||
});
|
||||
console.log(`Door depth: ${doorSprite.depth} (roomDepth: ${position.y * 100}, should be above all layers)`);
|
||||
console.log(`Door depth: ${doorSprite.depth} (roomDepth: ${doorY}, between tiles and sprites)`);
|
||||
|
||||
// Set up door properties
|
||||
doorSprite.doorProperties = {
|
||||
@@ -217,6 +264,13 @@ function createDoorSpritesForRoom(roomId, position) {
|
||||
requires: roomData.requires || null
|
||||
};
|
||||
|
||||
// Set up door info for transition detection
|
||||
doorSprite.doorInfo = {
|
||||
roomId: roomId,
|
||||
connectedRoom: connectedRoom,
|
||||
direction: direction
|
||||
};
|
||||
|
||||
// Set up collision
|
||||
gameRef.physics.add.existing(doorSprite);
|
||||
doorSprite.body.setSize(doorWidth, doorHeight);
|
||||
@@ -477,9 +531,12 @@ function createAnimatedDoorOnOppositeSide(roomId, fromRoomId, direction, doorWor
|
||||
// Create main door sprite
|
||||
animatedDoorSprite = gameRef.add.sprite(doorX, doorY, 'door_sheet');
|
||||
|
||||
// Calculate the bottom of the door (where it meets the ground)
|
||||
const doorBottomY = doorY + (TILE_SIZE * 2) / 2; // doorY is center, so add half height to get bottom
|
||||
|
||||
// Set sprite properties
|
||||
animatedDoorSprite.setOrigin(0.5, 0.5);
|
||||
animatedDoorSprite.setDepth(roomPosition.y * 100 + 1000);
|
||||
animatedDoorSprite.setDepth(doorBottomY + 0.45); // Bottom Y + door layer offset
|
||||
animatedDoorSprite.setVisible(true);
|
||||
|
||||
// Play the opening animation
|
||||
@@ -488,7 +545,7 @@ function createAnimatedDoorOnOppositeSide(roomId, fromRoomId, direction, doorWor
|
||||
// Create door top sprite (6th frame) at high z-index
|
||||
doorTopSprite = gameRef.add.sprite(doorX, doorY, 'door_sheet');
|
||||
doorTopSprite.setOrigin(0.5, 0.5);
|
||||
doorTopSprite.setDepth(roomPosition.y * 100 + 2000); // Higher z-index than main door
|
||||
doorTopSprite.setDepth(doorBottomY + 0.55); // Bottom Y + door top layer offset
|
||||
doorTopSprite.setVisible(true);
|
||||
doorTopSprite.play('door_top');
|
||||
|
||||
@@ -508,7 +565,10 @@ function createAnimatedDoorOnOppositeSide(roomId, fromRoomId, direction, doorWor
|
||||
graphics.fillStyle(0x00ff00, 1); // Green color for open door
|
||||
graphics.fillRect(-doorWidth/2, -doorHeight/2, doorWidth, doorHeight);
|
||||
graphics.setPosition(doorX, doorY);
|
||||
graphics.setDepth(roomPosition.y * 100 + 1000);
|
||||
|
||||
// Calculate the bottom of the door (where it meets the ground)
|
||||
const doorBottomY = doorY + (TILE_SIZE * 2) / 2; // doorY is center, so add half height to get bottom
|
||||
graphics.setDepth(doorBottomY + 0.45); // Bottom Y + door layer offset
|
||||
|
||||
if (!room.animatedDoors) {
|
||||
room.animatedDoors = [];
|
||||
@@ -1301,7 +1361,8 @@ export function createRoom(roomId, roomData, position) {
|
||||
if (!window.globalLayerCounter) window.globalLayerCounter = 0;
|
||||
|
||||
// Calculate base depth for this room's layers
|
||||
const roomDepth = position.y * 100;
|
||||
// Use world Y position + layer offset (room Y is 2 tiles south of actual room position)
|
||||
const roomWorldY = position.y + TILE_SIZE * 2; // Room Y is 2 tiles south of room position
|
||||
|
||||
// Create door sprites based on gameScenario connections
|
||||
const doorSprites = createDoorSpritesForRoom(roomId, position);
|
||||
@@ -1336,11 +1397,11 @@ export function createRoom(roomId, roomData, position) {
|
||||
|
||||
// Set depth based on layer type and room position
|
||||
if (layerData.name.toLowerCase().includes('floor')) {
|
||||
layer.setDepth(roomDepth + 100);
|
||||
console.log(`Floor layer depth: ${roomDepth + 100}`);
|
||||
layer.setDepth(roomWorldY + 0.1);
|
||||
console.log(`Floor layer depth: ${roomWorldY + 0.1}`);
|
||||
} else if (layerData.name.toLowerCase().includes('walls')) {
|
||||
layer.setDepth(roomDepth + 200);
|
||||
console.log(`Wall layer depth: ${roomDepth + 200}`);
|
||||
layer.setDepth(roomWorldY + 0.2);
|
||||
console.log(`Wall layer depth: ${roomWorldY + 0.2}`);
|
||||
|
||||
// Remove wall tiles under doors
|
||||
removeTilesUnderDoor(layer, roomId, position);
|
||||
@@ -1363,8 +1424,8 @@ export function createRoom(roomId, roomData, position) {
|
||||
console.warn(`Error setting up collisions for ${uniqueLayerId}:`, e);
|
||||
}
|
||||
} else if (layerData.name.toLowerCase().includes('collision')) {
|
||||
layer.setDepth(roomDepth + 150);
|
||||
console.log(`Collision layer depth: ${roomDepth + 150}`);
|
||||
layer.setDepth(roomWorldY + 0.15);
|
||||
console.log(`Collision layer depth: ${roomWorldY + 0.15}`);
|
||||
|
||||
// Set up collision layer
|
||||
try {
|
||||
@@ -1381,11 +1442,12 @@ export function createRoom(roomId, roomData, position) {
|
||||
console.warn(`Error setting up collision layer ${uniqueLayerId}:`, e);
|
||||
}
|
||||
} else if (layerData.name.toLowerCase().includes('props')) {
|
||||
layer.setDepth(roomDepth + 300);
|
||||
console.log(`Props layer depth: ${roomDepth + 300}`);
|
||||
layer.setDepth(roomWorldY + 0.3);
|
||||
console.log(`Props layer depth: ${roomWorldY + 0.3}`);
|
||||
} else {
|
||||
layer.setDepth(roomDepth + 400);
|
||||
console.log(`Other layer depth: ${roomDepth + 400}`);
|
||||
// Other layers (decorations, etc.)
|
||||
layer.setDepth(roomWorldY + 0.4);
|
||||
console.log(`Other layer depth: ${roomWorldY + 0.4}`);
|
||||
}
|
||||
|
||||
layers[uniqueLayerId] = layer;
|
||||
@@ -1505,16 +1567,15 @@ export function createRoom(roomId, roomData, position) {
|
||||
sprite.objectId = objectId; // Use our simplified ID format
|
||||
sprite.setInteractive({ useHandCursor: true });
|
||||
|
||||
// Set dynamic depth based on the bottom of the object sprite for proper layering
|
||||
// Set dynamic depth based on world Y position + layer offset
|
||||
const objectBottomY = sprite.y + (sprite.height * sprite.scaleY); // Bottom of the sprite
|
||||
const roomDepth = Math.floor(objectBottomY / 100) * 100;
|
||||
const objectDepth = roomDepth + 500; // Objects above all room tiles (floor:100, collision:150, walls:200, props:300, other:400)
|
||||
const objectDepth = objectBottomY + 0.5; // World Y + sprite layer offset
|
||||
sprite.setDepth(objectDepth);
|
||||
|
||||
// Debug logging with more detail
|
||||
console.log(`Object ${objectId} depth: ${objectDepth} (Y: ${sprite.y}, BottomY: ${objectBottomY}, RoomDepth: ${roomDepth})`);
|
||||
console.log(`Object ${objectId} depth: ${objectDepth} (World Y: ${objectBottomY})`);
|
||||
console.log(` Room position: (${position.x}, ${position.y}), Object world position: (${sprite.x}, ${sprite.y})`);
|
||||
console.log(` Object should be above room tiles (max depth: ${roomDepth + 400})`);
|
||||
console.log(` Object layers: worldY(${objectBottomY}) + 0.5`);
|
||||
|
||||
sprite.originalAlpha = 1;
|
||||
sprite.active = true;
|
||||
@@ -1589,6 +1650,79 @@ export function revealRoom(roomId) {
|
||||
currentRoom = roomId;
|
||||
}
|
||||
|
||||
// Function to check if player has crossed a door threshold
|
||||
function checkDoorTransitions(player) {
|
||||
// Check cooldown first
|
||||
const currentTime = Date.now();
|
||||
if (currentTime - lastDoorTransitionTime < DOOR_TRANSITION_COOLDOWN) {
|
||||
return null; // Still in cooldown
|
||||
}
|
||||
|
||||
const playerBottomY = player.y + (player.height * player.scaleY) / 2;
|
||||
let closestTransition = null;
|
||||
let closestDistance = Infinity;
|
||||
|
||||
// Check all rooms for door transitions
|
||||
Object.entries(rooms).forEach(([roomId, room]) => {
|
||||
if (!room.doorSprites) return;
|
||||
|
||||
room.doorSprites.forEach(doorSprite => {
|
||||
// Get door information from the sprite's custom properties
|
||||
const doorInfo = doorSprite.doorInfo;
|
||||
if (!doorInfo) return;
|
||||
|
||||
const { direction, connectedRoom } = doorInfo;
|
||||
|
||||
// Skip if this would transition to the current room
|
||||
if (connectedRoom === currentPlayerRoom) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate door threshold based on direction
|
||||
let doorThreshold = null;
|
||||
const roomPosition = room.position;
|
||||
const roomHeight = room.map.heightInPixels;
|
||||
|
||||
if (direction === 'north') {
|
||||
// North door: threshold is 2 tiles down from top (bottom of door)
|
||||
doorThreshold = roomPosition.y + TILE_SIZE * 2; // 1 tile from top + 1 more tile for door height
|
||||
} else if (direction === 'south') {
|
||||
// South door: threshold is 2 tiles up from bottom (top of door)
|
||||
doorThreshold = roomPosition.y + roomHeight - TILE_SIZE * 2; // 1 tile from bottom + 1 more tile for door height
|
||||
}
|
||||
|
||||
if (doorThreshold !== null) {
|
||||
// Check if player has crossed the threshold
|
||||
let shouldTransition = false;
|
||||
if (direction === 'north' && playerBottomY <= doorThreshold) {
|
||||
shouldTransition = true;
|
||||
} else if (direction === 'south' && playerBottomY >= doorThreshold) {
|
||||
shouldTransition = true;
|
||||
}
|
||||
|
||||
if (shouldTransition) {
|
||||
// Calculate distance to this door threshold
|
||||
const distanceToThreshold = Math.abs(playerBottomY - doorThreshold);
|
||||
|
||||
// Only consider this transition if it's closer than any previous one
|
||||
if (distanceToThreshold < closestDistance) {
|
||||
closestDistance = distanceToThreshold;
|
||||
closestTransition = connectedRoom;
|
||||
console.log(`Player crossed ${direction} door threshold in ${roomId} -> ${connectedRoom} (current: ${currentPlayerRoom}, distance: ${distanceToThreshold.toFixed(2)})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// If a transition was detected, set the cooldown
|
||||
if (closestTransition) {
|
||||
lastDoorTransitionTime = currentTime;
|
||||
}
|
||||
|
||||
return closestTransition;
|
||||
}
|
||||
|
||||
export function updatePlayerRoom() {
|
||||
// Check which room the player is currently in
|
||||
const player = window.player;
|
||||
@@ -1596,6 +1730,23 @@ export function updatePlayerRoom() {
|
||||
return; // Player not created yet
|
||||
}
|
||||
|
||||
// Check for door transitions first
|
||||
const doorTransitionRoom = checkDoorTransitions(player);
|
||||
if (doorTransitionRoom && doorTransitionRoom !== currentPlayerRoom) {
|
||||
// Door transition detected to a different room
|
||||
console.log(`Door transition detected: ${currentPlayerRoom} -> ${doorTransitionRoom}`);
|
||||
currentPlayerRoom = doorTransitionRoom;
|
||||
|
||||
// Reveal the room if not already discovered
|
||||
if (!discoveredRooms.has(doorTransitionRoom)) {
|
||||
revealRoom(doorTransitionRoom);
|
||||
}
|
||||
|
||||
// Player depth is now handled by the simplified updatePlayerDepth function in player.js
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to overlap-based room detection
|
||||
let overlappingRooms = [];
|
||||
|
||||
// Check all rooms for overlap with proper threshold
|
||||
@@ -1608,7 +1759,10 @@ export function updatePlayerRoom() {
|
||||
};
|
||||
|
||||
if (isPlayerInBounds(player, roomBounds)) {
|
||||
overlappingRooms.push(roomId);
|
||||
overlappingRooms.push({
|
||||
roomId: roomId,
|
||||
position: room.position.y // Use Y position for northernmost sorting
|
||||
});
|
||||
|
||||
// Reveal room if not already discovered
|
||||
if (!discoveredRooms.has(roomId)) {
|
||||
@@ -1625,36 +1779,23 @@ export function updatePlayerRoom() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update current room (use the first overlapping room as the "main" room)
|
||||
if (currentPlayerRoom !== overlappingRooms[0]) {
|
||||
console.log(`Player's main room changed to: ${overlappingRooms[0]}`);
|
||||
currentPlayerRoom = overlappingRooms[0];
|
||||
window.currentPlayerRoom = overlappingRooms[0];
|
||||
|
||||
// Update player depth for the new room
|
||||
updatePlayerDepthForRoom(overlappingRooms[0]);
|
||||
}
|
||||
// Sort overlapping rooms by Y position (northernmost first - lower Y values)
|
||||
overlappingRooms.sort((a, b) => a.position - b.position);
|
||||
|
||||
return currentPlayerRoom;
|
||||
// Use the northernmost room (lowest Y position) as the main room
|
||||
const northernmostRoom = overlappingRooms[0].roomId;
|
||||
|
||||
// Update current room (use the northernmost overlapping room as the "main" room)
|
||||
if (currentPlayerRoom !== northernmostRoom) {
|
||||
console.log(`Player's main room changed to: ${northernmostRoom} (northernmost of ${overlappingRooms.length} overlapping rooms)`);
|
||||
currentPlayerRoom = northernmostRoom;
|
||||
window.currentPlayerRoom = northernmostRoom;
|
||||
|
||||
// Player depth is now handled by the simplified updatePlayerDepth function in player.js
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update player depth when entering a room
|
||||
export function updatePlayerDepthForRoom(roomId) {
|
||||
const player = window.player;
|
||||
if (!player) return;
|
||||
|
||||
// Use the same depth calculation as objects for consistent z-index behavior
|
||||
const playerBottomY = player.y + (player.height * player.scaleY) / 2;
|
||||
const roomDepth = Math.floor(playerBottomY / 50) * 50; // Use 50-pixel boundaries for finer granularity
|
||||
const playerDepth = roomDepth + 500; // Same as objects - above all room layers
|
||||
|
||||
// Update player depth
|
||||
player.setDepth(playerDepth);
|
||||
|
||||
console.log(`Updated player depth for room ${roomId}: ${playerDepth} (RoomDepth: ${roomDepth})`);
|
||||
console.log(` Player uses same depth calculation as objects: roomDepth + 500`);
|
||||
console.log(` Room layer depths: floor=${roomDepth + 100}, collision=${roomDepth + 150}, walls=${roomDepth + 200}, props=${roomDepth + 300}, other=${roomDepth + 400}`);
|
||||
}
|
||||
|
||||
|
||||
// Helper function to check if player properly overlaps with room bounds
|
||||
function isPlayerInBounds(player, bounds) {
|
||||
|
||||
Reference in New Issue
Block a user