Unity3D 自制摄像机不穿墙/不穿物体(射线cast方法)
墙和物体都要加上collider(碰撞体),一般注意以下几点:
- 墙加mesh collider,在Convex上打勾
- 物体加box collider
- 加刚体(rigidbody)的物体不要选Is Kenimatic
基础 最简单的Raycast方法
void Update()
{RaycastHit hitInfo;Vector3 fwd = Camera.main.transform.TransformDirection(Vector3.forward);if (Physics.Raycast(Camera.main.transform.position, fwd, out hitInfo, 0.5f)){float dis = hitInfo.distance;Vector3 correction = Vector3.Normalize(Camera.main.transform.TransformDirection(Vector3.back)) * dis;Camera.main.transform.position += correction;}
}
上面的代码,在撞墙时会有抖动的效果,如果要平滑后退,可以把
Vector3.Normalize(Camera.main.transform.TransformDirection(Vector3.back)) * dis;
改为:
Vector3.Normalize(Camera.main.transform.TransformDirection(Vector3.back)) * dis * Time.deltaTime;
但是,这样可能会出现“移动物体过快导致穿墙”的问题。
关于 TransformDirection 参考资料: Unity TransformPoint、InverseTransformPoint、TransformDirection
Vector3 worldPosition = transform.TransformPoint ( Vector3 relativePosition )
将相对 “当前游戏对象” 的坐标转化为基于世界坐标系的坐标
Vector3 relativePosition = transform.InverseTransformPoint ( Vector3 worldPosition )
将世界坐标转化为相对 “当前游戏对象” 的基于世界坐标系的坐标
Vector3 worldDirection = Transform.TransformDirection ( Vector3 relativeDirection )
将相对 “当前游戏对象” 的方向转化为基于世界坐标系的方向(不受父对象缩放的影响)
进阶1 四个方向Raycast
在上一种方法中,显然,只有一个方向(前方)能不穿墙,没有考虑如下情况:
- 摄像机倒着走,从背后穿墙
- 摄像机横着向左/右走,从左/右穿墙
这里用了一个比较蠢的方法,就是往前、后、左、右四个方向投射线,作四次检测。把这个检测过程封装成函数detect()。
Vector3.forward实际是一个固定值,unity 内置的vector3还有以下一些方向:
参考资料 Unity - Scripting API: Vector3
| back | Shorthand for writing Vector3(0, 0, -1). |
| down | Shorthand for writing Vector3(0, -1, 0). |
| forward | Shorthand for writing Vector3(0, 0, 1). |
| left | Shorthand for writing Vector3(-1, 0, 0). |
| negativeInfinity | Shorthand for writing Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity). |
| one | Shorthand for writing Vector3(1, 1, 1). |
| positiveInfinity | Shorthand for writing Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity). |
| right | Shorthand for writing Vector3(1, 0, 0). |
| up | Shorthand for writing Vector3(0, 1, 0). |
| zero | Shorthand for writing Vector3(0, 0, 0). |
void detect(Vector3 dir, Vector3 inverse_dir)
{RaycastHit hitInfo;Vector3 _dir = Camera.main.transform.TransformDirection(dir);if (Physics.Raycast(Camera.main.transform.position, _dir, out hitInfo, 0.5f)){float dis = hitInfo.distance;Vector3 correction = Vector3.Normalize(Camera.main.transform.TransformDirection(inverse_dir)) * dis;Camera.main.transform.position += correction;}
}// Update is called once per frame
void Update()
{detect(Vector3.forward, Vector3.back);detect(Vector3.back, Vector3.forward);detect(Vector3.left, Vector3.right);detect(Vector3.right, Vector3.left);
}
进阶2 SphereCast
这里,射线只有一个像素点,尽管已经覆盖四个方向,但是可能还是会有疏漏的情况。可以用Physics.SphereCast()方法。
可参考下列指南:http://www.ceeger.com/Script/Physics/Physics.SphereCast.html
void detect(Vector3 dir, Vector3 inverse_dir)
{RaycastHit hitInfo;Vector3 _dir = Camera.main.transform.TransformDirection(dir);if (Physics.SphereCast(Camera.main.transform.position, 0.5f, _dir, out hitInfo, 0.5f)){float dis = hitInfo.distance;Vector3 correction = Vector3.Normalize(Camera.main.transform.TransformDirection(inverse_dir)) * dis;Camera.main.transform.position += correction;}
}// Update is called once per frame
void Update()
{detect(Vector3.forward, Vector3.back);detect(Vector3.back, Vector3.forward);detect(Vector3.left, Vector3.right);detect(Vector3.right, Vector3.left);
}
进阶3 层遮罩LayerMask
某些碰撞体(collider) 可能只被用作trigger,但是却受到了碰撞检测。
一个比较简单的方法:
把物体放置到 Ignore Raycast层

或者用LayerMask,以下为示例:
void detect(Vector3 dir, Vector3 inverse_dir)
{RaycastHit hitInfo;Vector3 _dir = Camera.main.transform.TransformDirection(dir);LayerMask _ignoreLayer = 1 << LayerMask.NameToLayer("mylayer");if (Physics.Raycast(Camera.main.transform.position, _dir, out hitInfo, 0.5f, _ignoreLayer)){float dis = hitInfo.distance;Vector3 correction = Vector3.Normalize(Camera.main.transform.TransformDirection(inverse_dir)) * dis;Camera.main.transform.position += correction;}
}
更详细资料可参考:U3D开发学习之路--RayCast中layerMask的使用
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
