Unity3d 脚本应用旋转两次?
Unity3d script applying rotation twice?
我一直在研究一个简单的 space 车辆控制器,它允许移动、偏航、滚动和俯仰。它在每个轴上都很好用,但是当我偏航和滚动、俯仰和移动等时,旋转是不正确的。我相信事情发生了两次,因为当车辆处于 90 度俯仰角时,它应该垂直移动时水平移动(90 度旋转时偏离 90 度)。 45 岁时,它处于中间位置。在 0 时它按预期工作。
我的完整代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Input : MonoBehaviour
{
private Rigidbody rb;
public float moveAcceleration = 50f;
public float maxMoveSpeed = 500f;
public float turnAcceleration = 30f;
public float maxTurnSpeed = 100f;
public float rotAcceleration = 30f;
public float maxRotSpeed = 100f;
private float moveSpeed = 0;
private float pitchSpeed = 0;
private float yawSpeed = 0;
private float rollSpeed = 0;
private Vector3 angle = new Vector3 (0, 0, 0);
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKey("w")) {
moveSpeed += moveAcceleration * Time.deltaTime;
} else if(Input.GetKey("s")) {
moveSpeed -= moveAcceleration * Time.deltaTime;
}
if(moveSpeed > 10f) {
moveSpeed -= 5f * Time.deltaTime;
}else if(moveSpeed < -10f) {
moveSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("w") && !Input.GetKey("s")) {
moveSpeed = 0f;
}
moveSpeed = Mathf.Clamp(moveSpeed, -maxMoveSpeed, maxMoveSpeed);
if(Input.GetKey("a")) {
yawSpeed += turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("d")) {
yawSpeed -= turnAcceleration * Time.deltaTime;
}
if(yawSpeed > 10f) {
yawSpeed -= 5f * Time.deltaTime;
}else if(yawSpeed < -10f) {
yawSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("a") && !Input.GetKey("d")) {
yawSpeed = 0f;
}
yawSpeed = Mathf.Clamp(yawSpeed, -maxTurnSpeed, maxTurnSpeed);
if(Input.GetKey("left")) {
rollSpeed += rotAcceleration * Time.deltaTime;
} else if(Input.GetKey("right")) {
rollSpeed -= rotAcceleration * Time.deltaTime;
}
if(rollSpeed > 10f) {
rollSpeed -= 5f * Time.deltaTime;
}else if(rollSpeed < -10f) {
rollSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("left") && !Input.GetKey("right")) {
rollSpeed = 0f;
}
rollSpeed = Mathf.Clamp(rollSpeed, -maxRotSpeed, maxRotSpeed);
if(Input.GetKey("up")) {
pitchSpeed += turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("down")) {
pitchSpeed -= turnAcceleration * Time.deltaTime;
}
if(pitchSpeed > 10f) {
pitchSpeed -= 5f * Time.deltaTime;
}else if(pitchSpeed < -10f) {
pitchSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("up") && !Input.GetKey("down")) {
pitchSpeed = 0f;
}
pitchSpeed = Mathf.Clamp(pitchSpeed, -maxTurnSpeed, maxTurnSpeed);
this.transform.Translate(moveSpeed * transform.forward * Time.deltaTime);
angle += Time.deltaTime * ((pitchSpeed * transform.right) + (rollSpeed * transform.forward) + (yawSpeed * transform.up));
//Debug.Log(transform.forward);
this.transform.eulerAngles = angle;
}
}
相关的位在最后(加速度和预期的工作),就在设置角度的地方。变换是正确的(我已经检查过),但应用的动作不正确。你看到问题了吗?
谢谢,我很感激!
编辑:GameObject 上也只有 1 个脚本实例,只是为了进一步缩小范围。
编辑 2:我发现 this 论坛 post 似乎有同样的问题,但我不认为我做过与此人相同的事情。也许是一个好的起点?
编辑 3:我觉得“angle += ...”行是罪魁祸首,但我说不出原因。也许看那里。
使用 Quaterion
class 来避免万向节锁定并将当前旋转与新的附加旋转相乘。我修改了你脚本的最后几行:
> angle = new Vector3(pitchSpeed, yawSpeed, rollSpeed);
> transform.rotation *= Quaternion.Euler(angle);
> transform.Translate(moveSpeed * transform.forward * Time.deltaTime, Space.World);
你会想大大减少这些,我把它们除以 10,看起来很平滑:
public float turnAcceleration = 30f;
public float maxTurnSpeed = 100f;
public float rotAcceleration = 30f;
public float maxRotSpeed = 100f;
不确定您是希望偏航方向是按下的方向还是反转的方向,目前如果您按下左键,它就会向右偏航,如果需要,您可以反转这些方向:
if(Input.GetKey("a")) {
yawSpeed += turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("d")) {
yawSpeed -= turnAcceleration * Time.deltaTime;
}
如果您正在制作 space 游戏,您可能需要考虑使用 https://docs.unity3d.com/ScriptReference/Mathf.SmoothDamp.html or https://docs.unity3d.com/ScriptReference/Vector3.SmoothDamp.html 平滑 moveSpeed , pitchSpeed, yawSpeed, rollSpeed
以使动作更逼真。
我一直在研究一个简单的 space 车辆控制器,它允许移动、偏航、滚动和俯仰。它在每个轴上都很好用,但是当我偏航和滚动、俯仰和移动等时,旋转是不正确的。我相信事情发生了两次,因为当车辆处于 90 度俯仰角时,它应该垂直移动时水平移动(90 度旋转时偏离 90 度)。 45 岁时,它处于中间位置。在 0 时它按预期工作。
我的完整代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Input : MonoBehaviour
{
private Rigidbody rb;
public float moveAcceleration = 50f;
public float maxMoveSpeed = 500f;
public float turnAcceleration = 30f;
public float maxTurnSpeed = 100f;
public float rotAcceleration = 30f;
public float maxRotSpeed = 100f;
private float moveSpeed = 0;
private float pitchSpeed = 0;
private float yawSpeed = 0;
private float rollSpeed = 0;
private Vector3 angle = new Vector3 (0, 0, 0);
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKey("w")) {
moveSpeed += moveAcceleration * Time.deltaTime;
} else if(Input.GetKey("s")) {
moveSpeed -= moveAcceleration * Time.deltaTime;
}
if(moveSpeed > 10f) {
moveSpeed -= 5f * Time.deltaTime;
}else if(moveSpeed < -10f) {
moveSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("w") && !Input.GetKey("s")) {
moveSpeed = 0f;
}
moveSpeed = Mathf.Clamp(moveSpeed, -maxMoveSpeed, maxMoveSpeed);
if(Input.GetKey("a")) {
yawSpeed += turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("d")) {
yawSpeed -= turnAcceleration * Time.deltaTime;
}
if(yawSpeed > 10f) {
yawSpeed -= 5f * Time.deltaTime;
}else if(yawSpeed < -10f) {
yawSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("a") && !Input.GetKey("d")) {
yawSpeed = 0f;
}
yawSpeed = Mathf.Clamp(yawSpeed, -maxTurnSpeed, maxTurnSpeed);
if(Input.GetKey("left")) {
rollSpeed += rotAcceleration * Time.deltaTime;
} else if(Input.GetKey("right")) {
rollSpeed -= rotAcceleration * Time.deltaTime;
}
if(rollSpeed > 10f) {
rollSpeed -= 5f * Time.deltaTime;
}else if(rollSpeed < -10f) {
rollSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("left") && !Input.GetKey("right")) {
rollSpeed = 0f;
}
rollSpeed = Mathf.Clamp(rollSpeed, -maxRotSpeed, maxRotSpeed);
if(Input.GetKey("up")) {
pitchSpeed += turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("down")) {
pitchSpeed -= turnAcceleration * Time.deltaTime;
}
if(pitchSpeed > 10f) {
pitchSpeed -= 5f * Time.deltaTime;
}else if(pitchSpeed < -10f) {
pitchSpeed += 5f * Time.deltaTime;
} else if(!Input.GetKey("up") && !Input.GetKey("down")) {
pitchSpeed = 0f;
}
pitchSpeed = Mathf.Clamp(pitchSpeed, -maxTurnSpeed, maxTurnSpeed);
this.transform.Translate(moveSpeed * transform.forward * Time.deltaTime);
angle += Time.deltaTime * ((pitchSpeed * transform.right) + (rollSpeed * transform.forward) + (yawSpeed * transform.up));
//Debug.Log(transform.forward);
this.transform.eulerAngles = angle;
}
}
相关的位在最后(加速度和预期的工作),就在设置角度的地方。变换是正确的(我已经检查过),但应用的动作不正确。你看到问题了吗?
谢谢,我很感激!
编辑:GameObject 上也只有 1 个脚本实例,只是为了进一步缩小范围。
编辑 2:我发现 this 论坛 post 似乎有同样的问题,但我不认为我做过与此人相同的事情。也许是一个好的起点?
编辑 3:我觉得“angle += ...”行是罪魁祸首,但我说不出原因。也许看那里。
使用 Quaterion
class 来避免万向节锁定并将当前旋转与新的附加旋转相乘。我修改了你脚本的最后几行:
> angle = new Vector3(pitchSpeed, yawSpeed, rollSpeed);
> transform.rotation *= Quaternion.Euler(angle);
> transform.Translate(moveSpeed * transform.forward * Time.deltaTime, Space.World);
你会想大大减少这些,我把它们除以 10,看起来很平滑:
public float turnAcceleration = 30f;
public float maxTurnSpeed = 100f;
public float rotAcceleration = 30f;
public float maxRotSpeed = 100f;
不确定您是希望偏航方向是按下的方向还是反转的方向,目前如果您按下左键,它就会向右偏航,如果需要,您可以反转这些方向:
if(Input.GetKey("a")) {
yawSpeed += turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("d")) {
yawSpeed -= turnAcceleration * Time.deltaTime;
}
如果您正在制作 space 游戏,您可能需要考虑使用 https://docs.unity3d.com/ScriptReference/Mathf.SmoothDamp.html or https://docs.unity3d.com/ScriptReference/Vector3.SmoothDamp.html 平滑 moveSpeed , pitchSpeed, yawSpeed, rollSpeed
以使动作更逼真。