mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
feat: Add sprite padding constants and adjust depth calculations for player and NPC sprites
This commit is contained in:
@@ -22,7 +22,7 @@ import { PlayerCombat } from '../systems/player-combat.js';
|
||||
import { NPCCombat } from '../systems/npc-combat.js';
|
||||
import { ApiClient } from '../api-client.js'; // Import to ensure window.ApiClient is set
|
||||
import { getTutorialManager } from '../systems/tutorial-manager.js';
|
||||
import { TILE_SIZE } from '../utils/constants.js';
|
||||
import { TILE_SIZE, SPRITE_PADDING_BOTTOM_ATLAS, SPRITE_PADDING_BOTTOM_LEGACY } from '../utils/constants.js';
|
||||
|
||||
// Global variables that will be set by main.js
|
||||
let gameScenario;
|
||||
@@ -885,7 +885,10 @@ export async function create() {
|
||||
} else {
|
||||
// NPC was out of range - treat click as a movement request
|
||||
// Calculate floor-level destination at the NPC's position, offset to stop short
|
||||
const npcBottomY = npcAtPosition.y + (npcAtPosition.height * (1 - (npcAtPosition.originY || 0.5)));
|
||||
// Account for sprite padding (16px for atlas sprites)
|
||||
const spriteCenterToBottom = npcAtPosition.height * (1 - (npcAtPosition.originY || 0.5));
|
||||
const paddingOffset = npcAtPosition.isAtlas ? SPRITE_PADDING_BOTTOM_ATLAS : SPRITE_PADDING_BOTTOM_LEGACY;
|
||||
const npcBottomY = npcAtPosition.y + spriteCenterToBottom - paddingOffset;
|
||||
const stopShortOffset = TILE_SIZE * 0.75; // Stop 24 pixels short (3/4 tile)
|
||||
movePlayerToPoint(npcAtPosition.x, npcBottomY + stopShortOffset);
|
||||
return;
|
||||
|
||||
@@ -10,7 +10,9 @@ import {
|
||||
PLAYER_FEET_OFFSET_Y,
|
||||
ROOM_CHECK_THRESHOLD,
|
||||
CLICK_INDICATOR_SIZE,
|
||||
CLICK_INDICATOR_DURATION
|
||||
CLICK_INDICATOR_DURATION,
|
||||
SPRITE_PADDING_BOTTOM_ATLAS,
|
||||
SPRITE_PADDING_BOTTOM_LEGACY
|
||||
} from '../utils/constants.js?v=8';
|
||||
|
||||
export let player = null;
|
||||
@@ -94,6 +96,9 @@ export function createPlayer(gameInstance) {
|
||||
player = gameInstance.add.sprite(startRoomPosition.x, startRoomPosition.y, playerSprite, initialFrame);
|
||||
gameInstance.physics.add.existing(player);
|
||||
|
||||
// Store atlas detection flag for depth calculations
|
||||
player.isAtlas = isAtlas;
|
||||
|
||||
// Keep the character at original size
|
||||
player.setScale(1);
|
||||
|
||||
@@ -624,8 +629,12 @@ export function movePlayerToPoint(x, y) {
|
||||
}
|
||||
|
||||
function updatePlayerDepth(x, y) {
|
||||
// Get the bottom of the player sprite (feet position)
|
||||
const playerBottomY = y + (player.height * player.scaleY) / 2;
|
||||
// Get the bottom of the player sprite, accounting for padding
|
||||
// Atlas sprites (80x80) have 16px padding at bottom, legacy sprites (64x64) have minimal padding
|
||||
// Use actual y parameter so depth follows visual position (including during death animations)
|
||||
const spriteCenterToBottom = (player.height * player.scaleY) / 2;
|
||||
const paddingOffset = player.isAtlas ? SPRITE_PADDING_BOTTOM_ATLAS : SPRITE_PADDING_BOTTOM_LEGACY;
|
||||
const playerBottomY = y + spriteCenterToBottom - paddingOffset;
|
||||
|
||||
// Simple depth calculation: world Y position + layer offset
|
||||
const playerDepth = playerBottomY + 0.5; // World Y + sprite layer offset
|
||||
@@ -637,8 +646,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} (World Y: ${playerBottomY})`);
|
||||
console.log(` Player layers: worldY(${playerBottomY}) + 0.5`);
|
||||
console.log(`Player depth: ${playerDepth} (Feet Y: ${playerBottomY}, Padding: ${paddingOffset}px)`);
|
||||
console.log(` Player layers: feetY(${playerBottomY}) + 0.5`);
|
||||
player.lastDepth = playerDepth;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +153,35 @@ function playNPCDeathAnimation(npcId, sprite) {
|
||||
if (sprite.anims.isPlaying) {
|
||||
sprite.anims.stop();
|
||||
}
|
||||
|
||||
// Store original origin for restoration
|
||||
const originalOriginY = sprite.originY;
|
||||
|
||||
// Add animation update listener to progressively shift visual display downward
|
||||
sprite.on('animationupdate', (anim, frame) => {
|
||||
if (anim.key === deathAnimKey) {
|
||||
// Calculate progress through animation (0 to 1)
|
||||
const totalFrames = anim.getTotalFrames();
|
||||
const currentFrame = frame.index;
|
||||
const progress = currentFrame / totalFrames;
|
||||
|
||||
// Shift sprite's visual display downward by adjusting origin
|
||||
// This moves the texture down without changing sprite.y (keeps depth constant)
|
||||
// Decrease originY by ~0.5 to shift texture down by half sprite height (~40px for 80px sprite)
|
||||
const originOffset = progress * 0.5;
|
||||
sprite.setOrigin(sprite.originX, originalOriginY - originOffset);
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up listener when animation completes
|
||||
sprite.once('animationcomplete', (anim) => {
|
||||
if (anim.key === deathAnimKey) {
|
||||
sprite.off('animationupdate');
|
||||
// Origin stays shifted - defeated body appears lower visually but sprite.y unchanged
|
||||
// Depth remains constant, naturally rendering behind standing characters at same Y
|
||||
}
|
||||
});
|
||||
|
||||
sprite.play(deathAnimKey);
|
||||
console.log(`💀 Playing NPC death animation: ${deathAnimKey}`);
|
||||
} else {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* @module npc-sprites
|
||||
*/
|
||||
|
||||
import { TILE_SIZE } from '../utils/constants.js?v=8';
|
||||
import { TILE_SIZE, SPRITE_PADDING_BOTTOM_ATLAS, SPRITE_PADDING_BOTTOM_LEGACY } from '../utils/constants.js?v=8';
|
||||
|
||||
/**
|
||||
* Create an NPC sprite in the game world
|
||||
@@ -78,6 +78,7 @@ export function createNPCSprite(scene, npc, roomData) {
|
||||
const sprite = scene.add.sprite(worldPos.x, worldPos.y, spriteSheet, initialFrame);
|
||||
sprite.npcId = npc.id; // Tag for identification
|
||||
sprite._isNPC = true; // Mark as NPC sprite
|
||||
sprite.isAtlas = isAtlas; // Store for depth calculation
|
||||
|
||||
console.log(`🎭 NPC ${npc.id} created with ${isAtlas ? 'atlas' : 'legacy'} sprite (${spriteSheet}), initial frame: ${initialFrame}`);
|
||||
|
||||
@@ -556,16 +557,20 @@ export function setupNPCAnimations(scene, sprite, spriteSheet, config, npcId) {
|
||||
/**
|
||||
* Update NPC sprite depth based on Y position
|
||||
*
|
||||
* Uses same system as player (bottomY + 0.5) to ensure correct
|
||||
* perspective in top-down view.
|
||||
* Uses same system as player (feetY + 0.5) to ensure correct
|
||||
* perspective in top-down view. Accounts for sprite padding.
|
||||
*
|
||||
* @param {Phaser.Sprite} sprite - NPC sprite to update
|
||||
*/
|
||||
export function updateNPCDepth(sprite) {
|
||||
if (!sprite || !sprite.body) return;
|
||||
|
||||
// Get the bottom of the sprite (feet position)
|
||||
const spriteBottomY = sprite.y + (sprite.displayHeight / 2);
|
||||
// Get the bottom of the sprite, accounting for padding
|
||||
// Atlas sprites (80x80) have 16px padding at bottom, legacy sprites (64x64) have minimal padding
|
||||
// Use actual sprite.y so depth follows visual position (including during death animations)
|
||||
const spriteCenterToBottom = sprite.displayHeight / 2;
|
||||
const paddingOffset = sprite.isAtlas ? SPRITE_PADDING_BOTTOM_ATLAS : SPRITE_PADDING_BOTTOM_LEGACY;
|
||||
const spriteBottomY = sprite.y + spriteCenterToBottom - paddingOffset;
|
||||
|
||||
// Set depth using standard formula
|
||||
const depth = spriteBottomY + 0.5; // World Y + sprite layer offset
|
||||
|
||||
@@ -99,6 +99,32 @@ function playPlayerDeathAnimation() {
|
||||
const deathAnimKey = `falling-back-death_${compassDir}`;
|
||||
|
||||
if (player.scene.anims.exists(deathAnimKey)) {
|
||||
// Store original origin for visual shift
|
||||
const originalOriginY = player.originY;
|
||||
|
||||
// Add animation update listener to progressively shift visual display downward
|
||||
player.on('animationupdate', (anim, frame) => {
|
||||
if (anim.key === deathAnimKey) {
|
||||
// Calculate progress through animation (0 to 1)
|
||||
const totalFrames = anim.getTotalFrames();
|
||||
const currentFrame = frame.index;
|
||||
const progress = currentFrame / totalFrames;
|
||||
|
||||
// Shift player's visual display downward by adjusting origin
|
||||
// Decrease originY by ~0.4 to shift texture down (~32px for 80px sprite)
|
||||
const originOffset = progress * 0.4;
|
||||
player.setOrigin(player.originX, originalOriginY - originOffset);
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up listener when animation completes
|
||||
player.once('animationcomplete', (anim) => {
|
||||
if (anim.key === deathAnimKey) {
|
||||
player.off('animationupdate');
|
||||
// Origin stays shifted - defeated player appears lower but depth unchanged
|
||||
}
|
||||
});
|
||||
|
||||
player.play(deathAnimKey);
|
||||
console.log(`💀 Playing player death animation: ${deathAnimKey}`);
|
||||
} else {
|
||||
|
||||
@@ -26,6 +26,12 @@ export const CLICK_INDICATOR_DURATION = 800; // milliseconds
|
||||
export const CLICK_INDICATOR_SIZE = 20; // pixels
|
||||
export const PLAYER_FEET_OFFSET_Y = 30; // Adjust based on your sprite's feet position (64px sprite)
|
||||
|
||||
// Sprite dimensions and padding
|
||||
export const SPRITE_SIZE_ATLAS = 80; // Atlas sprites (PixelLab) are 80x80px
|
||||
export const SPRITE_SIZE_LEGACY = 64; // Legacy sprites are 64x64px
|
||||
export const SPRITE_PADDING_BOTTOM_ATLAS = 6; // Atlas sprites have 16px padding at bottom
|
||||
export const SPRITE_PADDING_BOTTOM_LEGACY = 4; // Legacy sprites have minimal bottom padding
|
||||
|
||||
// Room visibility settings
|
||||
export const HIDE_ROOMS_INITIALLY = true;
|
||||
export const HIDE_ROOMS_ON_EXIT = false;
|
||||
|
||||
Reference in New Issue
Block a user