diff --git a/app/helpers/break_escape/player_preferences_helper.rb b/app/helpers/break_escape/player_preferences_helper.rb index 80e46fc..3882950 100644 --- a/app/helpers/break_escape/player_preferences_helper.rb +++ b/app/helpers/break_escape/player_preferences_helper.rb @@ -12,11 +12,7 @@ module BreakEscape # Headshot filename for sprite (prefer _down_headshot for hacker_hood, else _headshot) def sprite_headshot_path(sprite) - base = if sprite == 'woman_bow' - 'woman_blowse' # filename typo in assets - else - sprite - end + base = sprite if sprite.end_with?('_hood_down') "/break_escape/assets/characters/#{base}_headshot.png" else diff --git a/app/models/break_escape/player_preference.rb b/app/models/break_escape/player_preference.rb index a23ac66..effafd7 100644 --- a/app/models/break_escape/player_preference.rb +++ b/app/models/break_escape/player_preference.rb @@ -14,7 +14,7 @@ module BreakEscape female_telecom female_spy female_scientist - woman_bow + female_blowse male_hacker_hood male_hacker_hood_down male_office_worker @@ -25,15 +25,9 @@ module BreakEscape male_nerd ].freeze - # Mapping from UI key to game texture key (game.js loads these atlas keys) - # woman_bow -> woman_blowse (filename typo in assets); others are identity - SPRITE_FILE_MAPPING = { - 'woman_bow' => 'woman_blowse' - }.freeze - # Get the texture key for game injection (must match game.js preload keys) def self.sprite_filename(sprite_name) - SPRITE_FILE_MAPPING[sprite_name] || sprite_name + sprite_name end # Validations diff --git a/public/break_escape/css/player_preferences.css b/public/break_escape/css/player_preferences.css index bdc7b30..2a1ff19 100644 --- a/public/break_escape/css/player_preferences.css +++ b/public/break_escape/css/player_preferences.css @@ -96,7 +96,8 @@ h1 { text-align: center; } -#sprite-preview-canvas-container { +#sprite-preview-canvas-container, +#sprite-preview-canvas-container-modal { width: 160px; height: 160px; margin: 0 auto; @@ -105,7 +106,8 @@ h1 { box-sizing: border-box; } -#sprite-preview-canvas-container canvas { +#sprite-preview-canvas-container canvas, +#sprite-preview-canvas-container-modal canvas { display: block; image-rendering: pixelated; image-rendering: -moz-crisp-edges; @@ -113,10 +115,7 @@ h1 { } .preview-label { - margin-top: 8px; - font-size: 14px; - color: #00ff00; - font-weight: bold; + display: none; } /* Grid of static headshots */ @@ -228,12 +227,7 @@ h1 { } .sprite-label { - display: block; - font-size: 11px; - font-weight: bold; - color: #00ff00; - text-transform: capitalize; - word-wrap: break-word; + display: none; } /* Form Actions */ @@ -337,7 +331,7 @@ h1 { } .sprite-label { - font-size: 10px; + display: none; } } diff --git a/public/break_escape/js/ui/hud.js b/public/break_escape/js/ui/hud.js index 9ec55db..777b949 100644 --- a/public/break_escape/js/ui/hud.js +++ b/public/break_escape/js/ui/hud.js @@ -175,7 +175,12 @@ export class PlayerHUD { // Show the modal preferencesModal.style.display = 'flex'; - + + // Pause keyboard so WASD doesn't move the player while typing + if (window.pauseKeyboardInput) { + window.pauseKeyboardInput(); + } + // Pause the game while modal is open if (this.scene && this.scene.scene.isPaused() === false) { this.scene.scene.pause(); @@ -195,7 +200,12 @@ export class PlayerHUD { const preferencesModal = document.getElementById('player-preferences-modal'); if (preferencesModal) { preferencesModal.style.display = 'none'; - + + // Re-enable keyboard input + if (window.resumeKeyboardInput) { + window.resumeKeyboardInput(); + } + // Resume the game if (this.scene && this.scene.scene.isPaused() === true) { this.scene.scene.resume(); diff --git a/public/break_escape/js/ui/sprite-grid.js b/public/break_escape/js/ui/sprite-grid.js index 5bf2df2..f44e651 100644 --- a/public/break_escape/js/ui/sprite-grid.js +++ b/public/break_escape/js/ui/sprite-grid.js @@ -4,13 +4,8 @@ const PREVIEW_SIZE = 160; -// Map UI sprite key to actual atlas filename (must match files in characters/) -// woman_bow -> woman_blowse (filename in assets); others use same name -const SPRITE_ATLAS_FILENAME = { - 'woman_bow': 'woman_blowse' -}; function atlasFilename(spriteKey) { - return SPRITE_ATLAS_FILENAME[spriteKey] || spriteKey; + return spriteKey; } let phaserGame = null; @@ -20,11 +15,18 @@ let initialSelectedSprite = null; export function initializeSpritePreview(sprites, selectedSprite, containerIdOverride = null) { console.log('🎨 Initializing sprite preview...', { sprites: sprites.length, selectedSprite, containerIdOverride }); initialSelectedSprite = selectedSprite || null; - + + // Destroy previous Phaser game instance to avoid stacking canvases + if (phaserGame) { + phaserGame.destroy(true); + phaserGame = null; + currentPreviewSprite = null; + } + // Use custom container ID if provided, otherwise use default const containerId = containerIdOverride || 'sprite-preview-canvas-container'; - const formId = containerIdOverride === 'sprite-preview-canvas-container-modal' - ? 'preference-form-modal' + const formId = containerIdOverride === 'sprite-preview-canvas-container-modal' + ? 'preference-form-modal' : 'preference-form'; class PreviewScene extends Phaser.Scene { @@ -56,6 +58,9 @@ export function initializeSpritePreview(sprites, selectedSprite, containerIdOver width: PREVIEW_SIZE, height: PREVIEW_SIZE, transparent: true, + pixelArt: true, + antialias: false, + roundPixels: true, scale: { mode: Phaser.Scale.NONE }, @@ -97,7 +102,7 @@ function showSpriteInPreview(scene, spriteKey) { const y = PREVIEW_SIZE / 2; currentPreviewSprite = scene.add.sprite(x, y, spriteKey); - currentPreviewSprite.setDisplaySize(PREVIEW_SIZE, PREVIEW_SIZE); + currentPreviewSprite.setScale(2); const animKey = `${spriteKey}-preview-south`; if (!scene.anims.exists(animKey)) { diff --git a/tools/convert_pixellab_to_spritesheet.py b/tools/convert_pixellab_to_spritesheet.py index 4d43230..c01fc13 100755 --- a/tools/convert_pixellab_to_spritesheet.py +++ b/tools/convert_pixellab_to_spritesheet.py @@ -263,7 +263,7 @@ def process_character(character_dir, output_dir): 'woman_female_high_vis_vest_polo_shirt_telecom_w': 'female_telecom', 'woman_female_spy_in_trench_oat_duffel_coat_trilby': 'female_spy', 'woman_in_science_lab_coat': 'female_scientist', - 'woman_with_black_long_hair_bow_in_hair_long_sleeve_(1)': 'woman_bow', + 'woman_with_black_long_hair_bow_in_hair_long_sleeve_(1)': 'female_blowse', 'hacker_in_a_hoodie_hood_up_black_obscured_face_sh': 'male_hacker_hood', 'hacker_in_hoodie_(1)': 'male_hacker', 'office_worker_white_shirt_and_tie_(7)': 'male_office_worker',