update time , score

This commit is contained in:
2026-05-11 21:35:39 +07:00
parent 8bf28a39fa
commit 685b3b6e12
6 changed files with 167 additions and 36 deletions

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -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}

View File

@@ -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($"<color=yellow>Chờ một chút! Cần {(nextShootTime - Time.time):F1}s nữa để ném tiếp.</color>");
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<BouncyBall>();
if (ballScript != null)
{
ballScript.shotPosition = Camera.main.transform.position;
}
Rigidbody rb = newBall.GetComponent<Rigidbody>();
if (rb != null)
{

View File

@@ -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<Rigidbody>();
if (rb != null)

View File

@@ -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<Collider>();
if (col == null)
Debug.LogError("<color=red>LỖI NẶNG: Object này (" + gameObject.name + ") CHƯA CÓ COLLIDER. Hãy add Box Collider ngay!</color>");
else if (!col.isTrigger)
Debug.LogWarning("<color=yellow>CẢNH BÁO: Collider của rổ chưa tích 'Is Trigger'. Hãy tích vào!</color>");
Debug.Log("<color=white>Script ScoreManager đang hoạt động trên: " + gameObject.name + "</color>");
UpdateScoreUI();
if (distanceCanvas != null) distanceCanvas.SetActive(false);
if (winStatusText != null) winStatusText.text = "";
Debug.Log("<color=green>ScoreManager đã khởi tạo thành công!</color>");
}
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<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)
{
currentScore += 2;
UpdateScoreUI();
Debug.Log("<color=cyan>===> GHI ĐIỂM THÀNH CÔNG! Điểm hiện tại: " + currentScore + "</color>");
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($"<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);
}
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;
}
}
}

Binary file not shown.