This commit is contained in:
2026-05-12 01:22:46 +07:00
parent 685b3b6e12
commit 1ee0f7ef7d
77 changed files with 6012 additions and 1036 deletions

View File

@@ -2,35 +2,70 @@ 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 TextMeshProUGUI winStatusText;
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 = 300f;
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 (winStatusText != null) winStatusText.text = "";
if (resultCanvas != null) resultCanvas.SetActive(false);
Debug.Log("<color=green>ScoreManager đã khởi tạo thành công!</color>");
if (restartButton != null)
{
restartButton.onClick.RemoveAllListeners();
restartButton.onClick.AddListener(() => {
if (AudioPool.Instance != null) AudioPool.Instance.PlaySound(buttonClickSound);
RestartGame();
});
}
}
void Update()
@@ -42,26 +77,44 @@ public class ScoreManager : MonoBehaviour
timeRemaining -= Time.deltaTime;
UpdateTimerUI();
if (currentScore >= targetScore)
if (timeRemaining <= 10f)
{
WinGame();
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
{
GameOver();
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)
{
Debug.Log("Va chạm Trigger với: " + other.gameObject.name);
ProcessScore(other.gameObject);
}
private void OnCollisionEnter(Collision collision)
{
Debug.Log("Va chạm Vật lý với: " + collision.gameObject.name);
ProcessScore(collision.gameObject);
}
@@ -69,50 +122,45 @@ public class ScoreManager : MonoBehaviour
{
if (isGameOver) return;
// Ưu tiên kiểm tra script BouncyBall
BouncyBall ball = obj.GetComponent<BouncyBall>();
// Nếu không có script, hoặc bóng đã được tính điểm rồi thì bỏ qua
if (ball == null || ball.isScored)
{
return;
}
if (ball == null || ball.isScored) return;
// Đánh dấu đã ghi điểm ngay lập tức
ball.isScored = true;
// Tính khoảng cách
#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());
// Hiển thị khoảng cách trên rổ
if (distanceCanvas != null)
{
StopAllCoroutines(); // Dng các lần hiện trước đó để tránh chồng chéo
StopAllCoroutines(); // Dùng cái này để đảm bảo reset mọi hiệu ứng cũ
StartCoroutine(ShowDistanceUI(distance));
}
else
{
Debug.LogWarning("distanceCanvas chưa được gán trong Inspector!");
StartCoroutine(CelebrationEffect()); // Chỉ chạy nếu đã win
}
Debug.Log($"<color=cyan>GHI ĐIỂM: {points}pt | Khoảng cách ném: {distance:F2}m | Tổng điểm: {currentScore}</color>");
// Vô hiệu hóa script hoặc quả bóng để không tính điểm lại
ball.enabled = false;
Destroy(obj, 0.5f);
Destroy(obj, 1f);
}
int CalculatePoints(float distance)
{
// Điều chỉnh lại logic: Nếu trong AR khoảng cách tính bằng Unity Unit có thể rất nhỏ
// Bạn có thể cần nhân distance với một hệ số nếu tỉ lệ scale của bạn khác 1:1 mét
if (distance >= 10f) return 3;
if (distance >= 5f) return 2;
if (distance >= 3f) return 1;
if (distance >= 20f) return 3;
if (distance >= 10f) return 2;
if (distance >= 6f) return 1;
return 1;
}
@@ -127,7 +175,7 @@ public class ScoreManager : MonoBehaviour
{
int minutes = Mathf.FloorToInt(timeRemaining / 60);
int seconds = Mathf.FloorToInt(timeRemaining % 60);
timerText.text = string.Format("Time: {0:00}:{1:00}", minutes, seconds);
timerText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
}
}
@@ -135,27 +183,58 @@ public class ScoreManager : MonoBehaviour
{
if (distanceText != null) distanceText.text = $"{distance:F1}m";
distanceCanvas.SetActive(true);
yield return new WaitForSeconds(2.5f);
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);
}
void WinGame()
IEnumerator FlashScoreUI()
{
isGameOver = true;
if (winStatusText != null)
for (int i = 0; i < 3; i++)
{
winStatusText.text = "YOU WIN!";
winStatusText.color = Color.green;
scoreText.color = Color.yellow;
yield return new WaitForSeconds(0.1f);
scoreText.color = Color.white;
yield return new WaitForSeconds(0.1f);
}
}
void GameOver()
IEnumerator CelebrationEffect()
{
isGameOver = true;
if (winStatusText != null)
while (isGameOver)
{
winStatusText.text = "GAME OVER";
winStatusText.color = Color.red;
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);
}
}