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