feat(B.7): TargetIndicatorPanel — corner triangles around selected entity
Per the B.7 design spec, wires a Vivid-Target-Indicator-style overlay
into GameWindow's ImGui pass:
TargetIndicatorPanel (src/AcDream.App/UI/TargetIndicatorPanel.cs)
- Three delegates injected from GameWindow:
selectedGuidProvider -> _selectedGuid
entityResolver -> (worldPos, itemType, pwdBits) from
_entitiesByServerGuid + _liveEntityInfoByGuid
+ _lastSpawnByGuid
cameraProvider -> (view, projection, viewport) from
_cameraController.Active + _window.Size
- Per-frame Render():
* Bail on null selection / despawned entity / zero viewport.
* Project entity world position (+0.9m mid-body offset) to NDC.
* Bail off-screen (no edge arrow in MVP).
* Convert to viewport pixel coords, draw 4 right-angle triangles
at corners of a 48px square around the projected center.
* Colour from RadarBlipColors.For(itemType, pwdBits).
GameWindow wiring:
- Construct _targetIndicator right after _panelHost during ImGui init.
- Call _targetIndicator?.Render() between _panelHost.RenderAll and
_imguiBootstrap.Render — draws to the ImGui background list so
docked panels can occlude the indicator if they overlap.
Build green. Core.Tests went 1046 -> 1054 (+8 RadarBlipColors tests
from the prior commit). Baseline failures unchanged at 8.
Visual verification next: launch, click an NPC → yellow corners; click
an item -> white corners; deselect -> corners disappear.
This commit is contained in:
parent
8544a785d7
commit
c7e5f9f00f
2 changed files with 187 additions and 0 deletions
|
|
@ -565,6 +565,11 @@ public sealed class GameWindow : IDisposable
|
|||
// See docs/plans/2026-04-24-ui-framework.md for the staged UI strategy.
|
||||
private AcDream.UI.ImGui.ImGuiBootstrapper? _imguiBootstrap;
|
||||
private AcDream.UI.ImGui.ImGuiPanelHost? _panelHost;
|
||||
// B.7 (2026-05-15): Vivid Target Indicator — four corner triangles
|
||||
// around the selected entity, colour-coded by ItemType + PWD bits.
|
||||
// Lives alongside the debug panels; cheap to construct + ignore
|
||||
// when no selection. Spec: docs/superpowers/specs/2026-05-15-phase-b7-target-indicator-design.md
|
||||
private AcDream.App.UI.TargetIndicatorPanel? _targetIndicator;
|
||||
private AcDream.UI.Abstractions.Panels.Vitals.VitalsVM? _vitalsVm;
|
||||
// Phase I.2: ImGui debug panel ViewModel. Lives for as long as
|
||||
// _panelHost does. Self-subscribes to CombatState in its ctor, so
|
||||
|
|
@ -1150,6 +1155,41 @@ public sealed class GameWindow : IDisposable
|
|||
_imguiBootstrap = new AcDream.UI.ImGui.ImGuiBootstrapper(_gl!, _window!, _input!);
|
||||
_panelHost = new AcDream.UI.ImGui.ImGuiPanelHost();
|
||||
|
||||
// B.7 Vivid Target Indicator — corner-triangle highlight
|
||||
// around the currently-selected entity. Delegates pull
|
||||
// live state from this GameWindow instance every frame:
|
||||
// - selected guid → _selectedGuid (set by PickAndStoreSelection)
|
||||
// - entity resolver → position from _entitiesByServerGuid +
|
||||
// itemType / PWD bits from cached LiveEntityInfo + last spawn
|
||||
// - camera → _cameraController.Active or (zero) when not
|
||||
// yet ready, in which case the panel bails on viewport==0.
|
||||
_targetIndicator = new AcDream.App.UI.TargetIndicatorPanel(
|
||||
selectedGuidProvider: () => _selectedGuid,
|
||||
entityResolver: guid =>
|
||||
{
|
||||
if (!_entitiesByServerGuid.TryGetValue(guid, out var entity))
|
||||
return null;
|
||||
uint rawItemType = 0;
|
||||
if (_liveEntityInfoByGuid.TryGetValue(guid, out var info))
|
||||
rawItemType = (uint)info.ItemType;
|
||||
uint pwdBits = 0;
|
||||
if (_lastSpawnByGuid.TryGetValue(guid, out var spawn)
|
||||
&& spawn.ObjectDescriptionFlags is { } odf)
|
||||
pwdBits = odf;
|
||||
return new AcDream.App.UI.TargetIndicatorPanel.TargetInfo(
|
||||
entity.Position, rawItemType, pwdBits);
|
||||
},
|
||||
cameraProvider: () =>
|
||||
{
|
||||
if (_cameraController is null || _window is null)
|
||||
return (System.Numerics.Matrix4x4.Identity,
|
||||
System.Numerics.Matrix4x4.Identity,
|
||||
System.Numerics.Vector2.Zero);
|
||||
var cam = _cameraController.Active;
|
||||
return (cam.View, cam.Projection,
|
||||
new System.Numerics.Vector2(_window.Size.X, _window.Size.Y));
|
||||
});
|
||||
|
||||
// VitalsVM: GUID=0 at construction; set later at EnterWorld
|
||||
// (see the _playerServerGuid assignment path). Pre-login the
|
||||
// HP bar just reads 1.0 (safe default) — harmless. Stam/Mana
|
||||
|
|
@ -7043,6 +7083,11 @@ public sealed class GameWindow : IDisposable
|
|||
}
|
||||
|
||||
_panelHost.RenderAll(ctx);
|
||||
// B.7 Vivid Target Indicator: draws corner triangles to the
|
||||
// ImGui background draw list so it appears behind any docked
|
||||
// panels but still over the 3D scene. Cheap when no
|
||||
// selection — internal early-return on null guid.
|
||||
_targetIndicator?.Render();
|
||||
_imguiBootstrap.Render();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue