詳解Unity地面檢測方案
1.普通射線
在角色坐標(biāo)(一般是腳底),發(fā)射一根向下的射線(長度約0.2)
但是簡單射線只適用于簡單地形,實際使用中常常遇到以下問題
1.用collider去碰撞地面,某些時候會有一定的穿插,于是角色的最低點就可能穿透地面,你發(fā)射射線的點可能就到了地面以下,射線一直檢測不到真正的地面,于是角色就一直懸空
2.角色走斜坡時,角色中點可能會離開地面一小段距離,這一小段距離往往就足夠讓判斷機制誤以為角色已經(jīng)離地,如果你增加射線的長度,那么一定程度上能緩解斜坡問題,但是會降低跳躍判斷的精度,精度過低就有可能出現(xiàn):角色跳起,會有那么一小段距離,其實已經(jīng)離地了,但是仍然返回了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,調(diào)用.isGrounded即可,但是實際效果讓人失望
因為.isGrounded是當(dāng)角色移動的時候才會檢測是否著地的,也就是說它只能在調(diào)用simplemove(和move等移動函數(shù))時,判斷isGrounded(是否著地)
這時播放一些動畫會導(dǎo)致判斷在true和false狀態(tài)來回切換,并且Skinwidth也會導(dǎo)致這種問題,再加上一些角色控制器的限制,邏輯上不是那么自由,例如需要自己實現(xiàn)物理模擬,比如重力,個人覺得非常麻煩,不推薦
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.三射線
這個方法是社團內(nèi)的Aery同志傳授的,他應(yīng)用到了一個2d卷軸游戲上https://github.com/KillerAery/DarkAdventrue
寫法和簡單射線沒有什么不同,區(qū)別在于給角色加上三條射線:左腳,右腳,襠
三條射線有一條返回true則isGround為true
在我們的這個2d游戲上表現(xiàn)不錯
我們看看他的代碼
float dt = Time.deltaTime;
//累計時間
vida.chargeTimer += dt;
vida.jumpTimer += dt;
//TODO 待優(yōu)化代碼
//是否到地面 用三個groundCheck來檢測
//public Transform[] groundChecks = new Transform[3];
for (int i = 0; i < 3; ++i)
{
checkResult = Physics2D.Linecast(transform.position,
groundChecks[i].position,
1 << LayerMask.NameToLayer("Ground"));
vida.grounded = checkResult;
if (vida.grounded) break;
}
if (vida.grounded)
{
//火箭蛋(硬件蛋特殊技能)
if (vida.playerType == Tags.YingjianDan)
{
vida.jumpable = 1;
}
}
//跳躍
//按下K時
if (Input.GetKeyDown(KeyCode.K) && vida.jumpTimer >= 0.03f)
{
if (vida.grounded)
{
//允許跳躍
vida.jumpTimer = 0.0f;
vida.jump = true;
}
else if (vida.jumpable > 0)
{
vida.jumpable--;
//允許跳躍
vida.jumpTimer = 0.0f;
vida.jump = true;
}
}
4.OverlapCapsule 投射膠囊碰撞體
這個方法是看傅老師的黑魂復(fù)刻系列視頻學(xué)的


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;
}
5.LayerMask設(shè)置方法
最后提下這個LayerMask
假設(shè)ground層為10,指定碰撞第10層Layer,寫法為:Layermask mask=1<<10
但是,投射的膠囊體也會檢測自己本身,如果你希望游戲中基本上任何能碰撞物體都能夠用來站腳,那么應(yīng)設(shè)置為:碰撞除了角色所在的Layer以外的所有層(假設(shè)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;
}
}
以上就是詳解Unity地面檢測方案的詳細(xì)內(nèi)容,更多關(guān)于Unity地面檢測方案的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#使用Twain協(xié)議實現(xiàn)掃描儀連續(xù)掃描功能
這篇文章主要介紹了C#使用Twain協(xié)議實現(xiàn)掃描儀連續(xù)掃描,只需一行代碼,就可實現(xiàn)一次掃描多張,且不需要更改掃描儀的任何設(shè)置,需要的朋友可以參考下2022-01-01
C#面向?qū)ο笤O(shè)計原則之組合/聚合復(fù)用原則
這篇文章介紹了C#面向?qū)ο笤O(shè)計原則之組合/聚合復(fù)用原則,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03

