1.为什么不用自带的物理系统
用unity进行2D游戏开发的时候一般都不会使用unity自带的2D物理系统,有几个因素:不可控(位置 旋转 )
2.静态的碰撞体
只带有碰撞体且没有刚体的物体属于静态碰撞体 如果需要让静态碰撞体移动 最好使用刚体使用物理方法 或者给对象加一个动力学刚体 不然也很消耗性能
3.移动
为了模拟真实的移动,你需要分别模拟 加速 匀速 减速 为了模拟这三种状态 你需要模拟加速度 和 摩擦力
//变速写法 inputHori = Input.GetAxis("Horizontal"); float s = 0.8f * speedChangeFactor; speedIncrement = 0; frictionPower = 0; //使用摇杆就清除所有除了遥感之外的横向反向速度 if (inputHori > 0.1f) { speedIncrement = s; if (shootDir.x < 0) { shootx = 0; shootSpeedX = 0; } if (reBoundDir.x < 0) { reBoundX = 0; reboundSpeedX = 0; } } else if (inputHori < -0.1f) { speedIncrement = -s; if (shootDir.x > 0) { shootx = 0; shootSpeedX = 0; } if (reBoundDir.x > 0) { reBoundX = 0; reboundSpeedX = 0; } } //摩擦力 if (moveSpeed > 0) { frictionPower = -Friction; } else if (moveSpeed < 0) { frictionPower = Friction; } moveSpeed += (speedIncrement + frictionPower) * Time.fixedDeltaTime; //静止方法 (这是偷懒方法 正确写法是摩擦力不会让速度反转 暂时不知道怎么写) if (Mathf.Abs(moveSpeed) < frictionPower * Time.fixedDeltaTime) { moveSpeed = 0; }
//速度限制 if (Mathf.Abs(moveSpeed) > MoveSpeed) { moveSpeed = (moveSpeed / Mathf.Abs(moveSpeed)) * MoveSpeed; }
这里的核心思路就是 利用摇杆的的变换来累计增量 而不是直接改位置 我们只对加速度进行控制 这里的 moveSpeed是一帧要移动的位置 当对加速度计算完毕后,再在Update最后一帧把所有的速度增量一起赋值给位置,因为在上一次模拟角色控制的时候在每一个需要移动的方法里都会对当前的位置进行改变,这样写虽然方便,但是主角的移动会有掉帧和卡顿的感觉,原因就是在一个Update里面多次修改主角的位置,
4.射线检测
unity里面的射线检测在使用的时候,有几个需要注意的盲点:一、3D的射线无法从碰撞体里面检测的物体,但是2D的射线可以,二、当主角一帧位移的距离大于射线长度的时候射线就会大概率检测不到。
射线检测是模拟物体是否碰到障碍,是否碰到物体的常用方法。为了解决盲点的第二个问题 ,就需要对所有的会对主角产生位移的方法,先算他们的加速度,在每一帧进行射线检测的提前将这一帧玩家要位移的距离计算出来,然后动态修改射线的长度。
注意当射线检测到的时候要注意将玩家的位置放置到合适的位置
void HorDownRayCheck() { //提前计算位移量 posX是算好的这一帧的X方向的位移增量 lengthX = Mathf.Abs(posX); lengthY = Mathf.Abs(posY); if (lengthY < 0.4f) { lengthY = 0.4f; } if (lengthX < 0.4f) { lengthX = 0.4f; } if (posX > 0) { horiRaynub = 1; } else if (posX < 0) { horiRaynub = -1; } else { if (inputHori > 0) { horiRaynub = 1; } else if (inputHori < 0) { horiRaynub = -1; } } RaycastHit2D horiHitOne = Physics2D.Raycast(horiRayOne.position, Vector3.right * horiRaynub, lengthX + 0.4f, 1 << 8); if (horiHitOne) { if (horiHitOne.collider.CompareTag("VeritualGround")) { transform.position = new Vector2(horiHitOne.point.x - 0.34f * horiRaynub, transform.position.y); isHorWallHere = true; } } RaycastHit2D horiHitTwo = Physics2D.Raycast(horiRayTwo.position, Vector3.right * horiRaynub, lengthX + 0.4f, 1 << 8); if (horiHitTwo) { if (horiHitTwo.collider.CompareTag("VeritualGround")) { transform.position = new Vector2(horiHitTwo.point.x - 0.34f * horiRaynub, transform.position.y); isHorWallHere = true; } } if (!horiHitOne && !horiHitTwo) { isHorWallHere = false; } RaycastHit2D downHitOne = Physics2D.Raycast(downRayOne.position, Vector3.down, lengthY, 1 << 8); if (downHitOne) { if (downHitOne.collider.CompareTag("DownGround")) { transform.position = new Vector2(transform.position.x, downHitOne.point.y + 0.34f); currentState = states.ground; isDownWallHere = true; jumpTimes = JumpTimes; return; } } RaycastHit2D downHitTwo = Physics2D.Raycast(downRayTwo.position, Vector3.down, lengthY, 1 << 8); if (downHitTwo) { if (downHitTwo.collider.CompareTag("DownGround")) { transform.position = new Vector2(transform.position.x, downHitTwo.point.y + 0.34f); currentState = states.ground; isDownWallHere = true; jumpTimes = JumpTimes; return; } } isDownWallHere = false; } void UpRayCheck() { if (posY < 0) return; RaycastHit2D upHitOne = Physics2D.Raycast(upRayOne.position, Vector3.up, lengthX, 1 << 8); if (upHitOne) { if (upHitOne.collider.CompareTag("UpGround")) { transform.position = new Vector2(transform.position.x, upHitOne.point.y - 0.34f); gvec = -0.2f; return; } } RaycastHit2D upHitTwo = Physics2D.Raycast(upRayTwo.position, Vector3.up, lengthY, 1 << 8); if (upHitTwo) { if (upHitTwo.collider.CompareTag("UpGround")) { transform.position = new Vector2(transform.position.x, upHitTwo.point.y - 0.34f); //修改重力 让主角下坠 防止一直被上一行代码影响 这里有多种解决方法 目前这一种是配合模拟重力比较好用的 gvec = -0.2f; return; } } }
5.模拟重力
void Gravity() { gvec += Physics2D.gravity.y * Time.fixedDeltaTime * Time.fixedDeltaTime * JumpSpeed; }
将 gvec作为Y轴的增量给到付给位置就可以了 如果需要人物跳跃 只需要给gvec附一正值就可以了 jumpSeed是控制主角跳跃的速度 也同时是重力倍数
自己模拟物理移动是有趣并且很帮助理解物理的过程,重点就是模拟 当我们想要一种运动方式的时候 首先要了解它在真实世界运动的本质,不要尝试对位置直接修改一部到位。
下面这张gif是在上面代码的基础上模拟效果出来的一个三维弹球的效果 使用了球形射线 置位置 计算了入射角和反射角等