diff --git a/.idea/.idea.VR-GAME/.idea/indexLayout.xml b/.idea/.idea.VR-GAME/.idea/indexLayout.xml deleted file mode 100644 index 7b08163..0000000 --- a/.idea/.idea.VR-GAME/.idea/indexLayout.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Assets/Prefab/Sphere.prefab b/Assets/Prefab/Sphere.prefab index c0ca996..a9461c0 100644 --- a/Assets/Prefab/Sphere.prefab +++ b/Assets/Prefab/Sphere.prefab @@ -13,6 +13,7 @@ GameObject: - component: {fileID: 4871679746275035045} - component: {fileID: 1403353099253554078} - component: {fileID: 4684177289331536007} + - component: {fileID: 5080108737146792294} m_Layer: 0 m_Name: Sphere m_TagString: Ball @@ -140,3 +141,16 @@ Rigidbody: m_Interpolate: 0 m_Constraints: 0 m_CollisionDetection: 0 +--- !u!114 &5080108737146792294 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7093238386133182062} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 15dabd6ae947f12439f46655ed59fd7c, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::BouncyBall + shotPosition: {x: 0, y: 0, z: 0} diff --git a/Assets/Script/BallShooter.cs b/Assets/Script/BallShooter.cs index ddb6903..fee135f 100644 --- a/Assets/Script/BallShooter.cs +++ b/Assets/Script/BallShooter.cs @@ -6,9 +6,23 @@ public class BallShooter : MonoBehaviour public Transform shootPoint; // Kéo điểm ShootPoint vào đây public float shootForce = 500f; public float upwardForce = 200f; // Lực ném vòng cung lên trên + + [Header("Shooting Limit")] + public float shootCooldown = 2f; // Thời gian chờ giữa 2 lần ném + private float nextShootTime = 0f; public void ShootBall() { + // Kiểm tra xem đã đến lúc được ném chưa + if (Time.time < nextShootTime) + { + Debug.Log($"Chờ một chút! Cần {(nextShootTime - Time.time):F1}s nữa để ném tiếp."); + return; + } + + // Cập nhật thời gian ném tiếp theo + nextShootTime = Time.time + shootCooldown; + // 1. Lấy vị trí ném: Từ Camera lùi xuống dưới một chút (giống tay người cầm bóng) Vector3 spawnPosition = Camera.main.transform.position + Camera.main.transform.forward * 0.5f @@ -20,6 +34,13 @@ public class BallShooter : MonoBehaviour // 3. Đảm bảo bóng không bị dính vào Image Target newBall.transform.SetParent(null); + // Gán vị trí ném vào script BouncyBall + BouncyBall ballScript = newBall.GetComponent(); + if (ballScript != null) + { + ballScript.shotPosition = Camera.main.transform.position; + } + Rigidbody rb = newBall.GetComponent(); if (rb != null) { diff --git a/Assets/Script/BouncyBall.cs b/Assets/Script/BouncyBall.cs index cacdd9e..3834b33 100644 --- a/Assets/Script/BouncyBall.cs +++ b/Assets/Script/BouncyBall.cs @@ -2,10 +2,13 @@ using UnityEngine; public class BouncyBall : MonoBehaviour { + public Vector3 shotPosition; + public bool isScored = false; + void Start() { - // Tự động gán Tag để chắc chắn ScoreManager nhận ra quả bóng - gameObject.tag = "Ball"; + // Loại bỏ việc gán Tag bằng code để tránh lỗi nếu chưa tạo Tag trong Unity + // Chúng ta sẽ nhận diện bóng bằng Component BouncyBall cho chắc chắn Rigidbody rb = GetComponent(); if (rb != null) diff --git a/Assets/Script/ScoreManager.cs b/Assets/Script/ScoreManager.cs index 216b4f8..b5c0d43 100644 --- a/Assets/Script/ScoreManager.cs +++ b/Assets/Script/ScoreManager.cs @@ -1,60 +1,161 @@ using UnityEngine; -using TMPro; // Dùng UnityEngine.UI nếu bạn xài Text thường +using TMPro; +using UnityEngine.UI; +using System.Collections; public class ScoreManager : MonoBehaviour { - public TextMeshProUGUI scoreText; // Kéo UI Text điểm số vào đây + [Header("UI References")] + public TextMeshProUGUI scoreText; + public TextMeshProUGUI timerText; + public TextMeshProUGUI winStatusText; + public GameObject distanceCanvas; + public TextMeshProUGUI distanceText; + + [Header("Game Settings")] + public float gameDuration = 300f; + public int targetScore = 50; + private int currentScore = 0; + private float timeRemaining; + private bool isGameOver = false; void Start() { currentScore = 0; - UpdateScoreUI(); + timeRemaining = gameDuration; + isGameOver = false; - // CHẨN ĐOÁN LỖI: - Collider col = GetComponent(); - if (col == null) - Debug.LogError("LỖI NẶNG: Object này (" + gameObject.name + ") CHƯA CÓ COLLIDER. Hãy add Box Collider ngay!"); - else if (!col.isTrigger) - Debug.LogWarning("CẢNH BÁO: Collider của rổ chưa tích 'Is Trigger'. Hãy tích vào!"); - - Debug.Log("Script ScoreManager đang hoạt động trên: " + gameObject.name + ""); + UpdateScoreUI(); + if (distanceCanvas != null) distanceCanvas.SetActive(false); + if (winStatusText != null) winStatusText.text = ""; + + Debug.Log("ScoreManager đã khởi tạo thành công!"); + } + + void Update() + { + if (isGameOver) return; + + if (timeRemaining > 0) + { + timeRemaining -= Time.deltaTime; + UpdateTimerUI(); + + if (currentScore >= targetScore) + { + WinGame(); + } + } + else + { + GameOver(); + } } - // Bắt va chạm kiểu Trigger (Xuyên qua) private void OnTriggerEnter(Collider other) { - GhiDiem(other.gameObject, "TRIGGER"); + Debug.Log("Va chạm Trigger với: " + other.gameObject.name); + ProcessScore(other.gameObject); } - // Bắt va chạm kiểu Vật lý (Đập vào nhau) - Dự phòng nếu bạn chưa tích Is Trigger private void OnCollisionEnter(Collision collision) { - GhiDiem(collision.gameObject, "PHYSICS"); + Debug.Log("Va chạm Vật lý với: " + collision.gameObject.name); + ProcessScore(collision.gameObject); } - void GhiDiem(GameObject obj, string type) + void ProcessScore(GameObject obj) { - Debug.Log("PHÁT HIỆN VA CHẠM [" + type + "] với: " + obj.name + " | Tag: " + obj.tag); + if (isGameOver) return; - if (obj.CompareTag("Ball") || obj.name.Contains("Sphere") || obj.name.Contains("ball")) + // Ưu tiên kiểm tra script BouncyBall + BouncyBall ball = obj.GetComponent(); + + // 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) { - currentScore += 2; - UpdateScoreUI(); - Debug.Log("===> GHI ĐIỂM THÀNH CÔNG! Điểm hiện tại: " + currentScore + ""); - Destroy(obj, 0.2f); + return; } + + // Đánh dấu đã ghi điểm ngay lập tức + ball.isScored = true; + + // Tính khoảng cách + float distance = Vector3.Distance(ball.shotPosition, transform.position); + int points = CalculatePoints(distance); + + currentScore += points; + UpdateScoreUI(); + + // Hiển thị khoảng cách trên rổ + if (distanceCanvas != null) + { + StopAllCoroutines(); // Dừng các lần hiện trước đó để tránh chồng chéo + StartCoroutine(ShowDistanceUI(distance)); + } + else + { + Debug.LogWarning("distanceCanvas chưa được gán trong Inspector!"); + } + + Debug.Log($"GHI ĐIỂM: {points}pt | Khoảng cách ném: {distance:F2}m | Tổng điểm: {currentScore}"); + + // 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); + } + + 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; + return 1; } void UpdateScoreUI() { - if (scoreText != null) + if (scoreText != null) scoreText.text = "Score: " + currentScore; + } + + void UpdateTimerUI() + { + if (timerText != null) { - scoreText.text = "Score: " + currentScore; + int minutes = Mathf.FloorToInt(timeRemaining / 60); + int seconds = Mathf.FloorToInt(timeRemaining % 60); + timerText.text = string.Format("Time: {0:00}:{1:00}", minutes, seconds); } - else + } + + IEnumerator ShowDistanceUI(float distance) + { + if (distanceText != null) distanceText.text = $"{distance:F1}m"; + distanceCanvas.SetActive(true); + yield return new WaitForSeconds(2.5f); + distanceCanvas.SetActive(false); + } + + void WinGame() + { + isGameOver = true; + if (winStatusText != null) { - Debug.LogWarning("ScoreText chưa được kéo vào ScoreManager!"); + winStatusText.text = "YOU WIN!"; + winStatusText.color = Color.green; + } + } + + void GameOver() + { + isGameOver = true; + if (winStatusText != null) + { + winStatusText.text = "GAME OVER"; + winStatusText.color = Color.red; } } } diff --git a/Library/ArtifactDB b/Library/ArtifactDB index 1459bb6..bc6bde3 100644 Binary files a/Library/ArtifactDB and b/Library/ArtifactDB differ