【Unity-實現小功能-001】骰子功能

最近在做飛行棋項目,實現了一個投擲骰子的小功能。其中使用的Uniy自帶的物理碰撞產生隨機點數的功能。

設計要點:

  1. 利用Unity自帶的物理系統進行投擲,與周圍環境進行碰撞,增加隨機性。
  2. 利用觸發器判斷點數。

模型結構:

  1. 骰子模型,掛上剛體組件(Rigidbody),掛上碰撞體(BoxCollider),創建掛載TouZi.cs腳本。
  2. 在骰子六個面分別放置一個空物體,掛上觸發器(BoxCollider 勾選上 IsTrigger 選項,PS:我用的SphereCollider),創建掛載TouZi_Point.cs 腳本。
  3. 設置牆壁和地面約束骰子的位置,防止亂跳。

部分腳本:

TouZi_Point.cs     

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

public enum PointType
{
    One = 1, Two, Three, Four, Five, Six, None
}

public class TouZi_Point : MonoBehaviour
{
    public PointType selfType;
    public PointType OppositeType = PointType.None;

    private void OnTriggerStay(Collider other)
    {
        if (other.tag == "Ground")
        {
            OppositeType = 7 - selfType;
        }
    }


     private void OnTriggerExit(Collider other)
     {
         OppositeType = PointType.None;
     }

     public void ResetOpposite()
     {
         OppositeType = PointType.None;
     }


      /// <summary>
      /// 數學計算的方式
      /// </summary>
      /// <returns></returns>
     public float GetDot()
     {
        //Debug.Log(Vector3.Dot(Vector3.up, transform.up)+"    "+ selfType);
        return Vector3.Dot(Vector3.up, transform.up);
     }
}

 

比較簡單不作介紹了


TouZi.cs


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


public class TouZi : MonoBehaviour
{
    /// <summary>
    /// 當骰子靜止時,調用的回調。
    /// </summary>
    public event EventHandler<PointType> PointTypeCallback;

    [Range(10, 20)]
    public float explosionForce = 1;
    [Range(1, 10)]
    public float torque = 1;

    private bool waiting = false;
    private Rigidbody rig;
    [SerializeField]
    private PointType currentType = PointType.None;
    [SerializeField]
    private List<TouZi_Point> touZi_Points = new List<TouZi_Point>();

    private void Awake()
    {
        rig = GetComponent<Rigidbody>();
    }

    IEnumerator WaitSelfStop()
    {
        yield return new WaitForSeconds(1);
        while (rig.velocity.sqrMagnitude > 0.001)
        {
            yield return null;
        }
        PointTypeCallback?.Invoke(this, GetCurrentType());
        StopAllCoroutines();
        waiting = false;
    }

    public void Throw()
    {
        if (waiting)
        {
            return;
        }
        waiting = true;
        for (int i = 0; i < touZi_Points.Count; i++)
        {
            touZi_Points[i].ResetOpposite();
        }
        currentType = PointType.None;
        rig.AddExplosionForce(explosionForce, transform.position - new Vector3(0, 0.5f, 0), 1, 0, ForceMode.Impulse);
        rig.AddTorque(UnityEngine.Random.onUnitSphere * torque, ForceMode.Impulse);
        StartCoroutine("WaitSelfStop");
    }

    public PointType GetCurrentType()
    {
        for (int i = 0; i < touZi_Points.Count; i++)
        {
            if (touZi_Points[i].OppositeType != PointType.None)
            {
                currentType = touZi_Points[i].OppositeType;
                break;
            }
        }
        return currentType;
    }



    ////////
    ///以下是 數學計算的方式,正確率 得到了提升 而且不消耗性能
    ////////
    //float dot = 0, dot1 = 0;
    //private PointType GetCurrentType()
    //{
    //    dot = touZi_Points[0].GetDot();
    //    currentType = touZi_Points[0].selfType;
    //    for (int i = 0; i < touZi_Points.Count - 1; i++)
    //    {
    //        dot1 = touZi_Points[i + 1].GetDot();
    //        if (dot < dot1)
    //        {
    //            dot = dot1;
    //           currentType = touZi_Points[i + 1].selfType;
    //        }
    //    }
    //    return currentType;
    // }






}

其中,

  1. 外界給 PointTypeCallback 註冊回調。
  2. Throw方法供外界調用,開始拋骰子,在骰子模型下方加一個爆炸力,把它炸起來,同時給一個隨機扭矩,讓它朝着一個隨機方向旋轉起來。
  3. 開啓協程等待骰子停下來。
  4. 執行回調,GetCurrentType() 方法遍歷子物體,找到朝上的一面的點數,將結果傳給註冊的回調。

還有一種方法判斷骰子朝上的點數,就是判斷骰子xyz三個軸和世界的xyz三個軸的數學關係。經過測試,在效率和容錯上,是優於物理碰撞檢測的。有興趣的可以自己研究一下。還可以省掉TouZiPoint這個腳本。

 


 

數學計算的方式我已經添加進去了,但是,我沒有省掉 TouZiPoint 這個腳本,各個面上的空物體的 Y軸正方向,向上垂直自己附屬的面,這樣計算 自己的UP 和 Vector3.Up 的Dot 就行,最後判斷各個 Dot 的大小,越大的 就越接近,直接取這個 touzipoint 的selfType 屬性就行了.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章