MiniGames/Assets/Scripts/ClawGrab/ClawScoreManager.cs

234 lines
8.0 KiB
C#
Raw Normal View History

using UnityEngine;
using System;
using System.Collections.Generic;
2025-09-06 00:08:22 +05:00
using Unity.VisualScripting;
using DG.Tweening;
public class ClawScoreManager : MonoBehaviour
{
public static ClawScoreManager Instance;
public event Action<int> OnScoreChanged; // passes TOTAL score
public int CurrentScore => score;
[Header("Scoring")]
public int wolfPoints = 100;
public int goldenWolfJackpot = 1000;
public int starPoints = 50;
public int comboBonus = 300;
public int starSuperBonus = 500;
[Header("Multipliers")]
public float crystalNextGrabMultiplier = 2f;
private bool crystalPrimed = false;
[Header("Timers & Effects")]
public float addTimeSeconds = 5f; // Sand Dial
public float slowDuration = 5f; // Clock
public float turboDuration = 5f; // Turbo
public float freezeDuration = 2f; // Freeze
public float bombDisableSeconds = 3f; // Bomb
public float shockJamSeconds = 2f; // Shock
// Events others can subscribe to
public event Action<int> OnScoreAdded;
public event Action<float> OnTimeAdded;
public event Action<float> OnPlatformSlow; // pass duration
public event Action<float> OnPlatformTurbo; // pass duration
public event Action<float> OnPlatformFreeze; // pass duration
public event Action<float> OnClawDisabled; // pass duration
public event Action<float> OnClawJam; // pass duration
public event Action<ClawBubbleType[]> OnComboAchieved;
private int score = 0;
2025-09-06 00:08:22 +05:00
// NEW: per-type collected counts
private readonly Dictionary<ClawBubbleType, int> collectedCounts = new Dictionary<ClawBubbleType, int>();
public IReadOnlyDictionary<ClawBubbleType, int> CollectedCounts => collectedCounts;
public int GetCount(ClawBubbleType t) => collectedCounts.TryGetValue(t, out var c) ? c : 0;
private readonly Queue<ClawBubbleType> comboQueue = new Queue<ClawBubbleType>();
private readonly Queue<ClawBubbleType> starQueue = new Queue<ClawBubbleType>();
2025-09-06 00:08:22 +05:00
public GameObject ScoreUIObj;
public Transform canvasTransform;
void Awake()
{
Instance = this;
2025-09-06 00:08:22 +05:00
// init counts for all enum values
foreach (ClawBubbleType t in Enum.GetValues(typeof(ClawBubbleType)))
if (!collectedCounts.ContainsKey(t)) collectedCounts[t] = 0;
}
public void EvaluateBubble(ClawBubbleType type)
{
2025-09-06 00:08:22 +05:00
Debug.Log("EvaluateBubble: " + type);
// count every collected bubble
collectedCounts[type] = GetCount(type) + 1;
int points = 0;
switch (type)
{
case ClawBubbleType.Wolf:
points += wolfPoints;
EnqueueCombo(type, comboQueue, 3, () =>
{
AddScore(comboBonus);
OnComboAchieved?.Invoke(new[] { ClawBubbleType.Wolf, ClawBubbleType.Wolf, ClawBubbleType.Wolf });
});
break;
case ClawBubbleType.GoldenWolf:
points += goldenWolfJackpot;
break;
case ClawBubbleType.Star:
points += starPoints;
EnqueueCombo(ClawBubbleType.Star, starQueue, 3, () =>
{
AddScore(starSuperBonus);
OnComboAchieved?.Invoke(new[] { ClawBubbleType.Star, ClawBubbleType.Star, ClawBubbleType.Star });
});
break;
case ClawBubbleType.Crystal:
// primes next-grab multiplier
crystalPrimed = true;
break;
case ClawBubbleType.Time:
OnTimeAdded?.Invoke(addTimeSeconds);
Debug.Log("TimeAdded Function");
break;
case ClawBubbleType.Freeze:
OnPlatformFreeze?.Invoke(freezeDuration);
break;
case ClawBubbleType.Turbo:
OnPlatformTurbo?.Invoke(turboDuration);
break;
case ClawBubbleType.Bomb:
OnClawDisabled?.Invoke(bombDisableSeconds);
OnPlatformTurbo?.Invoke(turboDuration);
break;
case ClawBubbleType.Shock:
OnClawJam?.Invoke(shockJamSeconds);
break;
}
// Apply crystal multiplier if primed (and we actually scored)
if (crystalPrimed && points > 0)
{
points = Mathf.RoundToInt(points * crystalNextGrabMultiplier);
crystalPrimed = false;
}
if (points > 0) AddScore(points);
// Tell spawner to introduce new targets
if (ClawBubbleSpawner.Instance)
ClawBubbleSpawner.Instance.NotifyBubbleGrabbed(type);
}
private void AddScore(int amount)
{
2025-09-06 00:08:22 +05:00
// If nothing to add or missing FX/canvas, just apply immediately.
if (amount == 0 || ScoreUIObj == null || canvasTransform == null)
{
score += amount;
OnScoreAdded?.Invoke(amount);
OnScoreChanged?.Invoke(score);
return;
}
const float MOVE_DURATION = 1f;
const float START_DELAY = 1.1f;
const int SIBLING_INDEX = 3;
// Spawn FX
var go = Instantiate(ScoreUIObj, canvasTransform);
go.transform.SetSiblingIndex(Mathf.Min(SIBLING_INDEX, go.transform.parent.childCount - 1));
var scoreFX = go.GetComponent<ClawGrabCoin>();
if (scoreFX == null || scoreFX.score == null)
{
// If prefab is misconfigured, still apply score to avoid losing points.
Destroy(go);
score += amount;
OnScoreAdded?.Invoke(amount);
OnScoreChanged?.Invoke(score);
return;
}
// Text with + / - automatically
scoreFX.score.text = amount.ToString("+0;-0;0") + " <sprite name=ball>";
// Choose a move target (child 0 if present, else root)
Transform target = go.transform.childCount > 0 ? go.transform.GetChild(0) : go.transform;
bool applied = false;
void ApplyScoreOnce()
{
if (applied) return;
applied = true;
score += amount;
OnScoreAdded?.Invoke(amount);
OnScoreChanged?.Invoke(score);
}
// Animate (prefer anchored pos for UI)
var rt = target as RectTransform;
if (rt != null)
{
DOTween.Sequence()
.AppendInterval(START_DELAY)
.Append(rt.DOAnchorPos(Vector2.zero, MOVE_DURATION))
.SetUpdate(true) // ignores timescale; good for UI
.OnComplete(ApplyScoreOnce)
.OnKill(ApplyScoreOnce);
}
else
{
DOTween.Sequence()
.AppendInterval(START_DELAY)
.Append(target.DOLocalMove(Vector3.zero, MOVE_DURATION))
.SetUpdate(true)
.OnComplete(ApplyScoreOnce)
.OnKill(ApplyScoreOnce);
}
}
2025-09-06 00:08:22 +05:00
//private void AddScore(int amount)
//{
// ClawGrabCoin scoreFX = Instantiate(ScoreUIObj, canvasTransform).GetComponent<ClawGrabCoin>();
// scoreFX.transform.SetSiblingIndex(3);
// if (amount > 0)
// scoreFX.score.text = "+";
// scoreFX.score.text += amount + "<sprite name=ball>";
// scoreFX.transform.GetChild(0).transform.DOLocalMove(Vector3.zero, 1).SetDelay(1.75f).OnComplete(() =>
// {
// score += amount;
// OnScoreAdded?.Invoke(amount); // delta
// OnScoreChanged?.Invoke(score); // total
// });
//}
private void EnqueueCombo(ClawBubbleType t, Queue<ClawBubbleType> q, int target, Action onCombo)
{
q.Enqueue(t);
while (q.Count > target) q.Dequeue();
if (q.Count == target)
{
var arr = q.ToArray();
bool allSame = true;
for (int i = 1; i < arr.Length; i++)
if (arr[i] != arr[0]) { allSame = false; break; }
if (allSame) onCombo?.Invoke();
}
}
}