1. 程式人生 > >Unity地面檢測方案總結(施工中)

Unity地面檢測方案總結(施工中)

height physics lap lin bool doc set mono 4.3

Unity地面檢測方案總結(施工中)

1.簡單射線

在角色坐標(一般是腳底),發射一根向下的射線,長度大約為0.2,這樣是的確可以檢測到玩家是否在地面的,但只適用於簡單地形,如果你配置好了下落動畫,那麽用這種方法在斜面上往下走的話就會導致著地狀態檢測為false,如果有動畫的話,就會播放浮空動畫..這是由於角色往前走了一步時,剛體還沒來得及讓玩家因重力而下降足夠的高度,導致射線不能射到斜面.因此判false,加長射線長度可以緩解問題,但又會導致跳躍動畫出現問題,(動畫會提前著地).而且在經過腳下有縫隙的情況而角色膠囊體半徑大於縫隙並不會掉下去的時也會導致著地狀態判false;

2.Unity官方的Character Controller

簡單的加上控制器並調用控制器腳本查詢是否著地時無法達到想要的效果的,著地狀態返回false,折騰了半天發現控制器只能在調用simplemove時(和move等移動函數)判斷isGrounded(是否著地),而且播放一些動畫會導致判斷在true和false狀態來回切換.並且Skinwidth也會導致這種問題.再加上一些角色控制器的限制,邏輯上不是那麽自由.例如需要自己編寫重力,因此我放棄了這個方法.

3.兩個球的碰撞體

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

public class OnGroundSensor : MonoBehaviour
{
    public CapsuleCollider capcol;
    public float offset = 0.1f;

    private Vector3 point1;
    private Vector3 point2;
    private float radius;

    void Awake()
    {
        radius = capcol.radius - 0.05f;
    }

    void FixedUpdate()
    {
        point1 = transform.position + transform.up * (radius - offset);
        point2 = transform.position + transform.up * (capcol.height - offset) - transform.up * radius;
        Collider[] outputCols = Physics.OverlapCapsule(point1, point2, radius, LayerMask.GetMask("Ground"));
        if (outputCols.Length != 0)
        {
            //foreach (var col in outputCols)
            //    print("collision:" + col.name);
            SendMessageUpwards("IsGround");
        }
        else
            SendMessageUpwards("IsNotGround");
    }
}

4.3射線復合

5.OverlapCapsule 投射膠囊碰撞體

API: public static Collider[] OverlapCapsule(Vector3 point0, Vector3 point1, float radius, int layerMask = AllLayers,QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

point0,point1,radius 分別為膠囊體起點球心,膠囊體終點球心,膠囊體半徑

我們這裏只要用到這一重載方法 Physics.OverlapCapsule(pointBottom, pointTop, radius, LayerMask);

    private CapsuleCollider capsuleCollider;
    private Vector3 pointBottom, pointTop;
    private float radius; 
 
    void Awake () {
       
        capsuleCollider = GetComponent<CapsuleCollider>();
        radius = capsuleCollider.radius;
 
 
    }

bool OnGround() {
 
        pointBottom = transform.position + transform.up * radius-transform.up*overLapCapsuleOffset;
? ? ? ? pointTop = transform.position + transform.up * capsuleCollider.height - transform.up * radius;
        LayerMask ignoreMask = ~(1 << 8);
 
        colliders = Physics.OverlapCapsule(pointBottom, pointTop, radius, ignoreMask);
        Debug.DrawLine(pointBottom, pointTop,Color.green);
        if (colliders.Length!=0)
        {
            isOnGround = true;
            return true;
        }
        else
        {
             isOnGround = false;
            return false;
        }
}

Unity地面檢測方案總結(施工中)