grant enemy abilities in debug console
This commit is contained in:
parent
749c9203de
commit
dc9184075b
4 changed files with 347 additions and 178 deletions
185
Assets/_Project/Scripts/Dev/DebugConsoleUI.cs
Normal file
185
Assets/_Project/Scripts/Dev/DebugConsoleUI.cs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
// Assets/_Project/Scripts/Dev/DebugConsoleUI.cs
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace TD.Dev
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and draws <see cref="DebugConsole"/>'s VisualElement tree: the input bar and
|
||||
/// its autocomplete list. Owns presentation only — element construction, styling, and
|
||||
/// row rendering — no command grammar, keybinding, or suggestion-selection logic; that
|
||||
/// stays in <see cref="DebugConsole"/>, which drives this class through its public
|
||||
/// members and reads/writes <see cref="CommandInput"/> directly for focus and value.
|
||||
/// </summary>
|
||||
internal sealed class DebugConsoleUI
|
||||
{
|
||||
// Beyond this many candidates the list is truncated with a "+N more" row so a
|
||||
// large DraftPool can't grow the console bar off the top of the screen.
|
||||
private const int MaxVisibleSuggestions = 12;
|
||||
|
||||
/// <summary>One row of the autocomplete list: a candidate token plus an optional dim hint.</summary>
|
||||
public readonly struct SuggestionRow
|
||||
{
|
||||
public readonly string Text;
|
||||
public readonly string Hint;
|
||||
|
||||
public SuggestionRow(string text, string hint)
|
||||
{
|
||||
Text = text;
|
||||
Hint = hint;
|
||||
}
|
||||
}
|
||||
|
||||
public TextField CommandInput { get; }
|
||||
|
||||
private readonly VisualElement consoleContainer;
|
||||
private readonly VisualElement suggestionList;
|
||||
|
||||
public DebugConsoleUI(VisualElement uiRoot)
|
||||
{
|
||||
// Top-anchored bar, closed by default. Distinct position from the HUD's
|
||||
// bottom-left chat panel so the two never overlap.
|
||||
consoleContainer = new VisualElement();
|
||||
consoleContainer.pickingMode = PickingMode.Ignore;
|
||||
consoleContainer.style.position = Position.Absolute;
|
||||
consoleContainer.style.left = 0;
|
||||
consoleContainer.style.right = 0;
|
||||
consoleContainer.style.top = 0;
|
||||
consoleContainer.style.paddingTop = 8;
|
||||
consoleContainer.style.paddingBottom = 8;
|
||||
consoleContainer.style.paddingLeft = 12;
|
||||
consoleContainer.style.paddingRight = 12;
|
||||
// Fully opaque: the console is a text-entry overlay that has to stay readable
|
||||
// over the level, the HUD, and whatever else is on screen.
|
||||
consoleContainer.style.backgroundColor = new Color(0f, 0f, 0f, 1f);
|
||||
consoleContainer.style.display = DisplayStyle.None;
|
||||
|
||||
CommandInput = new TextField();
|
||||
CommandInput.style.minHeight = 28;
|
||||
CommandInput.style.width = Length.Percent(100);
|
||||
CommandInput.maxLength = 200;
|
||||
CommandInput.isDelayed = false;
|
||||
StyleConsoleInput(CommandInput);
|
||||
|
||||
suggestionList = new VisualElement();
|
||||
suggestionList.pickingMode = PickingMode.Ignore;
|
||||
suggestionList.style.flexDirection = FlexDirection.Column;
|
||||
suggestionList.style.marginTop = 4;
|
||||
suggestionList.style.display = DisplayStyle.None;
|
||||
|
||||
consoleContainer.Add(CommandInput);
|
||||
consoleContainer.Add(suggestionList);
|
||||
uiRoot.Add(consoleContainer);
|
||||
}
|
||||
|
||||
// Mirrors HUDController.StyleChatInputDark — dark background, white text,
|
||||
// a thin border, and inner padding so ascenders/descenders don't clip.
|
||||
// Green border (vs. chat's neutral gray) as a quick visual "this is the
|
||||
// debug console, not chat" cue.
|
||||
private static void StyleConsoleInput(TextField field)
|
||||
{
|
||||
var darkBg = new Color(0.05f, 0.05f, 0.05f, 1f);
|
||||
var borderClr = new Color(0.35f, 0.75f, 0.35f);
|
||||
|
||||
field.style.backgroundColor = darkBg;
|
||||
field.style.color = Color.white;
|
||||
field.style.borderTopWidth = field.style.borderBottomWidth =
|
||||
field.style.borderLeftWidth = field.style.borderRightWidth = 1;
|
||||
field.style.borderTopColor = field.style.borderBottomColor =
|
||||
field.style.borderLeftColor = field.style.borderRightColor = borderClr;
|
||||
|
||||
var inner = field.Q("unity-text-input");
|
||||
if (inner != null)
|
||||
{
|
||||
inner.style.backgroundColor = darkBg;
|
||||
inner.style.color = Color.white;
|
||||
inner.style.paddingTop = 4;
|
||||
inner.style.paddingBottom = 4;
|
||||
inner.style.paddingLeft = 6;
|
||||
inner.style.paddingRight = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// One autocomplete row: the candidate token plus an optional dim hint. Rows are
|
||||
// pickingMode Ignore and keyboard-driven only — nothing here is clickable, which
|
||||
// avoids the recursive picking-mode problem documented in HUDController's chat
|
||||
// panel (clicks falling through to the game world via a ScrollView's internal
|
||||
// wrapper element).
|
||||
private static VisualElement BuildSuggestionRow(string text, string hint, bool selected)
|
||||
{
|
||||
var row = new VisualElement();
|
||||
row.pickingMode = PickingMode.Ignore;
|
||||
row.style.flexDirection = FlexDirection.Row;
|
||||
row.style.minHeight = 20;
|
||||
row.style.paddingLeft = 6;
|
||||
row.style.paddingRight = 6;
|
||||
row.style.backgroundColor = selected
|
||||
? new Color(0.16f, 0.38f, 0.16f, 1f) // matches the green console cue
|
||||
: new Color(0.05f, 0.05f, 0.05f, 1f);
|
||||
|
||||
var label = new Label(text);
|
||||
label.pickingMode = PickingMode.Ignore;
|
||||
label.style.color = Color.white;
|
||||
label.style.unityFontStyleAndWeight = selected ? FontStyle.Bold : FontStyle.Normal;
|
||||
row.Add(label);
|
||||
|
||||
if (!string.IsNullOrEmpty(hint))
|
||||
{
|
||||
var hintLabel = new Label(hint);
|
||||
hintLabel.pickingMode = PickingMode.Ignore;
|
||||
hintLabel.style.color = new Color(0.6f, 0.6f, 0.6f);
|
||||
hintLabel.style.marginLeft = 12;
|
||||
row.Add(hintLabel);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
consoleContainer.style.display = DisplayStyle.Flex;
|
||||
consoleContainer.pickingMode = PickingMode.Position;
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
consoleContainer.style.display = DisplayStyle.None;
|
||||
consoleContainer.pickingMode = PickingMode.Ignore;
|
||||
}
|
||||
|
||||
// Windows the list around selectedIndex so arrowing past MaxVisibleSuggestions
|
||||
// keeps the selected row on screen instead of scrolling it out of the truncated view.
|
||||
public void RenderSuggestions(List<SuggestionRow> rows, int selectedIndex)
|
||||
{
|
||||
suggestionList.Clear();
|
||||
|
||||
if (rows == null || rows.Count == 0)
|
||||
{
|
||||
suggestionList.style.display = DisplayStyle.None;
|
||||
return;
|
||||
}
|
||||
|
||||
suggestionList.style.display = DisplayStyle.Flex;
|
||||
|
||||
int start = rows.Count > MaxVisibleSuggestions
|
||||
? Mathf.Clamp(selectedIndex - MaxVisibleSuggestions / 2, 0,
|
||||
rows.Count - MaxVisibleSuggestions)
|
||||
: 0;
|
||||
int end = Mathf.Min(start + MaxVisibleSuggestions, rows.Count);
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
suggestionList.Add(BuildSuggestionRow(rows[i].Text, rows[i].Hint, i == selectedIndex));
|
||||
|
||||
int hidden = rows.Count - (end - start);
|
||||
if (hidden > 0)
|
||||
suggestionList.Add(BuildSuggestionRow($"+{hidden} more", null, false));
|
||||
}
|
||||
|
||||
public void ClearSuggestions()
|
||||
{
|
||||
suggestionList.Clear();
|
||||
suggestionList.style.display = DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue