Initial commit
This commit is contained in:
205
docs/superpowers/plans/2026-04-01-combat-ui-unit-panel.md
Normal file
205
docs/superpowers/plans/2026-04-01-combat-ui-unit-panel.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# Combat UI Unit Panel Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Replace the exit-button CombatUI with a bottom-left panel that shows the selected unit's name and HP.
|
||||
|
||||
**Architecture:** CombatUI listens to the `unit_selected_changed` signal from units in the `"units"` group. On selection, it populates a name label and HP progress bar and shows the panel. On deselection, it hides the panel.
|
||||
|
||||
**Tech Stack:** Godot 4.6, GDScript, `.tscn` scene files
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| File | Action | Responsibility |
|
||||
|------|--------|----------------|
|
||||
| `prefabs/unit.tscn` | Modify | Add Unit node to `"units"` group |
|
||||
| `scripts/combat_ui.gd` | Create | Script that connects to unit signals, shows/hides panel, populates data |
|
||||
| `prefabs/combat_ui.tscn` | Modify | Remove exit button, add UnitPanel with NameLabel and HPBar, attach new script |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add Unit to the "units" group
|
||||
|
||||
**Files:**
|
||||
- Modify: `prefabs/unit.tscn`
|
||||
|
||||
- [ ] **Step 1: Add the group to the Unit scene**
|
||||
|
||||
In `prefabs/unit.tscn`, add a `groups` property to the root `Unit` node so every instantiated unit is automatically in the `"units"` group. Add this line to the root `[node name="Unit" ...]` block:
|
||||
|
||||
```
|
||||
groups=["units"]
|
||||
```
|
||||
|
||||
The full node line becomes:
|
||||
```
|
||||
[node name="Unit" type="Node2D" unique_id=1893234933 groups=["units"]]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify in editor**
|
||||
|
||||
Open `scenes/combat_test.tscn` in Godot, run the scene (F5), and use the Remote scene tree to confirm the spawned unit node appears under the `"units"` group.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add prefabs/unit.tscn
|
||||
git commit -m "feat: add Unit to 'units' group for discovery"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Create combat_ui.gd script
|
||||
|
||||
**Files:**
|
||||
- Create: `scripts/combat_ui.gd`
|
||||
|
||||
- [ ] **Step 1: Write the script**
|
||||
|
||||
Create `scripts/combat_ui.gd` with the following content:
|
||||
|
||||
```gdscript
|
||||
class_name CombatUI extends CanvasLayer
|
||||
|
||||
@onready var unit_panel: PanelContainer = %UnitPanel
|
||||
@onready var name_label: Label = %NameLabel
|
||||
@onready var hp_bar: ProgressBar = %HPBar
|
||||
|
||||
func _ready() -> void:
|
||||
unit_panel.visible = false
|
||||
for unit: Unit in get_tree().get_nodes_in_group("units"):
|
||||
unit.unit_selected_changed.connect(_on_unit_selected_changed)
|
||||
|
||||
func _on_unit_selected_changed(unit: Unit, selected: bool) -> void:
|
||||
if selected:
|
||||
name_label.text = unit.current_info.name
|
||||
hp_bar.max_value = unit.current_stats.max_hp
|
||||
hp_bar.value = unit.current_stats.current_hp
|
||||
unit_panel.visible = true
|
||||
else:
|
||||
unit_panel.visible = false
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/combat_ui.gd
|
||||
git commit -m "feat: add CombatUI script for unit info panel"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Rebuild combat_ui.tscn
|
||||
|
||||
**Files:**
|
||||
- Modify: `prefabs/combat_ui.tscn`
|
||||
|
||||
- [ ] **Step 1: Replace the scene file contents**
|
||||
|
||||
Replace the entire contents of `prefabs/combat_ui.tscn` with:
|
||||
|
||||
```
|
||||
[gd_scene format=3 uid="uid://cy7r0udfcsqbn"]
|
||||
|
||||
[ext_resource type="Theme" uid="uid://dx26d6py3n8xi" path="res://resources/main_ui_theme.tres" id="1_2ro41"]
|
||||
[ext_resource type="Script" path="res://scripts/combat_ui.gd" id="2_ui_script"]
|
||||
|
||||
[node name="CombatUI" type="CanvasLayer" unique_id=1093388037]
|
||||
script = ExtResource("2_ui_script")
|
||||
|
||||
[node name="UnitPanel" type="PanelContainer" parent="." unique_id=2000000001]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 8.0
|
||||
offset_top = -78.0
|
||||
offset_right = 208.0
|
||||
offset_bottom = -8.0
|
||||
grow_vertical = 0
|
||||
theme = ExtResource("1_2ro41")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="UnitPanel"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 8
|
||||
theme_override_constants/margin_top = 8
|
||||
theme_override_constants/margin_right = 8
|
||||
theme_override_constants/margin_bottom = 8
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="UnitPanel/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="NameLabel" type="Label" parent="UnitPanel/MarginContainer/VBoxContainer" unique_id=2000000002]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Unit"
|
||||
|
||||
[node name="HPBar" type="ProgressBar" parent="UnitPanel/MarginContainer/VBoxContainer" unique_id=2000000003]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
max_value = 100.0
|
||||
value = 100.0
|
||||
show_percentage = false
|
||||
```
|
||||
|
||||
Key changes from the old file:
|
||||
- Removed the exit button, its inline GDScript, the VBoxContainer, and the `[connection]` block.
|
||||
- Added the `combat_ui.gd` script as an ext_resource and attached it to the root node.
|
||||
- Added `UnitPanel` (PanelContainer) anchored to bottom-left with 8px margin from edges, 200px wide, ~70px tall.
|
||||
- `NameLabel` and `HPBar` are marked with `unique_name_in_owner = true` so the script can reference them via `%NameLabel` and `%HPBar`.
|
||||
- `UnitPanel` is also unique-named for `%UnitPanel` access.
|
||||
- `show_percentage = false` on HPBar since we just want the bar visual.
|
||||
|
||||
- [ ] **Step 2: Open in Godot and verify scene tree**
|
||||
|
||||
Open `prefabs/combat_ui.tscn` in the Godot editor. Confirm:
|
||||
1. No errors in the Scene dock.
|
||||
2. The node tree shows: `CombatUI > UnitPanel > MarginContainer > VBoxContainer > NameLabel + HPBar`.
|
||||
3. The UnitPanel is positioned at the bottom-left of the viewport.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add prefabs/combat_ui.tscn
|
||||
git commit -m "feat: replace exit button with unit info panel in CombatUI"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Integration test — verify end-to-end behavior
|
||||
|
||||
**Files:**
|
||||
- None (manual verification)
|
||||
|
||||
- [ ] **Step 1: Run the combat test scene**
|
||||
|
||||
Run `scenes/combat_test.tscn` (F5 or F6 from the scene). The test map generator spawns a unit named "Putit" with 50 HP.
|
||||
|
||||
- [ ] **Step 2: Verify panel is hidden on start**
|
||||
|
||||
Confirm the bottom-left corner is empty — no panel visible.
|
||||
|
||||
- [ ] **Step 3: Click the unit to select it**
|
||||
|
||||
Click the "Putit" unit on the map. Confirm:
|
||||
1. The panel appears in the bottom-left corner.
|
||||
2. The name label shows "Putit".
|
||||
3. The HP bar is full (50/50).
|
||||
|
||||
- [ ] **Step 4: Click an empty tile to deselect**
|
||||
|
||||
Click an empty floor tile (this moves the unit, but the unit stays selected). Currently, clicking a different unit would deselect the first — since there's only one test unit, verify that selecting the same unit again keeps the panel visible and data correct.
|
||||
|
||||
- [ ] **Step 5: Verify exit button is gone**
|
||||
|
||||
Confirm there is no "Exit" button anywhere in the UI.
|
||||
|
||||
- [ ] **Step 6: Commit (if any tweaks were needed)**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "fix: adjustments from integration testing"
|
||||
```
|
||||
@@ -0,0 +1,68 @@
|
||||
# Combat UI: Unit Info Panel
|
||||
|
||||
## Overview
|
||||
|
||||
Replace the current exit-button-only CombatUI with a unit info panel that displays the selected unit's name and HP. The panel appears in the bottom-left corner when a unit is selected and hides when deselected.
|
||||
|
||||
## Scene Structure
|
||||
|
||||
```
|
||||
CombatUI (CanvasLayer) — script: scripts/combat_ui.gd
|
||||
└─ UnitPanel (PanelContainer) — anchored bottom-left, hidden by default
|
||||
└─ MarginContainer
|
||||
└─ VBoxContainer
|
||||
├─ NameLabel (Label) — displays unit name
|
||||
└─ HPBar (ProgressBar) — displays current_hp / max_hp
|
||||
```
|
||||
|
||||
- The existing exit button and its VBoxContainer are removed entirely.
|
||||
- The CombatUI CanvasLayer is preserved; its theme reference to `main_ui_theme.tres` stays.
|
||||
|
||||
## Layout
|
||||
|
||||
- UnitPanel is anchored to the bottom-left of the viewport.
|
||||
- Margin of 8px from the left and bottom edges.
|
||||
- Panel width: ~200px (enough for name and HP bar).
|
||||
- Height: determined by contents.
|
||||
|
||||
## Behavior
|
||||
|
||||
### Unit Discovery
|
||||
|
||||
CombatUI finds units by looking for nodes in the `"units"` group. Units must be added to this group — this is done in `unit.tscn` (scene-level group assignment) or in `unit.gd`'s `_ready()`.
|
||||
|
||||
### Signal Connection
|
||||
|
||||
On `_ready()`, CombatUI:
|
||||
1. Calls `get_tree().get_nodes_in_group("units")` to find all current units.
|
||||
2. Connects each unit's `unit_selected_changed(unit: Unit, selected: bool)` signal to a handler.
|
||||
|
||||
### Selection Handling
|
||||
|
||||
When `unit_selected_changed` is received:
|
||||
- If `selected == true`: populate NameLabel with `unit.current_info.name`, set HPBar's `max_value` to `unit.current_stats.max_hp` and `value` to `unit.current_stats.current_hp`, show UnitPanel.
|
||||
- If `selected == false`: hide UnitPanel.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- If no units exist in the group at ready time, the panel simply stays hidden.
|
||||
- If a unit is removed from the scene (e.g., defeated), the signal disconnects naturally with the node. The panel hides if that unit was selected.
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `prefabs/combat_ui.tscn` | Remove exit button/VBoxContainer. Add UnitPanel with NameLabel and HPBar. Attach new script. |
|
||||
| `scripts/combat_ui.gd` | New script: connects to unit signals, shows/hides panel, populates data. |
|
||||
| `prefabs/unit.tscn` | Add the node to the `"units"` group. |
|
||||
|
||||
## Styling
|
||||
|
||||
Uses the existing `main_ui_theme.tres` applied at the CombatUI or UnitPanel level. No new theme resources needed.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Full stat display (ATK, DEF, etc.) — future expansion.
|
||||
- Animations (fade/slide) — instant show/hide only.
|
||||
- Pause menu / exit button — separate future feature.
|
||||
- HP bar color theming — uses default ProgressBar style from theme.
|
||||
Reference in New Issue
Block a user