使用rigidbody2d和collider2d,可以实现控制物体移动和碰撞。但是有一个问题让博主抓狂:代表玩家的小方块撞上障碍物时,会有一瞬间嵌入障碍物,然后被弹回去。
简单的控制代码如下:
private void Update() { inputX = Input.GetAxisRaw("Horizontal"); if (inputX != 0) { Vector2 dir = new Vector2(inputX, 0f); float dist = Mathf.Abs(speed * Time.deltaTime); rb.velocity = dir * dist; // 使用了刚体 } else { rb.velocity = Vector2.zero; } }
经实验,无论是换成AddForce也好,换成MovePosition也好,把Update换成FixedUpdate也好,改Material2D也好,都会有这烦人的抖一下。
如果不用刚体控制,改用transform.Translate,甚至还会造成连续抖动的效果。
根据【Unity物体移动碰撞抖动(原因和解决方法)】的说法,这是因为Update位于unity自身的物理处理之后,所以Update里面通过代码移动了位置,之后并不会经过unity自身的物理修正,就被渲染出来了,所以是嵌入墙里的;而下一帧的FixedUpdate修正了位置,就被弹出墙外了。但那样似乎没有解释为什么控制代码移到FixedUpdate后,还是会抖一下。
解决方法一:将Rigidbody2D的CollisionDetection属性从Discrete改为Continuous
但是很耗性能。
解决方法二:通过射线时刻检测“即将走的距离”上是否会发生碰撞,从而决定最终走多远的距离
这个方法甚至可以不挂刚体了,直接通过射线来获取碰撞。(但是OnCollisionEnter2D那些函数也不能用了)
但要注意的一点是,射线是会撞到玩家自己的碰撞体的,所以为了忽略自身,可以将想要检测的碰撞体放到同一Layer上,这样就可以进行过滤。
代码如下:
private void Update() { inputX = Input.GetAxisRaw("Horizontal"); if (inputX != 0) { Vector2 dir = new Vector2(inputX, 0f); float dist = Mathf.Abs(speed * Time.deltaTime); // collider的偏移量也纳入考虑 Vector2 startPos = (Vector2)transform.position + boxCollider.offset; var hit = Physics2D.BoxCast(startPos, boxCollider.size, 0, dir, dist, LayerMask.GetMask("Wall")); if (hit.collider != null) { Debug.Log("hit x"); Vector2 endPos = (Vector2) hit.collider.transform.position + hit.collider.offset; // 计算实际上可以移动的最大距离,即两个collider边界之间的距离 float maxDist = Mathf.Abs(endPos.x - startPos.x) - (boxCollider.size.x + hit.collider.bounds.size.x) / 2; transform.Translate(dir * maxDist); } else { transform.Translate(dir * dist); } } }
这样就可以了……吗?如果你把刚体去掉,然后把这个脚本挂到玩家身上,你会发现确实不抖了,但是玩家会贴在墙上卡住,没法移动了,而且会疯狂打印hit x,仿佛玩家的碰撞体和墙的碰撞体有所重合,所以射线检测在起点处就能检测到它。
给maxDist加一点偏移量可以解决:
maxDist -= 0.01f;
但这是为啥呢?
打开Project Settings - Physics2D,你能看到一个属性叫Default Contact Offset,值正好就等于0.01。根据文档,如果碰撞体的距离小于它们的 contactOffset 值之和,则将生成接触,也就是撞上了。所以我们强行让两个碰撞体之间的距离为0,实际上已经嵌在一起了。如果你仔细看本文开头的动图,可以发现即使是贴墙的时候,两者之间确实也有一点缝隙,这就是那0.01的距离。
这个值可以再调小一些,但调成0似乎会造成一些问题。我们通过射线确定移动距离时,记得把它给加上。
总算不抖了!可以睡个好觉了!
最后一个问题:怎么玩家走起来似乎有点忽快忽慢?
解决方案:只会在编辑器里这样,build出来顺滑得很。
标签:hit,unity2d,Vector2,碰撞,collider,移动,inputX,dir From: https://www.cnblogs.com/chopwoodfish/p/17103937.html