Unity 我的用過的地面檢測方案總結

Unity 我的用過的地面檢測方案總結

1.普通射線

在角色座標(通常是腳底),發射一根向下的射線,長度大約爲0.2,html

只適用於簡單地形,實際使用中經常遇到如下問題c#

  1. 用的collider去碰撞地面時,某些時候會有必定的穿插,因而角色的最低點就可能穿透地面,你發射射線的點可能就到了地面如下,射線一直檢測不到真正的地面,因而角色就一直懸空。ide

  2. 角色是走斜坡的時候,角色中點可能會離開地面一小段距離,這一小段距離每每就足夠讓判斷機制誤覺得角色已經離地了。若是你增長射線的長度,那麼必定程度上能緩解斜坡問題,可是會下降跳躍判斷的精度:角色每次跳起,會有一小段距離,其實已經離地了,可是仍然返回了isGround = true;函數

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class RaycastTest : MonoBehaviour {
    
    private bool isGround = false;
    private Rigidbody2D myRigidbody2D;
    void Awake () {
        myAnimator = GetComponent<Animator>();
        myRigidbody2D = GetComponent<Rigidbody2D>();
    }
    void FixedUpdate () {
        Debug.DrawRay(transform.position, Vector2.down * 0.11f, Color.red);
        RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, 0.15f, 1 << 8);
        if (hit.collider != null)
            isGround = true;
        else
            isGround = false;
}

2.Unity官方的Character Controller

直接給角色加入Character Controller組件,在腳本中Get到Character Controller,調用.isGrounded就能夠用。動畫

可是.isGrounded時當角色移動的時候纔會檢測是否着地,也就是說他只能在調用simplemove(和move等移動函數)時,判斷isGrounded(是否着地)pwa

這時播放一些動畫會致使判斷在true和false狀態來回切換,而且Skinwidth也會致使這種問題,再加上一些角色控制器的限制,邏輯上不是那麼自由,例如須要本身實現物理模擬,好比重力3d

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

3.三射線

寫法和簡單射線沒有什麼不一樣,區別在於給角色加上三條射線:左腳,右腳,襠,三條射線有一條返回true則isGround爲true。code

4.OverlapCapsule 投射膠囊碰撞體

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

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

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

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

LayerMask設置方法

假設ground層爲10,指定碰撞第10層Layer

寫法爲:Layermask mask=1<<10

可是。投射的膠囊體也會檢測本身自己,若是你但願遊戲中基本上任何能碰撞物體都可以用來站腳,那麼應設置爲:碰撞除了角色所在的Layer之外的全部層(假設Player層爲8

寫法爲:~(1<<8)

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;
        }
}
相關文章
相關標籤/搜索