詳解Unity地面檢測(cè)方案
1.普通射線
在角色坐標(biāo)(一般是腳底),發(fā)射一根向下的射線(長(zhǎng)度約0.2)
但是簡(jiǎn)單射線只適用于簡(jiǎn)單地形,實(shí)際使用中常常遇到以下問(wèn)題
1.用collider去碰撞地面,某些時(shí)候會(huì)有一定的穿插,于是角色的最低點(diǎn)就可能穿透地面,你發(fā)射射線的點(diǎn)可能就到了地面以下,射線一直檢測(cè)不到真正的地面,于是角色就一直懸空
2.角色走斜坡時(shí),角色中點(diǎn)可能會(huì)離開(kāi)地面一小段距離,這一小段距離往往就足夠讓判斷機(jī)制誤以為角色已經(jīng)離地,如果你增加射線的長(zhǎng)度,那么一定程度上能緩解斜坡問(wèn)題,但是會(huì)降低跳躍判斷的精度,精度過(guò)低就有可能出現(xiàn):角色跳起,會(huì)有那么一小段距離,其實(shí)已經(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即可,但是實(shí)際效果讓人失望
因?yàn)?isGrounded是當(dāng)角色移動(dòng)的時(shí)候才會(huì)檢測(cè)是否著地的,也就是說(shuō)它只能在調(diào)用simplemove(和move等移動(dòng)函數(shù))時(shí),判斷isGrounded(是否著地)
這時(shí)播放一些動(dòng)畫會(huì)導(dǎo)致判斷在true和false狀態(tài)來(lái)回切換,并且Skinwidth也會(huì)導(dǎo)致這種問(wèn)題,再加上一些角色控制器的限制,邏輯上不是那么自由,例如需要自己實(shí)現(xiàn)物理模擬,比如重力,個(gè)人覺(jué)得非常麻煩,不推薦
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.三射線
這個(gè)方法是社團(tuán)內(nèi)的Aery同志傳授的,他應(yīng)用到了一個(gè)2d卷軸游戲上https://github.com/KillerAery/DarkAdventrue
寫法和簡(jiǎn)單射線沒(méi)有什么不同,區(qū)別在于給角色加上三條射線:左腳,右腳,襠
三條射線有一條返回true則isGround為true
在我們的這個(gè)2d游戲上表現(xiàn)不錯(cuò)
我們看看他的代碼
float dt = Time.deltaTime; //累計(jì)時(shí)間 vida.chargeTimer += dt; vida.jumpTimer += dt; //TODO 待優(yōu)化代碼 //是否到地面 用三個(gè)groundCheck來(lái)檢測(cè) //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時(shí) 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 投射膠囊碰撞體
這個(gè)方法是看傅老師的黑魂復(fù)刻系列視頻學(xué)的
point0,point1,radius 分別為膠囊體起點(diǎn)球心,膠囊體終點(diǎn)球心,膠囊體半徑
我們這里只要用到這一重載方法 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è)置方法
最后提下這個(gè)LayerMask
假設(shè)ground層為10,指定碰撞第10層Layer,寫法為:Layermask mask=1<<10
但是,投射的膠囊體也會(huì)檢測(cè)自己本身,如果你希望游戲中基本上任何能碰撞物體都能夠用來(lái)站腳,那么應(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地面檢測(cè)方案的詳細(xì)內(nèi)容,更多關(guān)于Unity地面檢測(cè)方案的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在C#使用字典存儲(chǔ)事件示例及實(shí)現(xiàn)自定義事件訪問(wèn)器
這篇文章主要介紹了在C#使用字典存儲(chǔ)事件示例及實(shí)現(xiàn)自定義事件訪問(wèn)器的方法,是C#事件編程中的基礎(chǔ)知識(shí),需要的朋友可以參考下2016-02-02C# 無(wú)需COM組件創(chuàng)建快捷方式的實(shí)現(xiàn)代碼
做一個(gè)小程序, 需要?jiǎng)?chuàng)建快捷方式, 網(wǎng)上普遍的做法是引入 COM 組件, 雖然也挺方便的, 但引入之后, 程序就需要多帶一個(gè) dll 文件, 這樣, 想做成單文件便攜版就不行了2011-05-05在C#中g(shù)lobal關(guān)鍵字的作用及其用法
global 是 C# 2.0 中新增的關(guān)鍵字,理論上說(shuō),如果代碼寫得好的話,根本不需要用到它,但是不排除一些特別的情況,比如修改別人的代碼,本文僅舉例說(shuō)明。2016-03-03C# winfrom 模擬ftp文件管理實(shí)現(xiàn)代碼
從網(wǎng)上找到的非常好用的模擬ftp管理代碼,整理了一下,希望對(duì)需要的人有幫助2014-01-01C#實(shí)現(xiàn)多種圖片格式轉(zhuǎn)換的示例詳解
這篇文章主要為大家詳細(xì)介紹了C#如何實(shí)現(xiàn)多種圖片格式轉(zhuǎn)換,例如轉(zhuǎn)換成圖標(biāo)圖像ICO,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01C#與SQL連接:GridView控件對(duì)數(shù)據(jù)庫(kù)的操作
GridView控件操作方面的知識(shí),需要的朋友可以參考一下2013-02-02深入理解C#中new、override、virtual關(guān)鍵字的區(qū)別
下面小編就為大家?guī)?lái)一篇深入理解C#中new、override、virtual關(guān)鍵字的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06