chore(unity): 固定Unity CLI Loop本地包并移除UnitySkills依赖
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
#if UNITY_EDITOR
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace io.github.hatayama.uLoopMCP
|
||||
{
|
||||
public class SimulateKeyboardOverlay : MonoBehaviour
|
||||
{
|
||||
public const float CONTAINER_BACKGROUND_ALPHA = 0.8f;
|
||||
|
||||
private const float PRESS_DISPLAY_DURATION = 0.5f;
|
||||
private const float FADE_DURATION = 0.2f;
|
||||
private const int FONT_SIZE = 48;
|
||||
private const int GLYPH_FONT_SIZE = 64;
|
||||
private static readonly Color ContainerBackgroundColor = new Color(0.15f, 0.15f, 0.15f, CONTAINER_BACKGROUND_ALPHA);
|
||||
|
||||
[SerializeField] private GameObject _container = null!;
|
||||
[SerializeField] private Image _containerImage = null!;
|
||||
|
||||
private readonly List<BadgeEntry> _badgePool = new();
|
||||
private readonly List<string> _cachedKeyNames = new();
|
||||
private readonly List<string> _displayKeys = new();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Debug.Assert(_container != null, "_container must be assigned in prefab");
|
||||
Debug.Assert(_containerImage != null, "_containerImage must be assigned in prefab");
|
||||
|
||||
// Prefab keeps preview badges for editor inspection, but runtime badges must start empty.
|
||||
for (int i = _container!.transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
DestroyImmediate(_container.transform.GetChild(i).gameObject);
|
||||
}
|
||||
|
||||
_container.SetActive(false);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
bool hasHeldKeys = SimulateKeyboardOverlayState.HeldKeys.Count > 0;
|
||||
string? pressKey = SimulateKeyboardOverlayState.PressKey;
|
||||
bool isPressHeld = SimulateKeyboardOverlayState.IsPressHeld;
|
||||
float pressElapsedSinceRelease = 0f;
|
||||
|
||||
if (pressKey != null && !isPressHeld)
|
||||
{
|
||||
pressElapsedSinceRelease = Time.realtimeSinceStartup - SimulateKeyboardOverlayState.PressReleasedTime;
|
||||
if (pressElapsedSinceRelease > PRESS_DISPLAY_DURATION + FADE_DURATION)
|
||||
{
|
||||
SimulateKeyboardOverlayState.ClearPress();
|
||||
pressKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasHeldKeys && pressKey == null)
|
||||
{
|
||||
SetBadgeCount(0);
|
||||
_container.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_displayKeys.Clear();
|
||||
IReadOnlyList<string> heldKeys = SimulateKeyboardOverlayState.HeldKeys;
|
||||
for (int i = 0; i < heldKeys.Count; i++)
|
||||
{
|
||||
_displayKeys.Add(heldKeys[i]);
|
||||
}
|
||||
|
||||
if (pressKey != null && !_displayKeys.Contains(pressKey))
|
||||
{
|
||||
_displayKeys.Add(pressKey);
|
||||
}
|
||||
|
||||
SetBadgeCount(_displayKeys.Count);
|
||||
_container.SetActive(true);
|
||||
|
||||
float maxAlpha = 0f;
|
||||
for (int i = 0; i < _displayKeys.Count; i++)
|
||||
{
|
||||
float alpha = GetBadgeAlpha(_displayKeys[i], pressKey, isPressHeld, pressElapsedSinceRelease);
|
||||
UpdateBadge(_badgePool[i], i, _displayKeys[i], alpha);
|
||||
if (alpha > maxAlpha)
|
||||
{
|
||||
maxAlpha = alpha;
|
||||
}
|
||||
}
|
||||
|
||||
_containerImage.color = new Color(
|
||||
ContainerBackgroundColor.r,
|
||||
ContainerBackgroundColor.g,
|
||||
ContainerBackgroundColor.b,
|
||||
ContainerBackgroundColor.a * maxAlpha);
|
||||
}
|
||||
|
||||
private void SetBadgeCount(int count)
|
||||
{
|
||||
while (_badgePool.Count < count)
|
||||
{
|
||||
_badgePool.Add(CreateBadge());
|
||||
_cachedKeyNames.Add("");
|
||||
}
|
||||
|
||||
for (int i = 0; i < _badgePool.Count; i++)
|
||||
{
|
||||
_badgePool[i].Root.SetActive(i < count);
|
||||
}
|
||||
}
|
||||
|
||||
private BadgeEntry CreateBadge()
|
||||
{
|
||||
GameObject badge = new GameObject("KeyBadge");
|
||||
badge.transform.SetParent(_container.transform, false);
|
||||
|
||||
badge.AddComponent<RectTransform>();
|
||||
|
||||
Image bg = badge.AddComponent<Image>();
|
||||
bg.color = new Color(0f, 0f, 0f, 0f);
|
||||
bg.raycastTarget = false;
|
||||
|
||||
LayoutElement layoutElement = badge.AddComponent<LayoutElement>();
|
||||
|
||||
GameObject textGo = new GameObject("KeyText");
|
||||
textGo.transform.SetParent(badge.transform, false);
|
||||
|
||||
RectTransform textRect = textGo.AddComponent<RectTransform>();
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.offsetMin = Vector2.zero;
|
||||
textRect.offsetMax = Vector2.zero;
|
||||
|
||||
Text text = textGo.AddComponent<Text>();
|
||||
text.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
|
||||
text.fontSize = FONT_SIZE;
|
||||
text.fontStyle = FontStyle.Bold;
|
||||
text.color = Color.white;
|
||||
text.alignment = TextAnchor.MiddleCenter;
|
||||
text.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||
text.raycastTarget = false;
|
||||
|
||||
// Thicken glyph strokes so Unicode symbols don't look too thin
|
||||
Outline outline = textGo.AddComponent<Outline>();
|
||||
outline.effectColor = Color.white;
|
||||
outline.effectDistance = new Vector2(1f, -1f);
|
||||
|
||||
return new BadgeEntry(badge, bg, text, layoutElement);
|
||||
}
|
||||
|
||||
private void UpdateBadge(BadgeEntry badge, int index, string keyName, float alpha)
|
||||
{
|
||||
badge.Text.color = new Color(1f, 1f, 1f, alpha);
|
||||
|
||||
if (_cachedKeyNames[index] == keyName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_cachedKeyNames[index] = keyName;
|
||||
string symbol = KeySymbolMap.GetSymbol(keyName);
|
||||
badge.Text.text = symbol;
|
||||
badge.Text.fontSize = KeySymbolMap.IsGlyphSymbol(symbol) ? GLYPH_FONT_SIZE : FONT_SIZE;
|
||||
|
||||
TextGenerationSettings settings = badge.Text.GetGenerationSettings(new Vector2(float.MaxValue, float.MaxValue));
|
||||
float preferredWidth = badge.Text.cachedTextGeneratorForLayout.GetPreferredWidth(symbol, settings);
|
||||
float preferredHeight = badge.Text.cachedTextGeneratorForLayout.GetPreferredHeight(symbol, settings);
|
||||
|
||||
badge.Layout.preferredWidth = Mathf.Max(preferredWidth / badge.Text.pixelsPerUnit, preferredHeight / badge.Text.pixelsPerUnit);
|
||||
badge.Layout.preferredHeight = preferredHeight / badge.Text.pixelsPerUnit;
|
||||
}
|
||||
|
||||
private static float GetBadgeAlpha(
|
||||
string keyName,
|
||||
string? pressKey,
|
||||
bool isPressHeld,
|
||||
float pressElapsedSinceRelease)
|
||||
{
|
||||
if (pressKey == null || keyName != pressKey || isPressHeld || pressElapsedSinceRelease <= PRESS_DISPLAY_DURATION)
|
||||
{
|
||||
return 1f;
|
||||
}
|
||||
|
||||
float fadeT = Mathf.Clamp01((pressElapsedSinceRelease - PRESS_DISPLAY_DURATION) / FADE_DURATION);
|
||||
return 1f - fadeT;
|
||||
}
|
||||
|
||||
private readonly struct BadgeEntry
|
||||
{
|
||||
public readonly GameObject Root;
|
||||
public readonly Image Background;
|
||||
public readonly Text Text;
|
||||
public readonly LayoutElement Layout;
|
||||
|
||||
public BadgeEntry(GameObject root, Image background, Text text, LayoutElement layout)
|
||||
{
|
||||
Root = root;
|
||||
Background = background;
|
||||
Text = text;
|
||||
Layout = layout;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user