demo
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections;
|
||||
using ReplacedPerson.Core;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ReplacedPerson.Runtime
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public sealed class ReplacedSlotResolutionMotion : MonoBehaviour
|
||||
{
|
||||
private Image? _background;
|
||||
private TMP_Text? _mainText;
|
||||
private RectTransform? _leftToken;
|
||||
private RectTransform? _rightToken;
|
||||
private CanvasGroup? _leftGroup;
|
||||
private CanvasGroup? _rightGroup;
|
||||
private TMP_Text? _leftLabel;
|
||||
private TMP_Text? _rightLabel;
|
||||
private Coroutine? _animation;
|
||||
private Color _baseColor;
|
||||
private float _baseFontSize;
|
||||
|
||||
public bool IsPlaying => _animation != null;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_background = GetComponent<Image>();
|
||||
_mainText = transform.Find("Text")?.GetComponent<TMP_Text>();
|
||||
if (_background != null) _baseColor = _background.color;
|
||||
if (_mainText != null) _baseFontSize = _mainText.fontSize;
|
||||
CreateToken("PlayerToken", out _leftToken, out _leftGroup, out _leftLabel);
|
||||
CreateToken("EnemyToken", out _rightToken, out _rightGroup, out _rightLabel);
|
||||
SetTokensActive(false);
|
||||
}
|
||||
|
||||
public void Play(ReplacedSlotResolution resolution, int localPlayer)
|
||||
{
|
||||
if (_animation != null) StopCoroutine(_animation);
|
||||
_animation = StartCoroutine(Animate(resolution, localPlayer));
|
||||
}
|
||||
|
||||
private IEnumerator Animate(ReplacedSlotResolution resolution, int localPlayer)
|
||||
{
|
||||
if (_background == null || _mainText == null || _leftToken == null || _rightToken == null ||
|
||||
_leftGroup == null || _rightGroup == null || _leftLabel == null || _rightLabel == null)
|
||||
yield break;
|
||||
|
||||
var localIsOne = localPlayer == 0;
|
||||
var localType = localIsOne ? resolution.PlayerOneType : resolution.PlayerTwoType;
|
||||
var enemyType = localIsOne ? resolution.PlayerTwoType : resolution.PlayerOneType;
|
||||
var localRoll = localIsOne ? resolution.PlayerOneRoll : resolution.PlayerTwoRoll;
|
||||
var enemyRoll = localIsOne ? resolution.PlayerTwoRoll : resolution.PlayerOneRoll;
|
||||
var localValue = localIsOne ? resolution.PlayerOneValue : resolution.PlayerTwoValue;
|
||||
var enemyValue = localIsOne ? resolution.PlayerTwoValue : resolution.PlayerOneValue;
|
||||
var localRerolled = localIsOne ? resolution.PlayerOneRerolled : resolution.PlayerTwoRerolled;
|
||||
var enemyRerolled = localIsOne ? resolution.PlayerTwoRerolled : resolution.PlayerOneRerolled;
|
||||
var localDamage = localIsOne ? resolution.DamageToPlayerOne : resolution.DamageToPlayerTwo;
|
||||
var enemyDamage = localIsOne ? resolution.DamageToPlayerTwo : resolution.DamageToPlayerOne;
|
||||
|
||||
SetTokensActive(true);
|
||||
_leftGroup.alpha = 1f;
|
||||
_rightGroup.alpha = 1f;
|
||||
_leftLabel.text = "我方\n" + TypeName(localType);
|
||||
_rightLabel.text = "敌方\n" + TypeName(enemyType);
|
||||
_leftToken.GetComponent<Image>().color = TypeColor(localType);
|
||||
_rightToken.GetComponent<Image>().color = TypeColor(enemyType);
|
||||
_mainText.text = $"槽 {resolution.SlotIndex + 1}\n对位";
|
||||
_leftToken.anchoredPosition = new Vector2(-280, 0);
|
||||
_rightToken.anchoredPosition = new Vector2(280, 0);
|
||||
transform.localScale = Vector3.one;
|
||||
|
||||
_mainText.fontSize = Mathf.Max(_baseFontSize, 23f);
|
||||
const float approachDuration = .28f;
|
||||
var elapsed = 0f;
|
||||
while (elapsed < approachDuration)
|
||||
{
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
var t = Mathf.SmoothStep(0, 1, Mathf.Clamp01(elapsed / approachDuration));
|
||||
_leftToken.anchoredPosition = Vector2.Lerp(new Vector2(-280, 0), new Vector2(-82, 0), t);
|
||||
_rightToken.anchoredPosition = Vector2.Lerp(new Vector2(280, 0), new Vector2(82, 0), t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
transform.localScale = Vector3.one * 1.045f;
|
||||
_mainText.text = $"槽 {resolution.SlotIndex + 1}\n投掷中";
|
||||
_leftLabel.fontSize = 21;
|
||||
_rightLabel.fontSize = 21;
|
||||
yield return new WaitForSecondsRealtime(.04f);
|
||||
transform.localScale = Vector3.one;
|
||||
for (var frame = 0; frame < 8; frame++)
|
||||
{
|
||||
var leftFace = (frame * 5 + 1) % 6 + 1;
|
||||
var rightFace = (frame * 3 + 4) % 6 + 1;
|
||||
_leftLabel.text = $"我方\nD6 {leftFace}";
|
||||
_rightLabel.text = $"敌方\nD6 {rightFace}";
|
||||
_leftToken.localRotation = Quaternion.Euler(0, 0, frame % 2 == 0 ? -2f : 2f);
|
||||
_rightToken.localRotation = Quaternion.Euler(0, 0, frame % 2 == 0 ? 2f : -2f);
|
||||
yield return new WaitForSecondsRealtime(.075f);
|
||||
}
|
||||
|
||||
_leftToken.localRotation = Quaternion.identity;
|
||||
_rightToken.localRotation = Quaternion.identity;
|
||||
_leftLabel.text = $"我方\nD6 {Roll(localRoll, localRerolled)}";
|
||||
_rightLabel.text = $"敌方\nD6 {Roll(enemyRoll, enemyRerolled)}";
|
||||
_mainText.fontSize = Mathf.Max(_baseFontSize, 27f);
|
||||
_mainText.text = $"槽 {resolution.SlotIndex + 1}\n骰点 {localRoll} : {enemyRoll}";
|
||||
yield return new WaitForSecondsRealtime(.75f);
|
||||
var flash = localDamage > 0 ? new Color(.55f, .10f, .09f, 1f) : enemyDamage > 0 ? new Color(.45f, .32f, .10f, 1f) : new Color(.24f, .29f, .27f, 1f);
|
||||
_background.color = flash;
|
||||
_leftLabel.text = $"我方\n{TypeName(localType)} {localValue}";
|
||||
_rightLabel.text = $"敌方\n{TypeName(enemyType)} {enemyValue}";
|
||||
_mainText.fontSize = Mathf.Max(_baseFontSize, 21f);
|
||||
_mainText.text = $"槽 {resolution.SlotIndex + 1}\n{TypeName(localType)} {localValue} : {enemyValue} {TypeName(enemyType)}\n{resolution.Summary}";
|
||||
yield return new WaitForSecondsRealtime(.55f);
|
||||
|
||||
elapsed = 0f;
|
||||
const float fadeDuration = .22f;
|
||||
while (elapsed < fadeDuration)
|
||||
{
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
var t = Mathf.Clamp01(elapsed / fadeDuration);
|
||||
_leftGroup.alpha = 1f - t;
|
||||
_rightGroup.alpha = 1f - t;
|
||||
_background.color = Color.Lerp(flash, _baseColor, t);
|
||||
yield return null;
|
||||
}
|
||||
_background.color = _baseColor;
|
||||
_mainText.fontSize = _baseFontSize;
|
||||
transform.localScale = Vector3.one;
|
||||
SetTokensActive(false);
|
||||
_animation = null;
|
||||
}
|
||||
|
||||
private void CreateToken(string tokenName, out RectTransform token, out CanvasGroup group, out TMP_Text label)
|
||||
{
|
||||
var tokenObject = new GameObject(tokenName, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(CanvasGroup));
|
||||
token = tokenObject.GetComponent<RectTransform>();
|
||||
token.SetParent(transform, false);
|
||||
token.anchorMin = token.anchorMax = new Vector2(.5f, .5f);
|
||||
token.sizeDelta = new Vector2(142, 86);
|
||||
tokenObject.GetComponent<Image>().raycastTarget = false;
|
||||
group = tokenObject.GetComponent<CanvasGroup>();
|
||||
group.blocksRaycasts = false;
|
||||
|
||||
var labelObject = new GameObject("Label", typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI));
|
||||
var labelRect = labelObject.GetComponent<RectTransform>();
|
||||
labelRect.SetParent(token, false);
|
||||
labelRect.anchorMin = Vector2.zero;
|
||||
labelRect.anchorMax = Vector2.one;
|
||||
labelRect.offsetMin = new Vector2(8, 5);
|
||||
labelRect.offsetMax = new Vector2(-8, -5);
|
||||
label = labelObject.GetComponent<TextMeshProUGUI>();
|
||||
label.font = _mainText != null ? _mainText.font : null;
|
||||
label.fontSize = 20;
|
||||
label.alignment = TextAlignmentOptions.Center;
|
||||
label.color = new Color(.96f, .94f, .88f, 1f);
|
||||
label.raycastTarget = false;
|
||||
}
|
||||
|
||||
private void SetTokensActive(bool active)
|
||||
{
|
||||
if (_leftToken != null) _leftToken.gameObject.SetActive(active);
|
||||
if (_rightToken != null) _rightToken.gameObject.SetActive(active);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_animation != null) StopCoroutine(_animation);
|
||||
_animation = null;
|
||||
if (_background != null) _background.color = _baseColor;
|
||||
if (_mainText != null) _mainText.fontSize = _baseFontSize;
|
||||
transform.localScale = Vector3.one;
|
||||
if (_leftToken != null) _leftToken.localRotation = Quaternion.identity;
|
||||
if (_rightToken != null) _rightToken.localRotation = Quaternion.identity;
|
||||
SetTokensActive(false);
|
||||
}
|
||||
|
||||
private static string Roll(int value, bool rerolled) => rerolled ? value + "(重掷)" : value.ToString();
|
||||
|
||||
private static string TypeName(ReplacedEffectType type) => type switch
|
||||
{
|
||||
ReplacedEffectType.Attack => "攻击",
|
||||
ReplacedEffectType.Dodge => "闪避",
|
||||
ReplacedEffectType.Counter => "反击",
|
||||
_ => "未知"
|
||||
};
|
||||
|
||||
private static Color TypeColor(ReplacedEffectType type) => type switch
|
||||
{
|
||||
ReplacedEffectType.Attack => new Color(.63f, .13f, .11f, .98f),
|
||||
ReplacedEffectType.Dodge => new Color(.18f, .31f, .29f, .98f),
|
||||
ReplacedEffectType.Counter => new Color(.42f, .31f, .16f, .98f),
|
||||
_ => new Color(.22f, .23f, .23f, .98f)
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user