墙和物体都要加上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还有以下一些方向:

参考资料 https://docs.unity3d.com/ScriptReference/Vector3.html

backShorthand for writing Vector3(0, 0, -1).
downShorthand for writing Vector3(0, -1, 0).
forwardShorthand for writing Vector3(0, 0, 1).
leftShorthand for writing Vector3(-1, 0, 0).
negativeInfinityShorthand for writing Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity).
oneShorthand for writing Vector3(1, 1, 1).
positiveInfinityShorthand for writing Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity).
rightShorthand for writing Vector3(1, 0, 0).
upShorthand for writing Vector3(0, 1, 0).
zeroShorthand 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的使用

墙和物体都要加上collider(碰撞体),一般注意以下几点:墙加mesh collider,在Convex上打勾 物体加box collider 加刚体(rigidbody)的物体不要选Is Kenimatic基础最简单的Raycast方法void Update(){ RaycastHit hitInfo; Vector3 fwd = Camera.m...
昨天做室内模型的时候,遇到一个非常棘手的问题,那就是第一视角在室内运行的时候,会出现穿墙的效果。类似下图效果,在靠近墙壁的时候,出现了镜头看见了墙壁外的情况,很显然这是不符合逻辑的。我们要做的就是避免这一问题的发生。 我的代码很简单,就是官方的FPS控制器,拿过来就能用。 我一开始遇到这个问题,也是搜了很多的资源,网上的答案层出不穷,脚本也是千奇百怪,但是这些对我来说,意义都不大,都没...
//首先,不好意思,可能标题的描述并不是很清楚 //我们现在的场景是这样的,一个摄像机在高处,场景中间有一面高墙,墙的后面有一个球形物体 //高度够高的时候我们可以看到球形物体,当摄像机的y轴下降的时候,就只能看到墙,看不到球形物体 //而我们现在的需求是,当球形物体被墙挡住的时候,我们想让墙消失,y轴够高的时候,又让墙出现 //好了,接下来看我们的代码吧~ using Unit
这个问题,摄像机拍摄主角,当主角被墙遮蔽了视野,那么就用正上方的点和当前相机所在位置的店为起始点和终点,从二者之间再找出三个关键点进行射线检测,能看到主角的店即可作为摄像机的transform.position Vector3[] posArray; Vector3 beginPos = player.transform.position + offset; Vector3 endPo
1.重新进行Unity布局,右上角哪里重新进行Layout布局,一般可以恢复Scene视角相机的初始化 2.Scene视角顶部信息栏有一个摄像头图标,点开,就是可以进行Scene摄像机的控制,把Field of View调小就可以调整穿模现象了。
我学习Unity3D一小段时间了,第一个制作目标就是实现一个自由漫游摄像机。 使用WSAD键控制摄像机的上下左右移动,使用鼠标右键控制摄像机的旋转。 这个功能比较简单,代码也一目了然,不做过多解释了,直接上代码。 //----------------------------------------------------------------- //1,把本类作为一个组件,包含在 Gam