我正在研究Unity开发的适用于Android的无尽转轮游戏。我不想使用运动刚体。因此涉及物理,但默认情况下,刚体应沿预定路径运行。 (并通过用户操作来跳转或更改车道)。直线移动很容易。我已经做到了,但我想在转弯的比赛中进入下一个阶段。它似乎可以正常工作,但有时会出现抖动,转弯并不像我希望的那样平稳。而且,如果我提高速度,播放器就会变怪。不管速度如何,能否请我帮我优化代码以使转弯更平稳。
据我搜索,我在互联网上找不到答案,可能是人们更频繁地使用运动刚体,以便不理会物理学。因此,我使用.AddForce
和.AddTorque
。现在,我使用具有预定转弯(预制件)的预制件。因此,它随着玩家的前进而生成。每个道路预制件都具有用于移动路径的样条线(我想是基于Unity 2015过程样条线生成视频的免费资产)。因此,玩家将沿着样条线拾取一个节点并将其设置为目标,并使用其旋转方向转向使用AddTorque。
如果我改用运动刚体,也许会更容易。也许这是理想的选择,但我坚持这样做是为了学习物理,并且由于没有足够的资源,有些人可能会发现它对另一个项目很有用。
void FixedUpdate()
{
if (!jump)
{
//maxangle = Mathf.Clamp(r.velocity.magnitude * 2f,3,15f);
maxangle = r.velocity.magnitude;
r.constraints = RigidbodyConstraints.None;
r.constraints = RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezeRotationX;
TurnToTarget(transform, sample.Rotation,target, maxangle);
r.constraints = RigidbodyConstraints.None;
r.constraints = RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY;
}
//Debug.Log(currentroad.transform.name + maxangle);
if (!GameManager.gameManager.dead && running)
{
r.isKinematic = false;
//Debug.Log(transform.position.y);
var speed = r.velocity.magnitude;
Vector3 directionOfTarget = (target - transform.position).normalized;
if (speed < runspeed)
{
//r.velocity += Vector3.forward * 1f;
Debug.Log(r.velocity.z+ " " + r.velocity.magnitude);
Debug.Log(directionOfTarget);
r.AddForce(directionOfTarget* (runspeed-speed), ForceMode.VelocityChange);
}
if (transform.position.y > 2.7f)
{
r.mass = 50000f;
Physics.gravity = new Vector3(0, -100f, 0);
}
if (grounded)
{
r.mass = 10f;
Physics.gravity = new Vector3(0, -10f, 0);
}
private void TurnToTarget(Transform transform, Quaternion targetrot, Vector3 movePoint, float maxTurnAccel)
{
Vector3 directionOfTarget = (movePoint -transform.position).normalized;
Vector3 directionInEulers = targetrot.eulerAngles;
Vector3 offsetInEulers = ClampHeading(directionInEulers) - ClampHeading(transform.eulerAngles);
offsetInEulers = ClampHeading(offsetInEulers);
//optional
Vector3 angularVelocity = r.angularVelocity / Time.fixedDeltaTime;
if (offsetInEulers.sqrMagnitude < Mathf.Pow(maxTurnAccel, 2))
{
if (offsetInEulers.y < 0)
{
if (angularVelocity.y < offsetInEulers.y)
{
offsetInEulers.y = -offsetInEulers.y;
}
}
else
{
if (angularVelocity.y > offsetInEulers.y)
{
offsetInEulers.y = -offsetInEulers.y;
}
}
if (offsetInEulers.x > 0)
{
if (angularVelocity.x < -offsetInEulers.x)
{
offsetInEulers.x = -offsetInEulers.x * 2;
}
}
else
{
if (angularVelocity.x > -offsetInEulers.x)
{
offsetInEulers.x = -offsetInEulers.x * 2;
}
}
if (offsetInEulers.z > 0)
{
if (angularVelocity.z < -offsetInEulers.z)
offsetInEulers.z = -offsetInEulers.z * 2;
}
else
{
if (angularVelocity.z > -offsetInEulers.z)
offsetInEulers.z = -offsetInEulers.z * 2;
}
}
offsetInEulers = ClampVector(offsetInEulers, -maxTurnAccel, maxTurnAccel);
//Debug.Log(currentroad + " " + offsetInEulers + " " + r.angularVelocity + " " + directionOfTarget + " " + ClampHeading(directionInEulers)+" " +transform.eulerAngles);
r.AddRelativeTorque(transform.up * offsetInEulers.y);
//r.AddTorque(offsetInEulers*r.velocity.magnitude);
}
答案 0 :(得分:3)
您可以查看样条曲线。您可以通过计算沿着角色在路径上移动字符所需的点,以使角色从一个点移动到另一个点,以使其看起来平滑。
有时,当人物快速移动时,模糊效果可用于减少需要绘制的多边形数量。
答案 1 :(得分:2)
首先要注意的是这段代码:
if (transform.position.y > 2.7f)
{
r.mass = 50000f;
Physics.gravity = new Vector3(0, -100f, 0);
}
if (grounded)
{
r.mass = 10f;
Physics.gravity = new Vector3(0, -10f, 0);
}
如果您正在操纵质量以达到“停止”的效果。如果播放器处于空中,则以高重力值将它们猛撞到地面,以使其迅速减速。操纵运动中的物体的质量可能会导致很多问题,尤其是在同一物理框架中施加力的情况下。我看到您使用 ForceMode.VelocityChange 来解决此问题,因此您对此表示敬意。但是,当您向对象添加RelativeTorque时,其影响在很大程度上取决于质量。
直接更改对象的质量不会自动缩放对象具有的当前线性和角动量。相反,当您将质量增加到50,000f时,您将通过以下方式增加动量:
50,000 / (prior mass).
不断变化的质量通常会引起问题。我建议您找到一种不同的解决方案,将您的玩家逼到不涉及操纵质量(以及较小的重力)的位置。也许保持刚体的位置下降,或者施加向下的脉冲力可能会达到相同的效果,而不会出现漏洞。
所有这些逻辑都在FixedUpdate()周期中发生。这与运行每帧的Update()周期是分开的。我看到您正在访问一些特定于帧的数据,特别是 transform.position 和 transform.eulerAngles 。在下一帧周期发生之前可能会发生2个物理周期,结果如下:
Update() - transform is updated
FixedUpdate() - reads most recent transform data
Update() - transform is updated
FixedUpdate() - reads most recent transform data
FixedUpdate() - reads most recent transform data
Update() - transform is updated
由于您的某些游戏逻辑是基于变换数据的,所以FixedUpdate()有时在更新之前有时会发生双重作用,从而导致抖动。
我建议避免在FixedUpdate()中进行任何转换读取,而应使用RigidBody.position。更改旋转角度会更加细微,但是RigidBody.MoveRotation在这里也可能有用。