多个骰子投掷机制 C# Unity

Multiple dice throw mechanic C# Unity

我想实例化多个骰子(您应该可以加减骰子)并掷骰子。

现在我可以掷骰子并在控制台中获取读数。 我的问题:我无法使用多个骰子...

这些是脚本:

骰子控制器:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DiceController : MonoBehaviour
{
    public Dice dice;
    public GameObject dicePre;

    public int count = 1;


void Update()
{   
    GameObject[] dices = GameObject.FindGameObjectsWithTag("Dice");
    if(count - 1 == dices.Length){
        for (int i = 0; i < count; i++)
            {
                Instantiate(dicePre, new Vector3(i * 1.1F, 0, 0), Quaternion.identity);
            }
    }
    else if(count -1 < dices.Length){
        return;
    }
}

    public void Throw()
    {
        GameObject[] dices = GameObject.FindGameObjectsWithTag("Dice");
        foreach(GameObject dic in dices){
            dice = dic.GetComponent<Dice>();
            dice.RollDice();
        }
        
    }

    public void Plus(){        //add dice
        count++;
    }

    public void Minus(){       //substract dice
        count--;
    }
}

骰子面:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

}

主要的骰子脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Dice : MonoBehaviour
{
   Rigidbody rb;
   bool hasLanded;
   bool thrown;
   Vector3 initPos;

   public int diceValue;

   public DiceSide[] diceSides;
   
   private void Start(){
        rb = GetComponent<Rigidbody>();
        initPos = transform.position;
        rb.useGravity = false;    
   }


    private void Update(){
        if(Input.GetKeyDown(KeyCode.T)){
            RollDice();
        }

        if(rb.IsSleeping() && !hasLanded && thrown){
            hasLanded = true;
            rb.useGravity = false;
            rb.isKinematic = true;

            SideValueCheck();
        }
        else if(rb.IsSleeping() && hasLanded && diceValue == 0){
            RollAgain();
        }
    }

    public 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 = initPos;
        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("Eine " + diceValue + " wurde gewürfelt!");
            }
        }
    }

}

我怎样才能让它工作? 你也可以在这里下载包含我现在得到的所有内容的 unitypackage: https://workupload.com/file/7brN4gTCeLu

首先如前所述,我将直接制作

类型的预制字段
public Dice dicePre;

那么我会不会一直使用FindGameObjectsWithTag来获取当前实例。

我宁愿在 List 中跟踪它们,例如

public class Dice : MonoBehaviour
{
    // every instance will add itself to this list
    private static List<Dice> instances = new List<Dice>();

    // public read only access
    public static ReadOnlyCollection<Dice> Instances => instances.AsReadOnly();

    // Add yourself to the instances
    private void Awake()
    {
        instances.Add(this);
    }

    // Remove yourself from the instances
    private void OnDestroy()
    {
        instances.Remove(this);
    }
}

所以以后你可以简单地使用

foreach(var dice in Dice.Instances)
{
    dice.RollDice();
}

主要问题

那么您当前正在查看

if(count - 1 == dices.Length)

如果是这样,你实例化 count 个骰子。

  • 如果你的骰子是空的,而你的点数是3怎么办? -> 什么都不会发生

  • 或者如果你已经有 2 个骰子但计数是 3 怎么办 -> 你生成 3 个骰子并最终得到 5 !

您需要实际检查骰子数量与 count 之间的差异,然后仅添加或删除差异。

为了解决这个问题,我不会在 Update 中这样做,而是使用像

这样的 属性
[SerializeField] private int _count;

public int Count
{
    get => _count;
    set
    {
        // Count can not be negative
        _count = Mathf.Max(0, value);

        // Now do something with this new value

        // check difference
        var dif = Dice.Instances.Count - _count;

        // if 0 -> nothing to do
        if(dif == 0)
        {
            return;
        }

        // if smaller then 0 -> need more dices
        if(dif < 0)
        {
            for(var i = dif; i < 0; i++)
            {
                Instantiate(dicePre, Vector3.right * Dice.Instances.Count, Quaternion.identity);
            }
        }
        // dif bigger then 0 -> have to many dices
        else
        {
            for(var i = 0; i < dif; i++)
            {
                DestroyImmediate(Dice.Instances[Dice.Instances.Count - 1]);
            }
        }
    }
}

[ContextMenu(nameof(Plus))]
public void Plus()
{      
    Count++;
}

[ContextMenu(nameof(Minus))]
public void Minus()
{  
    Count--;
}

我不知道统一性...所以如果这与此有关,那么我很乐意删除。

public class DiceController : MonoBehaviour
{
    public List<Dice> dices;

    void DiceController()
    {
        dices = new list<Dice>();
        dices.add(new Dice); //ensure always have at least 1 on start
    }

    public void Plus()
    {        
        dices.Add(new Dice);
    }

    //caller can decided, could be random which one get removed.
    //assume they all equal
    public void Minus(Dice dice){  
        dices.Remove(dice);
    }

    public void Throw()
    {
        foreach(Dice dice in dices){
            dice.RollDice();
        }
    }
}