【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 属性就行了.

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