Fix defense bar visual direction and restore GUI element sizes#27
Fix defense bar visual direction and restore GUI element sizes#27Copilot wants to merge 6 commits intocopilot/refactor-defensesystem-damagefrom
Conversation
Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com>
Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 31d9fb867f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Track missing stats warnings to avoid spam | ||
| this.missingStatsWarned = new Set(); | ||
|
|
||
| // Tactical UI state | ||
| this.tacticalUI = { | ||
| enabled: true, | ||
| container: null, | ||
| defenseUI: null, | ||
| heatUI: null, | ||
| weaponTypeUI: null, | ||
| floatingTexts: [] | ||
| }; | ||
|
|
||
| // Initialize tactical UI | ||
| this.initTacticalUI(); | ||
| } | ||
|
|
||
| /** | ||
| * Initialize tactical UI components | ||
| */ | ||
| initTacticalUI() { | ||
| if (!window.EnhancedUIComponents) { | ||
| console.warn('[UI] EnhancedUIComponents not found, skipping tactical UI'); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| // Create container | ||
| const container = document.createElement('div'); | ||
| container.id = 'tactical-ui-container'; | ||
| container.style.cssText = 'position:absolute;top:10px;left:10px;z-index:100;pointer-events:none;'; | ||
| document.body.appendChild(container); | ||
| this.tacticalUI.container = container; | ||
|
|
||
| // Defense UI container | ||
| const defenseContainer = document.createElement('div'); | ||
| defenseContainer.id = 'defense-ui'; | ||
| container.appendChild(defenseContainer); | ||
|
|
||
| // Heat UI container | ||
| const heatContainer = document.createElement('div'); | ||
| heatContainer.id = 'heat-ui'; | ||
| heatContainer.style.marginTop = '10px'; | ||
| container.appendChild(heatContainer); | ||
|
|
||
| // Weapon type UI container | ||
| const weaponContainer = document.createElement('div'); | ||
| weaponContainer.id = 'weapon-type-ui'; | ||
| weaponContainer.style.marginTop = '10px'; | ||
| container.appendChild(weaponContainer); | ||
|
|
||
| // Instantiate components | ||
| const Components = window.EnhancedUIComponents; | ||
| this.tacticalUI.defenseUI = new Components.ThreeLayerDefenseUI(defenseContainer); | ||
| this.tacticalUI.heatUI = new Components.HeatGaugeUI(heatContainer); | ||
| this.tacticalUI.weaponTypeUI = new Components.WeaponDamageTypeDisplay(weaponContainer); | ||
|
|
||
| // Subscribe to damage events | ||
| if (this.world.events) { | ||
| this.world.events.on('damageApplied', (data) => this.onDamageApplied(data)); | ||
| } | ||
|
|
||
| console.log('[UI] Tactical UI components initialized'); | ||
| } catch (err) { | ||
| console.error('[UI] Error initializing tactical UI:', err); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Toggle tactical UI visibility | ||
| */ | ||
| toggleTacticalUI() { | ||
| this.tacticalUI.enabled = !this.tacticalUI.enabled; | ||
| if (this.tacticalUI.container) { | ||
| this.tacticalUI.container.style.display = this.tacticalUI.enabled ? 'block' : 'none'; | ||
| } | ||
| // Store state for RenderSystem to check | ||
| if (this.world && this.world.gameState) { | ||
| this.world.gameState.tacticalUIEnabled = this.tacticalUI.enabled; | ||
| } | ||
| console.log(`[UI] tactical HUD ${this.tacticalUI.enabled ? 'enabled' : 'disabled'}`); | ||
| } | ||
|
|
||
| /** | ||
| * Update tactical UI components | ||
| */ | ||
| updateTacticalUI() { | ||
| if (!this.tacticalUI.enabled || !this.tacticalUI.defenseUI) return; | ||
|
|
||
| const player = this.world.getEntitiesByType('player')[0]; | ||
| if (!player) return; | ||
|
|
||
| try { | ||
| // Update defense bars | ||
| const defense = player.getComponent('defense'); | ||
| if (defense && this.tacticalUI.defenseUI) { | ||
| this.tacticalUI.defenseUI.update(defense); | ||
| } | ||
|
|
||
| // Update heat gauge | ||
| const heat = player.getComponent('heat'); | ||
| if (heat && this.tacticalUI.heatUI) { | ||
| this.tacticalUI.heatUI.update(heat); | ||
| } | ||
|
|
||
| // Update weapon type display | ||
| const playerComp = player.getComponent('player'); | ||
| if (playerComp && playerComp.currentWeapon && this.tacticalUI.weaponTypeUI) { | ||
| const damageType = playerComp.currentWeapon.damageType || 'kinetic'; | ||
| this.tacticalUI.weaponTypeUI.update(damageType); | ||
| } | ||
| } catch (err) { | ||
| console.error('[UI] Error updating tactical UI:', err); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Handle damage applied event | ||
| */ | ||
| onDamageApplied(data) { | ||
| this.createFloatingDamage(data); | ||
|
|
||
| const layerEmojis = { | ||
| shield: '🟦 BOUCLIER', | ||
| armor: '🟫 ARMURE', | ||
| structure: '🔧 STRUCTURE' | ||
| }; | ||
| const layerName = layerEmojis[data.layerHit] || data.layerHit; | ||
| console.log(`[Combat] ${layerName} -${Math.round(data.finalDamage)}`); | ||
| } | ||
|
|
||
| /** | ||
| * Create floating damage text | ||
| */ | ||
| createFloatingDamage(data) { | ||
| // Limit active floating texts | ||
| if (this.tacticalUI.floatingTexts.length >= 10) { | ||
| const oldest = this.tacticalUI.floatingTexts.shift(); | ||
| if (oldest && oldest.parentNode) { | ||
| oldest.parentNode.removeChild(oldest); | ||
| } | ||
| } | ||
|
|
||
| const text = document.createElement('div'); | ||
| text.className = 'floating-damage'; | ||
| text.textContent = `-${Math.round(data.finalDamage)}`; | ||
|
|
||
| const typeColors = { | ||
| em: '#00FFFF', | ||
| thermal: '#FF8C00', | ||
| kinetic: '#FFFFFF', | ||
| explosive: '#FF0000' | ||
| }; | ||
|
|
||
| const canvas = this.gameCanvas; | ||
| let left = data.x || 0; | ||
| let top = data.y || 0; | ||
|
|
||
| if (canvas) { | ||
| const rect = canvas.getBoundingClientRect(); | ||
| left = rect.left + left; | ||
| top = rect.top + top; | ||
| } | ||
|
|
||
| text.style.cssText = ` | ||
| position: fixed; | ||
| left: ${left}px; | ||
| top: ${top}px; | ||
| color: ${typeColors[data.damageType] || '#FFF'}; | ||
| font-size: 20px; | ||
| font-weight: bold; | ||
| pointer-events: none; | ||
| animation: floatUp 1s ease-out forwards; | ||
| z-index: 1000; | ||
| `; | ||
|
|
||
| document.body.appendChild(text); | ||
| this.tacticalUI.floatingTexts.push(text); | ||
|
|
||
| setTimeout(() => { | ||
| if (text.parentNode) { | ||
| text.parentNode.removeChild(text); | ||
| } | ||
| const index = this.tacticalUI.floatingTexts.indexOf(text); | ||
| if (index > -1) { | ||
| this.tacticalUI.floatingTexts.splice(index, 1); | ||
| } | ||
| }, 1000); | ||
| } |
There was a problem hiding this comment.
Remove stale tactical UI method invocations
This commit deletes toggleTacticalUI and updateTacticalUI, but the class still invokes them from existing paths (setupEventListeners on U key and update()), so pressing U during gameplay now throws TypeError: this.toggleTacticalUI is not a function and any caller of update() would likewise fail on this.updateTacticalUI(). Keep no-op replacements or remove those call sites in the same change to avoid runtime exceptions.
Useful? React with 👍 / 👎.
Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com>
Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com>
Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com>
Defense bars were emptying left-to-right instead of right-to-left. User also requested defense bars remain large while other GUI elements return to original size.
Changes
Defense bar direction
Added
margin-left: autoto align bars right so they shrink from left edge:Effect: Bars now anchored right, empty right-to-left as width decreases.
GUI sizing
Visual comparison
Before - bars empty left-to-right:

After - bars at full, right-aligned:

After - structure at 71/120, empties from left:

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.