You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 10:50:16