Unity C#骰子游戏分数更新异常及跨脚本调用问题求助
骰子游戏开发问题
我是Unity与C#新手,正在开发一款骰子游戏,规则如下:
- 掷两个骰子,将点数之和累加到玩家总分
- 游戏结束条件:掷出两个1(失败),或总分达到/超过50(胜利)
- 结束后显示胜负结果与分数
目前已实现大部分功能,但存在分数持续累加、直接触发胜利提示的问题,无法正常更新分数。我已经通过GetComponent获取了Dice脚本中的diceValue变量,但问题仍未解决。后续计划将游戏扩展为双人回合制,希望得到帮助。
相关代码
Dice 脚本
public class Dice : MonoBehaviour { Rigidbody rb; bool hasLanded; bool thrown; Vector3 initPosition; //Initial Position public int diceValue; public DiceSide[] diceSides; void Start() { rb = GetComponent<Rigidbody>(); initPosition = transform.position; rb.useGravity = false; } void Update() { if (Input.GetKeyDown(KeyCode.Space)) { RollDice(); } if(rb.IsSleeping() && !hasLanded && thrown) { hasLanded = true; rb.useGravity = false; //rb.isKinematic = true; SideValueCheck(); } else if(rb.IsSleeping() && hasLanded && diceValue == 0) { RollAgain(); } } void RollDice() { if(!thrown && !hasLanded) { thrown = true; rb.useGravity = true; rb.AddTorque(Random.Range(0, 500), Random.Range(0, 500), Random.Range(0, 500)); } else if(thrown && hasLanded) { Reset(); } } void Reset() { transform.position = initPosition; thrown = false; hasLanded = false; rb.useGravity = false; //rb.isKinematic = false; } void RollAgain() { Reset(); thrown = true; rb.useGravity = true; rb.AddTorque(Random.Range(0, 500), Random.Range(0, 500), Random.Range(0, 500)); } void SideValueCheck() { diceValue = 0; foreach (DiceSide side in diceSides) { if (side.OnGround()) { diceValue = side.sideValue; Debug.Log(diceValue + " has been rolled!"); } } } }
DiceSide 脚本
public class DiceSide : MonoBehaviour { bool onGround; public int sideValue; void OnTriggerStay(Collider col) { if(col.tag == "Ground") { onGround = true; } } void OnTriggerExit(Collider col) { if(col.tag == "Ground") { onGround = false; } } public bool OnGround() { return onGround; } }
Check 脚本
public class Check : MonoBehaviour { public GameObject DiceGameObject1; public GameObject DiceGameObject2; private Dice dice; private Dice dice2; public int dicevalue1; public int dicevalue2; private int score; private int totalScore; public TMP_Text Score; public TMP_Text TotalScore; public TMP_Text Win; public TMP_Text Lose; public TMP_Text Player; void Start() { totalScore = 0; score = 0; Win.text = ""; Lose.text = ""; } void Awake() { dice = DiceGameObject1.GetComponent<Dice>(); dice2 = DiceGameObject2.GetComponent<Dice>(); } void Update() { UpdateScore(); } void SetScoreText() { if (dicevalue1 == 1 && dicevalue2 == 1) { Lose.text = "You Lose:("; } else if (totalScore >= 50) { Win.text = "You win!"; } else { TotalScore.text = totalScore.ToString(); } } public void UpdateScore() { dicevalue1 = dice.diceValue; dicevalue2 = dice2.diceValue; score = dicevalue1 + dicevalue2; Debug.Log(dicevalue1 + dicevalue2); // how do I import diceValue variables from Dice class and use the values here? totalScore += score; SetScoreText(); } }
问题解决思路与代码修改
核心问题分析
Check脚本中UpdateScore()方法在Update()里每帧调用,导致每帧都在累加分数,这就是分数暴增、直接触发胜利的核心原因。另外,当前逻辑没有区分骰子是否完成投掷,也没有限制游戏结束后的操作。
具体修改步骤
1. 给Dice脚本添加投掷完成通知
修改Dice脚本,添加事件标记骰子投掷完成:
// 在Dice类中添加公共事件 public event System.Action OnDiceRollCompleted; // 修改SideValueCheck方法,触发事件 void SideValueCheck() { diceValue = 0; foreach (DiceSide side in diceSides) { if (side.OnGround()) { diceValue = side.sideValue; Debug.Log(diceValue + " has been rolled!"); } } // 骰子落地计算完成后触发事件 OnDiceRollCompleted?.Invoke(); }
2. 修改Check脚本,仅在双骰完成时计算一次分数
移除每帧调用的逻辑,通过事件监听骰子状态,仅在两个骰子都落地后计算分数:
public class Check : MonoBehaviour { public GameObject DiceGameObject1; public GameObject DiceGameObject2; private Dice dice; private Dice dice2; public int dicevalue1; public int dicevalue2; private int score; private int totalScore; public TMP_Text Score; public TMP_Text TotalScore; public TMP_Text Win; public TMP_Text Lose; public TMP_Text Player; // 新增:记录双骰是否完成投掷 private bool isDice1Completed; private bool isDice2Completed; // 新增:标记游戏是否结束 private bool isGameOver; void Start() { totalScore = 0; score = 0; Win.text = ""; Lose.text = ""; isGameOver = false; isDice1Completed = false; isDice2Completed = false; } void Awake() { dice = DiceGameObject1.GetComponent<Dice>(); dice2 = DiceGameObject2.GetComponent<Dice>(); // 订阅骰子投掷完成事件 dice.OnDiceRollCompleted += OnDice1Rolled; dice2.OnDiceRollCompleted += OnDice2Rolled; } // 骰子1完成投掷回调 private void OnDice1Rolled() { if (isGameOver) return; isDice1Completed = true; CheckBothDiceCompleted(); } // 骰子2完成投掷回调 private void OnDice2Rolled() { if (isGameOver) return; isDice2Completed = true; CheckBothDiceCompleted(); } // 检查双骰是否都完成,是则计算分数 private void CheckBothDiceCompleted() { if (isDice1Completed && isDice2Completed) { UpdateScore(); // 重置标记,准备下一次投掷 isDice1Completed = false; isDice2Completed = false; } } void SetScoreText() { if (dicevalue1 == 1 && dicevalue2 == 1) { Lose.text = "You Lose:("; isGameOver = true; } else if (totalScore >= 50) { Win.text = "You win!"; isGameOver = true; } else { TotalScore.text = totalScore.ToString(); Score.text = score.ToString(); // 新增:显示本次投掷的点数和 } } public void UpdateScore() { dicevalue1 = dice.diceValue; dicevalue2 = dice2.diceValue; score = dicevalue1 + dicevalue2; Debug.Log($"本次点数:{dicevalue1} + {dicevalue2} = {score}"); totalScore += score; SetScoreText(); } // 销毁时取消事件订阅,避免内存泄漏 private void OnDestroy() { dice.OnDiceRollCompleted -= OnDice1Rolled; dice2.OnDiceRollCompleted -= OnDice2Rolled; } }
3. 双人回合制扩展思路
- 添加
currentPlayer变量记录当前回合玩家(如int currentPlayer = 1) - 给两个玩家维护独立的总分(
int player1Score、int player2Score) - 在
CheckBothDiceCompleted方法中计算完分数后,判断游戏是否结束,未结束则切换currentPlayer - 更新UI显示当前玩家,比如
Player.text = $"当前玩家:玩家{currentPlayer}"
内容的提问来源于stack exchange,提问作者Chloe Jung
相关产品推荐
相关产品推荐

