feat(demo): 改造 Lucky Dice 交互演示
This commit is contained in:
@@ -2,7 +2,8 @@
|
|||||||
"name": "FishDice.Demo",
|
"name": "FishDice.Demo",
|
||||||
"rootNamespace": "FishDice.Demo",
|
"rootNamespace": "FishDice.Demo",
|
||||||
"references": [
|
"references": [
|
||||||
"FishDice.Runtime"
|
"FishDice.Runtime",
|
||||||
|
"UnityEngine.UI"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|||||||
@@ -1,142 +1,307 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using FishDice.LuckyDice;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
namespace FishDice.Demo
|
namespace FishDice.Demo
|
||||||
{
|
{
|
||||||
public sealed class LuckyDiceDemoController : MonoBehaviour
|
public sealed class LuckyDiceDemoController : MonoBehaviour
|
||||||
{
|
{
|
||||||
private static readonly LuckyDiceDemoScenario[] Scenarios =
|
private static readonly string[] NormalPreviewFaces = { "2", "3", "4", "5", "6", "Clover" };
|
||||||
{
|
private static readonly string[] LuckyPreviewFaces = { "Rocket", "Thief" };
|
||||||
new LuckyDiceDemoScenario("Normal Reward", "Numbers pay the base reward.", 0, 1),
|
public const string BuiltinFontResourcePath = "LegacyRuntime.ttf";
|
||||||
new LuckyDiceDemoScenario("Clover Bonus", "A number plus Clover grants reward and bonus.", 0, 5),
|
|
||||||
new LuckyDiceDemoScenario("Lucky Dice: Rocket", "Two Clovers enter Lucky Dice and resolve Slap Down.", 5, 5, 0),
|
|
||||||
new LuckyDiceDemoScenario("Lucky Dice: Thief", "Two Clovers enter Lucky Dice and resolve Treasure Heist.", 5, 5, 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly List<LuckyDiceDemoSnapshot> _history = new List<LuckyDiceDemoSnapshot>();
|
private readonly SystemRandomSource _flowRandom = new SystemRandomSource(new System.Random());
|
||||||
private Vector2 _scroll;
|
private Text _titleText;
|
||||||
private LuckyDiceDemoSnapshot _current;
|
private Text _statusText;
|
||||||
private GUIStyle _titleStyle;
|
private Text _detailText;
|
||||||
private GUIStyle _labelStyle;
|
private Text _rewardText;
|
||||||
private GUIStyle _summaryStyle;
|
private Text[] _normalDiceTexts;
|
||||||
|
private Text[] _luckyDiceTexts;
|
||||||
|
private Button _primaryButton;
|
||||||
|
private Text _primaryButtonText;
|
||||||
|
private Coroutine _flowRoutine;
|
||||||
|
private LuckyDiceDemoSnapshot _lastSnapshot;
|
||||||
|
private Font _uiFont;
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
RunScenario(Scenarios[0]);
|
BuildUi();
|
||||||
|
ShowReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGUI()
|
private void StartRoll()
|
||||||
{
|
{
|
||||||
EnsureStyles();
|
if (_flowRoutine != null)
|
||||||
|
|
||||||
var margin = 24f;
|
|
||||||
var width = Mathf.Min(780f, Screen.width - margin * 2f);
|
|
||||||
var height = Mathf.Min(620f, Screen.height - margin * 2f);
|
|
||||||
GUILayout.BeginArea(new Rect(margin, margin, width, height), GUI.skin.box);
|
|
||||||
GUILayout.Label("FishDice Lucky Dice Demo", _titleStyle);
|
|
||||||
GUILayout.Label("Runtime path: normal roll -> combo facts -> rule actions -> optional Lucky Dice target mode.", _labelStyle);
|
|
||||||
GUILayout.Space(10f);
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
if (GUILayout.Button("Random Roll", GUILayout.Height(34f)))
|
|
||||||
{
|
{
|
||||||
RunRandom();
|
StopCoroutine(_flowRoutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var scenario in Scenarios)
|
_flowRoutine = StartCoroutine(PlayRollFlow());
|
||||||
{
|
|
||||||
if (GUILayout.Button(scenario.Title, GUILayout.Height(34f)))
|
|
||||||
{
|
|
||||||
RunScenario(scenario);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.Space(12f);
|
|
||||||
DrawSnapshot(_current);
|
|
||||||
GUILayout.Space(12f);
|
|
||||||
DrawHistory();
|
|
||||||
GUILayout.EndArea();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunScenario(LuckyDiceDemoScenario scenario)
|
private IEnumerator PlayRollFlow()
|
||||||
{
|
{
|
||||||
SetCurrent(LuckyDiceDemoRunner.RunScenario(scenario));
|
_primaryButton.interactable = false;
|
||||||
|
_primaryButtonText.text = "投掷中";
|
||||||
|
_rewardText.text = string.Empty;
|
||||||
|
_detailText.text = string.Empty;
|
||||||
|
SetLuckyDiceVisible(false);
|
||||||
|
SetStatus("摇动普通骰子");
|
||||||
|
|
||||||
|
_lastSnapshot = LuckyDiceDemoRunner.RunRandom(_flowRandom);
|
||||||
|
yield return AnimateDice(_normalDiceTexts, NormalPreviewFaces, 0.9f);
|
||||||
|
ApplyDiceTexts(_normalDiceTexts, _lastSnapshot.NormalFaces);
|
||||||
|
SetStatus("组合判定");
|
||||||
|
_detailText.text = _lastSnapshot.ComboLine;
|
||||||
|
yield return new WaitForSeconds(0.55f);
|
||||||
|
|
||||||
|
if (_lastSnapshot.OutcomeKind == "lucky_dice")
|
||||||
|
{
|
||||||
|
SetStatus("触发 Lucky Dice");
|
||||||
|
_rewardText.text = "双 Clover 命中";
|
||||||
|
yield return new WaitForSeconds(0.45f);
|
||||||
|
SetLuckyDiceVisible(true);
|
||||||
|
SetStatus("揭示特殊骰子");
|
||||||
|
yield return AnimateDice(_luckyDiceTexts, LuckyPreviewFaces, 1.0f);
|
||||||
|
ApplyDiceTexts(_luckyDiceTexts, _lastSnapshot.LuckyDiceSlotKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunRandom()
|
ShowResult(_lastSnapshot);
|
||||||
{
|
_flowRoutine = null;
|
||||||
SetCurrent(LuckyDiceDemoRunner.RunRandom());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCurrent(LuckyDiceDemoSnapshot snapshot)
|
private IEnumerator AnimateDice(Text[] diceTexts, string[] previewFaces, float duration)
|
||||||
{
|
{
|
||||||
_current = snapshot;
|
var elapsed = 0f;
|
||||||
_history.Insert(0, snapshot);
|
while (elapsed < duration)
|
||||||
if (_history.Count > 8)
|
|
||||||
{
|
{
|
||||||
_history.RemoveAt(_history.Count - 1);
|
for (var i = 0; i < diceTexts.Length; i++)
|
||||||
|
{
|
||||||
|
diceTexts[i].text = previewFaces[Random.Range(0, previewFaces.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(0.08f);
|
||||||
|
elapsed += 0.08f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawSnapshot(LuckyDiceDemoSnapshot snapshot)
|
private void ShowReady()
|
||||||
{
|
{
|
||||||
if (snapshot == null)
|
_titleText.text = "Lucky Dice";
|
||||||
|
SetStatus("准备投骰");
|
||||||
|
_detailText.text = "普通骰子会随机落点,命中双 Clover 后进入 Lucky Dice。";
|
||||||
|
_rewardText.text = string.Empty;
|
||||||
|
ApplyDiceTexts(_normalDiceTexts, new[] { "?", "?" });
|
||||||
|
ApplyDiceTexts(_luckyDiceTexts, new[] { "?", "?", "?" });
|
||||||
|
SetLuckyDiceVisible(false);
|
||||||
|
_primaryButton.interactable = true;
|
||||||
|
_primaryButtonText.text = "投骰";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowResult(LuckyDiceDemoSnapshot snapshot)
|
||||||
|
{
|
||||||
|
SetStatus(ResolveResultStatus(snapshot));
|
||||||
|
_detailText.text = $"{snapshot.FaceLine}\n{snapshot.RuleLine}\n{snapshot.EffectLine}";
|
||||||
|
_rewardText.text = snapshot.TargetModeLine == "Target Mode: -"
|
||||||
|
? snapshot.Summary
|
||||||
|
: $"{snapshot.Summary}\n{snapshot.TargetModeLine}";
|
||||||
|
_primaryButton.interactable = true;
|
||||||
|
_primaryButtonText.text = "再投一次";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolveResultStatus(LuckyDiceDemoSnapshot snapshot)
|
||||||
|
{
|
||||||
|
switch (snapshot.OutcomeKind)
|
||||||
|
{
|
||||||
|
case "lucky_dice":
|
||||||
|
return "进入目标玩法";
|
||||||
|
case "clover_bonus":
|
||||||
|
return "获得 Clover Bonus";
|
||||||
|
case "normal_reward":
|
||||||
|
return "获得普通奖励";
|
||||||
|
default:
|
||||||
|
return "本轮结束";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildUi()
|
||||||
|
{
|
||||||
|
EnsureEventSystem();
|
||||||
|
|
||||||
|
var canvasObject = new GameObject("LuckyDiceCanvas");
|
||||||
|
canvasObject.transform.SetParent(transform, false);
|
||||||
|
var canvas = canvasObject.AddComponent<Canvas>();
|
||||||
|
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||||
|
canvas.pixelPerfect = true;
|
||||||
|
var scaler = canvasObject.AddComponent<CanvasScaler>();
|
||||||
|
scaler.uiScaleMode = CanvasScaler.ScaleMode.ConstantPixelSize;
|
||||||
|
scaler.scaleFactor = 1f;
|
||||||
|
scaler.referencePixelsPerUnit = 100f;
|
||||||
|
canvasObject.AddComponent<GraphicRaycaster>();
|
||||||
|
|
||||||
|
var root = CreatePanel("Root", canvasObject.transform, new Color(0.06f, 0.09f, 0.13f, 1f));
|
||||||
|
Stretch(root.rectTransform);
|
||||||
|
|
||||||
|
var board = CreatePanel("Board", root.transform, new Color(0.12f, 0.16f, 0.22f, 0.96f));
|
||||||
|
Center(board.rectTransform, new Vector2(760f, 600f));
|
||||||
|
|
||||||
|
_titleText = CreateText("Title", board.transform, "Lucky Dice", 34, FontStyle.Bold, Color.white);
|
||||||
|
SetRect(_titleText.rectTransform, new Vector2(0f, 194f), new Vector2(680f, 48f));
|
||||||
|
|
||||||
|
_statusText = CreateText("Status", board.transform, string.Empty, 24, FontStyle.Bold, new Color(1f, 0.84f, 0.38f));
|
||||||
|
SetRect(_statusText.rectTransform, new Vector2(0f, 142f), new Vector2(680f, 40f));
|
||||||
|
|
||||||
|
_normalDiceTexts = new[]
|
||||||
|
{
|
||||||
|
CreateDiceText("NormalDiceA", board.transform, new Vector2(-96f, 64f), new Color(0.96f, 0.97f, 1f)),
|
||||||
|
CreateDiceText("NormalDiceB", board.transform, new Vector2(96f, 64f), new Color(0.96f, 0.97f, 1f))
|
||||||
|
};
|
||||||
|
|
||||||
|
_luckyDiceTexts = new[]
|
||||||
|
{
|
||||||
|
CreateDiceText("LuckySlotA", board.transform, new Vector2(-150f, -48f), new Color(1f, 0.86f, 0.46f)),
|
||||||
|
CreateDiceText("LuckySlotB", board.transform, new Vector2(0f, -48f), new Color(1f, 0.86f, 0.46f)),
|
||||||
|
CreateDiceText("LuckySlotC", board.transform, new Vector2(150f, -48f), new Color(1f, 0.86f, 0.46f))
|
||||||
|
};
|
||||||
|
|
||||||
|
_detailText = CreateText("Detail", board.transform, string.Empty, 16, FontStyle.Normal, new Color(0.82f, 0.88f, 0.94f));
|
||||||
|
SetRect(_detailText.rectTransform, new Vector2(0f, -142f), new Vector2(650f, 86f));
|
||||||
|
|
||||||
|
_rewardText = CreateText("Reward", board.transform, string.Empty, 19, FontStyle.Bold, new Color(0.55f, 0.92f, 0.75f));
|
||||||
|
SetRect(_rewardText.rectTransform, new Vector2(0f, -210f), new Vector2(650f, 56f));
|
||||||
|
|
||||||
|
_primaryButton = CreateButton("PrimaryButton", board.transform, "投骰", new Vector2(0f, -254f), new Vector2(190f, 48f));
|
||||||
|
_primaryButton.onClick.AddListener(StartRoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EnsureEventSystem()
|
||||||
|
{
|
||||||
|
if (FindObjectOfType<EventSystem>() != null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.Label(snapshot.Title, _summaryStyle);
|
var eventSystemObject = new GameObject("EventSystem");
|
||||||
GUILayout.Label(snapshot.Description, _labelStyle);
|
eventSystemObject.AddComponent<EventSystem>();
|
||||||
GUILayout.Space(6f);
|
eventSystemObject.AddComponent<StandaloneInputModule>();
|
||||||
GUILayout.Label(snapshot.FaceLine, _labelStyle);
|
|
||||||
GUILayout.Label(snapshot.ComboLine, _labelStyle);
|
|
||||||
GUILayout.Label(snapshot.RuleLine, _labelStyle);
|
|
||||||
GUILayout.Label(snapshot.EffectLine, _labelStyle);
|
|
||||||
GUILayout.Label(snapshot.LuckyDiceLine, _labelStyle);
|
|
||||||
GUILayout.Label(snapshot.TargetModeLine, _labelStyle);
|
|
||||||
GUILayout.Space(6f);
|
|
||||||
GUILayout.Label(snapshot.Summary, _summaryStyle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawHistory()
|
private Text CreateDiceText(string name, Transform parent, Vector2 anchoredPosition, Color faceColor)
|
||||||
{
|
{
|
||||||
GUILayout.Label("Recent Rolls", _summaryStyle);
|
var background = CreatePanel(name, parent, new Color(0.2f, 0.25f, 0.33f, 1f));
|
||||||
_scroll = GUILayout.BeginScrollView(_scroll, GUILayout.Height(180f));
|
SetRect(background.rectTransform, anchoredPosition, new Vector2(116f, 84f));
|
||||||
foreach (var snapshot in _history)
|
|
||||||
{
|
var text = CreateText(name + "Text", background.transform, "?", 24, FontStyle.Bold, faceColor);
|
||||||
GUILayout.Label($"{snapshot.Title} | {snapshot.FaceLine} | {snapshot.Summary}", _labelStyle);
|
Stretch(text.rectTransform);
|
||||||
}
|
return text;
|
||||||
GUILayout.EndScrollView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureStyles()
|
private Button CreateButton(string name, Transform parent, string label, Vector2 anchoredPosition, Vector2 size)
|
||||||
{
|
{
|
||||||
if (_titleStyle != null)
|
var image = CreatePanel(name, parent, new Color(0.92f, 0.56f, 0.16f, 1f));
|
||||||
{
|
SetRect(image.rectTransform, anchoredPosition, size);
|
||||||
return;
|
var button = image.gameObject.AddComponent<Button>();
|
||||||
|
_primaryButtonText = CreateText(name + "Text", image.transform, label, 20, FontStyle.Bold, Color.white);
|
||||||
|
Stretch(_primaryButtonText.rectTransform);
|
||||||
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
_titleStyle = new GUIStyle(GUI.skin.label)
|
private Image CreatePanel(string name, Transform parent, Color color)
|
||||||
{
|
{
|
||||||
fontSize = 26,
|
var gameObject = new GameObject(name, typeof(RectTransform), typeof(Image));
|
||||||
fontStyle = FontStyle.Bold,
|
gameObject.transform.SetParent(parent, false);
|
||||||
normal = { textColor = Color.white },
|
var image = gameObject.GetComponent<Image>();
|
||||||
wordWrap = true
|
image.color = color;
|
||||||
};
|
return image;
|
||||||
_labelStyle = new GUIStyle(GUI.skin.label)
|
}
|
||||||
|
|
||||||
|
private Text CreateText(string name, Transform parent, string text, int fontSize, FontStyle fontStyle, Color color)
|
||||||
{
|
{
|
||||||
fontSize = 15,
|
var gameObject = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(Text));
|
||||||
normal = { textColor = new Color(0.86f, 0.9f, 0.95f) },
|
gameObject.transform.SetParent(parent, false);
|
||||||
wordWrap = true
|
var label = gameObject.GetComponent<Text>();
|
||||||
};
|
label.font = GetUiFont();
|
||||||
_summaryStyle = new GUIStyle(GUI.skin.label)
|
label.text = text;
|
||||||
|
label.fontSize = fontSize;
|
||||||
|
label.fontStyle = fontStyle;
|
||||||
|
label.color = color;
|
||||||
|
label.alignment = TextAnchor.MiddleCenter;
|
||||||
|
label.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||||
|
label.verticalOverflow = VerticalWrapMode.Overflow;
|
||||||
|
label.alignByGeometry = true;
|
||||||
|
label.raycastTarget = false;
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Font GetUiFont()
|
||||||
{
|
{
|
||||||
fontSize = 18,
|
if (_uiFont == null)
|
||||||
fontStyle = FontStyle.Bold,
|
{
|
||||||
normal = { textColor = new Color(1f, 0.86f, 0.35f) },
|
_uiFont = Resources.GetBuiltinResource<Font>(BuiltinFontResourcePath);
|
||||||
wordWrap = true
|
}
|
||||||
};
|
|
||||||
|
return _uiFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetStatus(string text)
|
||||||
|
{
|
||||||
|
_statusText.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyDiceTexts(Text[] diceTexts, string[] values)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < diceTexts.Length; i++)
|
||||||
|
{
|
||||||
|
diceTexts[i].text = i < values.Length ? FormatFace(values[i]) : "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatFace(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
return char.ToUpperInvariant(value[0]) + value.Substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetLuckyDiceVisible(bool visible)
|
||||||
|
{
|
||||||
|
foreach (var text in _luckyDiceTexts)
|
||||||
|
{
|
||||||
|
text.transform.parent.gameObject.SetActive(visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Center(RectTransform rectTransform, Vector2 size)
|
||||||
|
{
|
||||||
|
rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
|
||||||
|
rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
|
||||||
|
rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||||
|
rectTransform.sizeDelta = size;
|
||||||
|
rectTransform.anchoredPosition = Vector2.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetRect(RectTransform rectTransform, Vector2 position, Vector2 size)
|
||||||
|
{
|
||||||
|
rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
|
||||||
|
rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
|
||||||
|
rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||||
|
rectTransform.sizeDelta = size;
|
||||||
|
rectTransform.anchoredPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Stretch(RectTransform rectTransform)
|
||||||
|
{
|
||||||
|
rectTransform.anchorMin = Vector2.zero;
|
||||||
|
rectTransform.anchorMax = Vector2.one;
|
||||||
|
rectTransform.offsetMin = Vector2.zero;
|
||||||
|
rectTransform.offsetMax = Vector2.zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,15 @@ namespace FishDice.Demo
|
|||||||
return Run(scenario, new SystemRandomSource());
|
return Run(scenario, new SystemRandomSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LuckyDiceDemoSnapshot RunRandom(IRandomSource random)
|
||||||
|
{
|
||||||
|
var scenario = new LuckyDiceDemoScenario(
|
||||||
|
"Random Roll",
|
||||||
|
"Uses the default FishDice runtime config and the supplied random source.");
|
||||||
|
|
||||||
|
return Run(scenario, random);
|
||||||
|
}
|
||||||
|
|
||||||
private static LuckyDiceDemoSnapshot Run(LuckyDiceDemoScenario scenario, IRandomSource random)
|
private static LuckyDiceDemoSnapshot Run(LuckyDiceDemoScenario scenario, IRandomSource random)
|
||||||
{
|
{
|
||||||
var flow = LuckyDiceRuntimeFactory.CreateDefault(random).CreateDefaultFlow();
|
var flow = LuckyDiceRuntimeFactory.CreateDefault(random).CreateDefaultFlow();
|
||||||
@@ -43,6 +52,11 @@ namespace FishDice.Demo
|
|||||||
var luckyDiceLine = FormatLuckyDice(result.LuckyDiceResult);
|
var luckyDiceLine = FormatLuckyDice(result.LuckyDiceResult);
|
||||||
var targetModeLine = "Target Mode: " + (result.TargetMode == null ? "-" : result.TargetMode.ModeKey);
|
var targetModeLine = "Target Mode: " + (result.TargetMode == null ? "-" : result.TargetMode.ModeKey);
|
||||||
var summary = FormatSummary(result);
|
var summary = FormatSummary(result);
|
||||||
|
var normalFaces = result.RollResult.Faces.Select(face => face.Key).ToArray();
|
||||||
|
var luckyDiceSlots = result.LuckyDiceResult == null || result.LuckyDiceResult.SlotResultKeys == null
|
||||||
|
? new string[0]
|
||||||
|
: result.LuckyDiceResult.SlotResultKeys.ToArray();
|
||||||
|
var outcomeKind = ResolveOutcomeKind(result);
|
||||||
|
|
||||||
return new LuckyDiceDemoSnapshot(
|
return new LuckyDiceDemoSnapshot(
|
||||||
scenario.Title,
|
scenario.Title,
|
||||||
@@ -53,7 +67,10 @@ namespace FishDice.Demo
|
|||||||
effectLine,
|
effectLine,
|
||||||
luckyDiceLine,
|
luckyDiceLine,
|
||||||
targetModeLine,
|
targetModeLine,
|
||||||
summary);
|
summary,
|
||||||
|
normalFaces,
|
||||||
|
luckyDiceSlots,
|
||||||
|
outcomeKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string FormatLuckyDice(LuckyDiceSelectionResult result)
|
private static string FormatLuckyDice(LuckyDiceSelectionResult result)
|
||||||
@@ -86,6 +103,26 @@ namespace FishDice.Demo
|
|||||||
return "No configured outcome.";
|
return "No configured outcome.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string ResolveOutcomeKind(RollFlowResult result)
|
||||||
|
{
|
||||||
|
if (result.TargetMode != null)
|
||||||
|
{
|
||||||
|
return "lucky_dice";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Effects.OfType<MultiplierEffect>().Any())
|
||||||
|
{
|
||||||
|
return "clover_bonus";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Effects.OfType<RewardEffect>().Any())
|
||||||
|
{
|
||||||
|
return "normal_reward";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "none";
|
||||||
|
}
|
||||||
|
|
||||||
private static string JoinOrDash(IEnumerable<string> values)
|
private static string JoinOrDash(IEnumerable<string> values)
|
||||||
{
|
{
|
||||||
var materialized = values.Where(value => !string.IsNullOrEmpty(value)).ToArray();
|
var materialized = values.Where(value => !string.IsNullOrEmpty(value)).ToArray();
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ namespace FishDice.Demo
|
|||||||
string effectLine,
|
string effectLine,
|
||||||
string luckyDiceLine,
|
string luckyDiceLine,
|
||||||
string targetModeLine,
|
string targetModeLine,
|
||||||
string summary)
|
string summary,
|
||||||
|
string[] normalFaces,
|
||||||
|
string[] luckyDiceSlotKeys,
|
||||||
|
string outcomeKind)
|
||||||
{
|
{
|
||||||
Title = title;
|
Title = title;
|
||||||
Description = description;
|
Description = description;
|
||||||
@@ -22,6 +25,9 @@ namespace FishDice.Demo
|
|||||||
LuckyDiceLine = luckyDiceLine;
|
LuckyDiceLine = luckyDiceLine;
|
||||||
TargetModeLine = targetModeLine;
|
TargetModeLine = targetModeLine;
|
||||||
Summary = summary;
|
Summary = summary;
|
||||||
|
NormalFaces = normalFaces ?? new string[0];
|
||||||
|
LuckyDiceSlotKeys = luckyDiceSlotKeys ?? new string[0];
|
||||||
|
OutcomeKind = string.IsNullOrEmpty(outcomeKind) ? "none" : outcomeKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Title { get; }
|
public string Title { get; }
|
||||||
@@ -41,5 +47,11 @@ namespace FishDice.Demo
|
|||||||
public string TargetModeLine { get; }
|
public string TargetModeLine { get; }
|
||||||
|
|
||||||
public string Summary { get; }
|
public string Summary { get; }
|
||||||
|
|
||||||
|
public string[] NormalFaces { get; }
|
||||||
|
|
||||||
|
public string[] LuckyDiceSlotKeys { get; }
|
||||||
|
|
||||||
|
public string OutcomeKind { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,5 +32,28 @@ namespace FishDice.Tests.LuckyDice
|
|||||||
Assert.That(snapshot.LuckyDiceLine, Is.EqualTo("Lucky Dice: rocket x3"));
|
Assert.That(snapshot.LuckyDiceLine, Is.EqualTo("Lucky Dice: rocket x3"));
|
||||||
Assert.That(snapshot.TargetModeLine, Is.EqualTo("Target Mode: slap_down_normal"));
|
Assert.That(snapshot.TargetModeLine, Is.EqualTo("Target Mode: slap_down_normal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DemoRunner_exposes_structured_faces_for_player_ui_flow()
|
||||||
|
{
|
||||||
|
var normal = LuckyDiceDemoRunner.RunScenario(
|
||||||
|
new LuckyDiceDemoScenario("Normal Reward", "Numbers pay the base reward.", 0, 1));
|
||||||
|
var lucky = LuckyDiceDemoRunner.RunScenario(
|
||||||
|
new LuckyDiceDemoScenario("Lucky Dice", "Clover pair enters the special dice flow.", 5, 5, 0));
|
||||||
|
|
||||||
|
Assert.That(normal.NormalFaces, Is.EqualTo(new[] { "2", "3" }));
|
||||||
|
Assert.That(normal.LuckyDiceSlotKeys, Is.Empty);
|
||||||
|
Assert.That(normal.OutcomeKind, Is.EqualTo("normal_reward"));
|
||||||
|
|
||||||
|
Assert.That(lucky.NormalFaces, Is.EqualTo(new[] { "clover", "clover" }));
|
||||||
|
Assert.That(lucky.LuckyDiceSlotKeys, Is.EqualTo(new[] { "rocket", "rocket", "rocket" }));
|
||||||
|
Assert.That(lucky.OutcomeKind, Is.EqualTo("lucky_dice"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DemoController_uses_current_unity_builtin_font_for_player_ui_text()
|
||||||
|
{
|
||||||
|
Assert.That(LuckyDiceDemoController.BuiltinFontResourcePath, Is.EqualTo("LegacyRuntime.ttf"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user