241 lines
6.9 KiB
C#
241 lines
6.9 KiB
C#
using UnityEngine;
|
|
using TMPro;
|
|
using UnityEngine.UI;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
public class ScoreManager : MonoBehaviour
|
|
{
|
|
[Header("UI References")]
|
|
public TextMeshProUGUI scoreText;
|
|
public TextMeshProUGUI timerText;
|
|
public GameObject resultCanvas;
|
|
public TextMeshProUGUI resultStatusText;
|
|
public TextMeshProUGUI resultScoreText;
|
|
public Button restartButton;
|
|
|
|
[Header("Distance Floating UI")]
|
|
public GameObject distanceCanvas;
|
|
public TextMeshProUGUI distanceText;
|
|
|
|
[Header("Audio Clips")]
|
|
public List<AudioClip> scoreSounds; // Danh sách các âm thanh vào rổ ngẫu nhiên
|
|
public AudioClip winSound;
|
|
public AudioClip loseSound;
|
|
public AudioClip buttonClickSound;
|
|
public AudioClip flashSound;
|
|
public AudioClip bgMusic;
|
|
public AudioClip alarmSound;
|
|
|
|
[Header("Game Settings")]
|
|
public float gameDuration = 60f;
|
|
public int targetScore = 50;
|
|
|
|
private int currentScore = 0;
|
|
private float timeRemaining;
|
|
private bool isGameOver = false;
|
|
private AudioSource musicSource;
|
|
private bool alarmPlayed = false;
|
|
|
|
void Start()
|
|
{
|
|
currentScore = 0;
|
|
timeRemaining = gameDuration;
|
|
isGameOver = false;
|
|
alarmPlayed = false;
|
|
|
|
musicSource = gameObject.AddComponent<AudioSource>();
|
|
if (bgMusic != null)
|
|
{
|
|
musicSource.clip = bgMusic;
|
|
musicSource.loop = true;
|
|
musicSource.volume = 0.5f;
|
|
musicSource.Play();
|
|
}
|
|
|
|
UpdateScoreUI();
|
|
if (distanceCanvas != null) distanceCanvas.SetActive(false);
|
|
if (resultCanvas != null) resultCanvas.SetActive(false);
|
|
|
|
if (restartButton != null)
|
|
{
|
|
restartButton.onClick.RemoveAllListeners();
|
|
restartButton.onClick.AddListener(() => {
|
|
if (AudioPool.Instance != null) AudioPool.Instance.PlaySound(buttonClickSound);
|
|
RestartGame();
|
|
});
|
|
}
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (isGameOver) return;
|
|
|
|
if (timeRemaining > 0)
|
|
{
|
|
timeRemaining -= Time.deltaTime;
|
|
UpdateTimerUI();
|
|
|
|
if (timeRemaining <= 10f)
|
|
{
|
|
timerText.color = Mathf.PingPong(Time.time * 5, 1) > 0.5f ? Color.red : Color.white;
|
|
if (!alarmPlayed && alarmSound != null)
|
|
{
|
|
if (AudioPool.Instance != null) AudioPool.Instance.PlaySound(alarmSound);
|
|
alarmPlayed = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
timeRemaining = 0;
|
|
UpdateTimerUI();
|
|
CheckGameEnd();
|
|
}
|
|
}
|
|
|
|
void CheckGameEnd()
|
|
{
|
|
if (currentScore >= targetScore)
|
|
{
|
|
EndGame("YOU WIN!", Color.green, winSound);
|
|
StartCoroutine(CelebrationEffect());
|
|
}
|
|
else
|
|
{
|
|
EndGame("GAME OVER", Color.red, loseSound);
|
|
}
|
|
}
|
|
|
|
private void OnTriggerEnter(Collider other)
|
|
{
|
|
ProcessScore(other.gameObject);
|
|
}
|
|
|
|
private void OnCollisionEnter(Collision collision)
|
|
{
|
|
ProcessScore(collision.gameObject);
|
|
}
|
|
|
|
void ProcessScore(GameObject obj)
|
|
{
|
|
if (isGameOver) return;
|
|
|
|
BouncyBall ball = obj.GetComponent<BouncyBall>();
|
|
if (ball == null || ball.isScored) return;
|
|
|
|
ball.isScored = true;
|
|
|
|
#if UNITY_ANDROID || UNITY_IOS
|
|
Handheld.Vibrate();
|
|
#endif
|
|
|
|
// Chọn ngẫu nhiên âm thanh vào rổ
|
|
if (AudioPool.Instance != null && scoreSounds != null && scoreSounds.Count > 0)
|
|
{
|
|
AudioClip randomClip = scoreSounds[Random.Range(0, scoreSounds.Count)];
|
|
AudioPool.Instance.PlaySound(randomClip, 1f, true);
|
|
}
|
|
|
|
float distance = Vector3.Distance(ball.shotPosition, transform.position);
|
|
int points = CalculatePoints(distance);
|
|
|
|
currentScore += points;
|
|
UpdateScoreUI();
|
|
StartCoroutine(FlashScoreUI());
|
|
|
|
if (distanceCanvas != null)
|
|
{
|
|
StopAllCoroutines(); // Dùng cái này để đảm bảo reset mọi hiệu ứng cũ
|
|
StartCoroutine(ShowDistanceUI(distance));
|
|
StartCoroutine(CelebrationEffect()); // Chỉ chạy nếu đã win
|
|
}
|
|
|
|
ball.enabled = false;
|
|
Destroy(obj, 1f);
|
|
}
|
|
|
|
int CalculatePoints(float distance)
|
|
{
|
|
if (distance >= 20f) return 3;
|
|
if (distance >= 10f) return 2;
|
|
if (distance >= 6f) return 1;
|
|
return 1;
|
|
}
|
|
|
|
void UpdateScoreUI()
|
|
{
|
|
if (scoreText != null) scoreText.text = "Score: " + currentScore;
|
|
}
|
|
|
|
void UpdateTimerUI()
|
|
{
|
|
if (timerText != null)
|
|
{
|
|
int minutes = Mathf.FloorToInt(timeRemaining / 60);
|
|
int seconds = Mathf.FloorToInt(timeRemaining % 60);
|
|
timerText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
|
|
}
|
|
}
|
|
|
|
IEnumerator ShowDistanceUI(float distance)
|
|
{
|
|
if (distanceText != null) distanceText.text = $"{distance:F1}m";
|
|
distanceCanvas.SetActive(true);
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
distanceText.enabled = !distanceText.enabled;
|
|
if (distanceText.enabled && AudioPool.Instance != null)
|
|
AudioPool.Instance.PlaySound(flashSound, 0.7f, true);
|
|
yield return new WaitForSeconds(0.2f);
|
|
}
|
|
|
|
distanceText.enabled = true;
|
|
yield return new WaitForSeconds(1.0f);
|
|
distanceCanvas.SetActive(false);
|
|
}
|
|
|
|
IEnumerator FlashScoreUI()
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
scoreText.color = Color.yellow;
|
|
yield return new WaitForSeconds(0.1f);
|
|
scoreText.color = Color.white;
|
|
yield return new WaitForSeconds(0.1f);
|
|
}
|
|
}
|
|
|
|
IEnumerator CelebrationEffect()
|
|
{
|
|
while (isGameOver)
|
|
{
|
|
resultStatusText.color = new Color(Random.value, Random.value, Random.value);
|
|
resultScoreText.transform.localScale = Vector3.one * (1f + Mathf.PingPong(Time.time * 2, 0.2f));
|
|
yield return new WaitForSeconds(0.1f);
|
|
}
|
|
}
|
|
|
|
void EndGame(string status, Color statusColor, AudioClip endClip)
|
|
{
|
|
isGameOver = true;
|
|
if (musicSource != null) musicSource.Stop();
|
|
if (AudioPool.Instance != null) AudioPool.Instance.PlaySound(endClip);
|
|
|
|
if (resultCanvas != null)
|
|
{
|
|
resultCanvas.SetActive(true);
|
|
resultStatusText.text = status;
|
|
resultStatusText.color = statusColor;
|
|
resultScoreText.text = "Final Score: " + currentScore;
|
|
}
|
|
}
|
|
|
|
public void RestartGame()
|
|
{
|
|
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
|
|
}
|
|
}
|