[Fix] Code visual

This commit is contained in:
2026-02-28 19:25:26 +07:00
parent bee20fd1f8
commit e24b30743b
39 changed files with 2611 additions and 2687 deletions
+311 -312
View File
@@ -11,348 +11,347 @@ using YachtDice.Modifiers;
namespace YachtDice.UI
{
public sealed class GameController : MonoBehaviour
{
[Header("Model")]
[SerializeField] private GameManager gameManager;
[SerializeField] private ScoringSystem scoringSystem;
[SerializeField] private DiceManager diceManager;
[Header("Views")]
[SerializeField] private ScoreCardView scoreCardView;
[SerializeField] private DicePanelView dicePanelView;
[SerializeField] private GameInfoView gameInfoView;
[Header("Economy & Modifiers")]
[SerializeField] private CurrencyBank currencyBank;
[SerializeField] private ShopController shopController;
[SerializeField] private InventoryController inventoryController;
[Header("Settings")]
[SerializeField] private int maxRollsPerTurn = 3;
[SerializeField] private int maxActiveModifierSlots = 5;
private static readonly YachtCategory[] UpperCategories =
public class GameController : MonoBehaviour
{
YachtCategory.Ones, YachtCategory.Twos, YachtCategory.Threes,
YachtCategory.Fours, YachtCategory.Fives, YachtCategory.Sixes
};
[Header("Model")]
[SerializeField] private GameManager gameManager;
[SerializeField] private ScoringSystem scoringSystem;
[SerializeField] private DiceManager diceManager;
private const int UpperBonusThreshold = 63;
private const int UpperBonusValue = 35;
[Header("Views")]
[SerializeField] private ScoreCardView scoreCardView;
[SerializeField] private DicePanelView dicePanelView;
[SerializeField] private GameInfoView gameInfoView;
private int totalCategoryCount;
[Header("Economy & Modifiers")]
[SerializeField] private CurrencyBank currencyBank;
[SerializeField] private ShopController shopController;
[SerializeField] private InventoryController inventoryController;
private InventoryModel inventoryModel;
private ShopModel shopModel;
[Header("Settings")]
[SerializeField] private int maxRollsPerTurn = 3;
[SerializeField] private int maxActiveModifierSlots = 5;
// ── Lifecycle ──────────────────────────────────────────────
private void Awake()
{
totalCategoryCount = Enum.GetValues(typeof(YachtCategory)).Length;
// Model → Controller
gameManager.OnTurnStarted += HandleTurnStarted;
gameManager.OnRollComplete += HandleRollComplete;
gameManager.OnScored += HandleScored;
gameManager.OnGameOver += HandleGameOver;
diceManager.OnDieSettled += HandleDieSettled;
// View → Controller
scoreCardView.OnCategorySelected += HandleCategorySelected;
dicePanelView.OnRollClicked += HandleRollClicked;
dicePanelView.OnDiceToggled += HandleDiceToggled;
gameInfoView.OnNewGameClicked += HandleNewGameClicked;
gameInfoView.OnShopClicked += HandleShopClicked;
gameInfoView.OnInventoryClicked += HandleInventoryClicked;
// Currency
if (currencyBank != null)
currencyBank.OnBalanceChanged += HandleCurrencyChanged;
InitializeModifierSystems();
}
private void OnDestroy()
{
gameManager.OnTurnStarted -= HandleTurnStarted;
gameManager.OnRollComplete -= HandleRollComplete;
gameManager.OnScored -= HandleScored;
gameManager.OnGameOver -= HandleGameOver;
diceManager.OnDieSettled -= HandleDieSettled;
scoreCardView.OnCategorySelected -= HandleCategorySelected;
dicePanelView.OnRollClicked -= HandleRollClicked;
dicePanelView.OnDiceToggled -= HandleDiceToggled;
gameInfoView.OnNewGameClicked -= HandleNewGameClicked;
gameInfoView.OnShopClicked -= HandleShopClicked;
gameInfoView.OnInventoryClicked -= HandleInventoryClicked;
if (currencyBank != null)
currencyBank.OnBalanceChanged -= HandleCurrencyChanged;
if (inventoryModel != null)
inventoryModel.OnInventoryChanged -= HandleInventoryChangedForSave;
}
// ── Modifier System Init ─────────────────────────────────
private void InitializeModifierSystems()
{
inventoryModel = new InventoryModel(maxActiveModifierSlots);
inventoryModel.OnInventoryChanged += HandleInventoryChangedForSave;
ShopCatalog catalog = shopController != null ? shopController.Catalog : null;
shopModel = new ShopModel(currencyBank, inventoryModel);
LoadSaveData(catalog);
if (inventoryController != null)
inventoryController.Initialize(inventoryModel);
if (shopController != null)
shopController.Initialize(shopModel);
if (currencyBank != null)
gameInfoView.SetCurrencyText(currencyBank.Balance);
}
private void LoadSaveData(ShopCatalog catalog)
{
SaveData save = SaveSystem.Load();
if (currencyBank != null && save.Currency > 0)
currencyBank.SetBalance(save.Currency);
if (catalog != null && save.OwnedModifiers.Count > 0)
private static readonly YachtCategory[] UpperCategories =
{
var runtimeList = new List<ModifierRuntime>();
var permanentIds = new HashSet<string>();
for (int i = 0; i < save.OwnedModifiers.Count; i++)
{
var entry = save.OwnedModifiers[i];
ModifierData data = catalog.FindById(entry.ModifierId);
if (data == null)
{
Debug.LogWarning($"Modifier '{entry.ModifierId}' not found in catalog, skipping.");
continue;
}
var runtime = new ModifierRuntime
{
ModifierId = entry.ModifierId,
IsActive = entry.IsActive,
RemainingUses = entry.RemainingUses,
Data = data
};
runtimeList.Add(runtime);
if (data.Durability == ModifierDurability.Permanent)
permanentIds.Add(data.Id);
}
inventoryModel.LoadState(runtimeList);
shopModel.LoadPurchasedPermanentIds(permanentIds);
}
}
private void PerformSave()
{
var save = new SaveData
{
Currency = currencyBank != null ? currencyBank.Balance : 0
YachtCategory.Ones, YachtCategory.Twos, YachtCategory.Threes,
YachtCategory.Fours, YachtCategory.Fives, YachtCategory.Sixes
};
var owned = inventoryModel.GetAllForSave();
for (int i = 0; i < owned.Count; i++)
private const int UpperBonusThreshold = 63;
private const int UpperBonusValue = 35;
private int totalCategoryCount;
private InventoryModel inventoryModel;
private ShopModel shopModel;
// ── Lifecycle ──────────────────────────────────────────────
private void Awake()
{
save.OwnedModifiers.Add(new ModifierSaveEntry
{
ModifierId = owned[i].ModifierId,
IsActive = owned[i].IsActive,
RemainingUses = owned[i].RemainingUses
});
totalCategoryCount = Enum.GetValues(typeof(YachtCategory)).Length;
// Model → Controller
gameManager.OnTurnStarted += HandleTurnStarted;
gameManager.OnRollComplete += HandleRollComplete;
gameManager.OnScored += HandleScored;
gameManager.OnGameOver += HandleGameOver;
diceManager.OnDieSettled += HandleDieSettled;
// View → Controller
scoreCardView.OnCategorySelected += HandleCategorySelected;
dicePanelView.OnRollClicked += HandleRollClicked;
dicePanelView.OnDiceToggled += HandleDiceToggled;
gameInfoView.OnNewGameClicked += HandleNewGameClicked;
gameInfoView.OnShopClicked += HandleShopClicked;
gameInfoView.OnInventoryClicked += HandleInventoryClicked;
// Currency
if (currencyBank != null)
currencyBank.OnBalanceChanged += HandleCurrencyChanged;
InitializeModifierSystems();
}
SaveSystem.Save(save);
}
// ── Model Event Handlers ──────────────────────────────────
private void HandleTurnStarted(int turn)
{
gameInfoView.SetTurnText(turn, totalCategoryCount);
dicePanelView.ResetForNewTurn();
dicePanelView.SetRollButtonState(true, 0, maxRollsPerTurn);
scoreCardView.ClearAllPreviews();
}
private void HandleRollComplete(int rollNumber)
{
bool canRollAgain = gameManager.CanRoll;
dicePanelView.SetRollButtonState(canRollAgain, rollNumber, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(true);
int[] values = diceManager.GetCurrentValues();
dicePanelView.SetAllDiceValues(values);
UpdatePreviewScores(values);
}
private void HandleDieSettled(int index, int value)
{
dicePanelView.SetDieValue(index, value);
}
private void HandleScored(YachtCategory category, int finalScore)
{
scoreCardView.SetCategoryScored(category, finalScore);
UpdateTotalDisplay();
PerformSave();
}
private void HandleGameOver(int totalScore)
{
dicePanelView.SetRollButtonState(false, maxRollsPerTurn, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(false);
scoreCardView.SetAllInteractable(false);
int displayTotal = CalculateDisplayTotal();
gameInfoView.ShowGameOver(displayTotal);
PerformSave();
}
// ── View Event Handlers ───────────────────────────────────
private void HandleRollClicked()
{
if (!gameManager.CanRoll) return;
dicePanelView.SetRollButtonState(false, gameManager.CurrentRoll, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(false);
scoreCardView.SetAllInteractable(false);
gameManager.Roll();
}
private void HandleDiceToggled(int index)
{
if (gameManager.CurrentRoll == 0) return;
if (diceManager.IsAnyRolling) return;
gameManager.ToggleDiceLock(index);
bool isLocked = diceManager.IsLocked(index);
dicePanelView.SetDieLocked(index, isLocked);
}
private void HandleCategorySelected(YachtCategory category)
{
if (!gameManager.CanScore) return;
if (scoringSystem.IsCategoryUsed(category)) return;
gameManager.ScoreInCategory(category);
}
private void HandleNewGameClicked()
{
gameInfoView.HideGameOver();
scoreCardView.ResetAll();
dicePanelView.ResetForNewGame();
gameManager.StartNewGame();
}
private void HandleShopClicked()
{
if (shopController != null)
private void OnDestroy()
{
var shopView = shopController.GetComponentInChildren<ShopView>(true);
if (shopView != null)
gameManager.OnTurnStarted -= HandleTurnStarted;
gameManager.OnRollComplete -= HandleRollComplete;
gameManager.OnScored -= HandleScored;
gameManager.OnGameOver -= HandleGameOver;
diceManager.OnDieSettled -= HandleDieSettled;
scoreCardView.OnCategorySelected -= HandleCategorySelected;
dicePanelView.OnRollClicked -= HandleRollClicked;
dicePanelView.OnDiceToggled -= HandleDiceToggled;
gameInfoView.OnNewGameClicked -= HandleNewGameClicked;
gameInfoView.OnShopClicked -= HandleShopClicked;
gameInfoView.OnInventoryClicked -= HandleInventoryClicked;
if (currencyBank != null)
currencyBank.OnBalanceChanged -= HandleCurrencyChanged;
if (inventoryModel != null)
inventoryModel.OnInventoryChanged -= HandleInventoryChangedForSave;
}
// ── Modifier System Init ─────────────────────────────────
private void InitializeModifierSystems()
{
inventoryModel = new InventoryModel(maxActiveModifierSlots);
inventoryModel.OnInventoryChanged += HandleInventoryChangedForSave;
ShopCatalog catalog = shopController != null ? shopController.Catalog : null;
shopModel = new ShopModel(currencyBank, inventoryModel);
LoadSaveData(catalog);
if (inventoryController != null)
inventoryController.Initialize(inventoryModel);
if (shopController != null)
shopController.Initialize(shopModel);
if (currencyBank != null)
gameInfoView.SetCurrencyText(currencyBank.Balance);
}
private void LoadSaveData(ShopCatalog catalog)
{
SaveData save = SaveSystem.Load();
if (currencyBank != null && save.Currency > 0)
currencyBank.SetBalance(save.Currency);
if (catalog != null && save.OwnedModifiers.Count > 0)
{
if (shopView.IsVisible) shopView.Hide();
else shopView.Show();
var runtimeList = new List<ModifierRuntime>();
var permanentIds = new HashSet<string>();
for (int i = 0; i < save.OwnedModifiers.Count; i++)
{
var entry = save.OwnedModifiers[i];
ModifierData data = catalog.FindById(entry.ModifierId);
if (data == null)
{
Debug.LogWarning($"Modifier '{entry.ModifierId}' not found in catalog, skipping.");
continue;
}
var runtime = new ModifierRuntime
{
ModifierId = entry.ModifierId,
IsActive = entry.IsActive,
RemainingUses = entry.RemainingUses,
Data = data
};
runtimeList.Add(runtime);
if (data.Durability == ModifierDurability.Permanent)
permanentIds.Add(data.Id);
}
inventoryModel.LoadState(runtimeList);
shopModel.LoadPurchasedPermanentIds(permanentIds);
}
}
}
private void HandleInventoryClicked()
{
if (inventoryController != null)
private void PerformSave()
{
var inventoryView = inventoryController.GetComponentInChildren<InventoryView>(true);
if (inventoryView != null)
var save = new SaveData
{
if (inventoryView.IsVisible) inventoryView.Hide();
else inventoryView.Show();
Currency = currencyBank != null ? currencyBank.Balance : 0
};
var owned = inventoryModel.GetAllForSave();
for (int i = 0; i < owned.Count; i++)
{
save.OwnedModifiers.Add(new ModifierSaveEntry
{
ModifierId = owned[i].ModifierId,
IsActive = owned[i].IsActive,
RemainingUses = owned[i].RemainingUses
});
}
SaveSystem.Save(save);
}
// ── Model Event Handlers ──────────────────────────────────
private void HandleTurnStarted(int turn)
{
gameInfoView.SetTurnText(turn, totalCategoryCount);
dicePanelView.ResetForNewTurn();
dicePanelView.SetRollButtonState(true, 0, maxRollsPerTurn);
scoreCardView.ClearAllPreviews();
}
private void HandleRollComplete(int rollNumber)
{
bool canRollAgain = gameManager.CanRoll;
dicePanelView.SetRollButtonState(canRollAgain, rollNumber, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(true);
int[] values = diceManager.GetCurrentValues();
dicePanelView.SetAllDiceValues(values);
UpdatePreviewScores(values);
}
private void HandleDieSettled(int index, int value)
{
dicePanelView.SetDieValue(index, value);
}
private void HandleScored(YachtCategory category, int finalScore)
{
scoreCardView.SetCategoryScored(category, finalScore);
UpdateTotalDisplay();
PerformSave();
}
private void HandleGameOver(int totalScore)
{
dicePanelView.SetRollButtonState(false, maxRollsPerTurn, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(false);
scoreCardView.SetAllInteractable(false);
int displayTotal = CalculateDisplayTotal();
gameInfoView.ShowGameOver(displayTotal);
PerformSave();
}
// ── View Event Handlers ───────────────────────────────────
private void HandleRollClicked()
{
if (!gameManager.CanRoll) return;
dicePanelView.SetRollButtonState(false, gameManager.CurrentRoll, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(false);
scoreCardView.SetAllInteractable(false);
gameManager.Roll();
}
private void HandleDiceToggled(int index)
{
if (gameManager.CurrentRoll == 0) return;
if (diceManager.IsAnyRolling) return;
gameManager.ToggleDiceLock(index);
bool isLocked = diceManager.IsLocked(index);
dicePanelView.SetDieLocked(index, isLocked);
}
private void HandleCategorySelected(YachtCategory category)
{
if (!gameManager.CanScore) return;
if (scoringSystem.IsCategoryUsed(category)) return;
gameManager.ScoreInCategory(category);
}
private void HandleNewGameClicked()
{
gameInfoView.HideGameOver();
scoreCardView.ResetAll();
dicePanelView.ResetForNewGame();
gameManager.StartNewGame();
}
private void HandleShopClicked()
{
if (shopController != null)
{
var shopView = shopController.GetComponentInChildren<ShopView>(true);
if (shopView != null)
{
if (shopView.IsVisible) shopView.Hide();
else shopView.Show();
}
}
}
}
private void HandleCurrencyChanged(int newBalance)
{
gameInfoView.SetCurrencyText(newBalance);
PerformSave();
}
private void HandleInventoryChangedForSave()
{
PerformSave();
}
// ── Helpers ────────────────────────────────────────────────
private void UpdatePreviewScores(int[] diceValues)
{
var previews = new Dictionary<YachtCategory, int>();
var categories = (YachtCategory[])Enum.GetValues(typeof(YachtCategory));
for (int i = 0; i < categories.Length; i++)
private void HandleInventoryClicked()
{
if (scoringSystem.IsCategoryUsed(categories[i])) continue;
ScoreResult result = scoringSystem.PreviewScore(diceValues, categories[i]);
previews[categories[i]] = result.FinalScore;
if (inventoryController != null)
{
var inventoryView = inventoryController.GetComponentInChildren<InventoryView>(true);
if (inventoryView != null)
{
if (inventoryView.IsVisible) inventoryView.Hide();
else inventoryView.Show();
}
}
}
scoreCardView.UpdatePreviews(previews);
}
private void UpdateTotalDisplay()
{
int upperSum = 0;
for (int i = 0; i < UpperCategories.Length; i++)
private void HandleCurrencyChanged(int newBalance)
{
int catScore = scoringSystem.GetCategoryScore(UpperCategories[i]);
if (catScore >= 0) upperSum += catScore;
gameInfoView.SetCurrencyText(newBalance);
PerformSave();
}
bool hasBonus = upperSum >= UpperBonusThreshold;
int displayTotal = CalculateDisplayTotal();
scoreCardView.UpdateTotalDisplay(displayTotal, upperSum, hasBonus);
}
private int CalculateDisplayTotal()
{
int total = scoringSystem.TotalScore;
int upperSum = 0;
for (int i = 0; i < UpperCategories.Length; i++)
private void HandleInventoryChangedForSave()
{
int catScore = scoringSystem.GetCategoryScore(UpperCategories[i]);
if (catScore >= 0) upperSum += catScore;
PerformSave();
}
if (upperSum >= UpperBonusThreshold)
total += UpperBonusValue;
// ── Helpers ────────────────────────────────────────────────
return total;
private void UpdatePreviewScores(int[] diceValues)
{
var previews = new Dictionary<YachtCategory, int>();
var categories = (YachtCategory[])Enum.GetValues(typeof(YachtCategory));
for (int i = 0; i < categories.Length; i++)
{
if (scoringSystem.IsCategoryUsed(categories[i])) continue;
ScoreResult result = scoringSystem.PreviewScore(diceValues, categories[i]);
previews[categories[i]] = result.FinalScore;
}
scoreCardView.UpdatePreviews(previews);
}
private void UpdateTotalDisplay()
{
int upperSum = 0;
for (int i = 0; i < UpperCategories.Length; i++)
{
int catScore = scoringSystem.GetCategoryScore(UpperCategories[i]);
if (catScore >= 0) upperSum += catScore;
}
bool hasBonus = upperSum >= UpperBonusThreshold;
int displayTotal = CalculateDisplayTotal();
scoreCardView.UpdateTotalDisplay(displayTotal, upperSum, hasBonus);
}
private int CalculateDisplayTotal()
{
int total = scoringSystem.TotalScore;
int upperSum = 0;
for (int i = 0; i < UpperCategories.Length; i++)
{
int catScore = scoringSystem.GetCategoryScore(UpperCategories[i]);
if (catScore >= 0) upperSum += catScore;
}
if (upperSum >= UpperBonusThreshold)
total += UpperBonusValue;
return total;
}
}
}
}