首先,这里是问题的视频:
link to video,package
这是hierachey的截图:
GUN是脚本的父级(空游戏对象)暂停被放到towerRotateObj
,而枪被放在turretRotateObj
上。暂停和枪也是空的游戏对象。它们只是某种群体对象
这里是代码:
public class WeaponMover : MonoBehaviour
{
public Transform target;
public GameObject turretRotateObj;
public GameObject towerRotateObj;
public float maxTowerRotationSpeed = 360.0f;
public float maxTurretRotationSpeed = 360.0f;
public float smoothFactorTower = 0.125f;
public float smoothFactorTurret = 0.125f;
public float maxTowerRotation = 130.0f;
public float maxTurretRotation = 50.0f;
private Vector3 m_newRotation;
private Vector3 m_angles;
private float m_minTowerAngle;
private float m_maxTowerAngle;
private float m_minTurretAngle;
private float m_maxTurretAngle;
private float m_velTower;
private float m_velTurret;
private bool m_isTransNecTower = false;
private bool m_isTransNecTurret = false;
// initialization
void Start()
{
m_newRotation = Vector3.zero;
m_angles = Vector3.zero;
m_maxTowerAngle = towerRotateObj.transform.eulerAngles.y + maxTowerRotation/2;
m_minTowerAngle = towerRotateObj.transform.eulerAngles.y - maxTowerRotation/2;
m_maxTurretAngle = turretRotateObj.transform.eulerAngles.z + maxTurretRotation/2;
m_minTurretAngle = turretRotateObj.transform.eulerAngles.z - maxTurretRotation/2;
// check if rotation happens between 0/360
// tower
if(m_minTowerAngle <= 0.0f)
m_minTowerAngle += 360.0f;
if(m_maxTowerAngle >= 360.0f)
m_maxTowerAngle -= 360.0f;
if(m_minTowerAngle > m_maxTowerAngle)
m_isTransNecTower = true;
// turret
if(m_minTurretAngle <= 0.0f)
m_minTurretAngle += 360.0f;
if(m_maxTurretAngle >= 360.0f)
m_maxTurretAngle -= 360.0f;
if(m_minTurretAngle > m_maxTurretAngle)
m_isTransNecTurret = true;
}
void Update()
{
m_newRotation = Quaternion.LookRotation(target.position - towerRotateObj.transform.position).eulerAngles;
m_angles = towerRotateObj.transform.rotation.eulerAngles;
towerRotateObj.transform.rotation = Quaternion.Euler(m_angles.x,
ClampAngle(Mathf.SmoothDampAngle(m_angles.y,
m_newRotation.y - 90.0f,
ref m_velTower,
smoothFactorTower,
maxTowerRotationSpeed), m_minTowerAngle, m_maxTowerAngle, m_isTransNecTower),
m_angles.z);
m_newRotation = Quaternion.LookRotation(target.position - turretRotateObj.transform.position).eulerAngles;
m_angles = turretRotateObj.transform.rotation.eulerAngles;
turretRotateObj.transform.rotation = Quaternion.Euler(m_angles.x,
m_angles.y,
ClampAngle(Mathf.SmoothDampAngle(m_angles.z,
-m_newRotation.x,
ref m_velTurret,
smoothFactorTurret,
maxTurretRotationSpeed), m_minTurretAngle, maxTurretRotation, m_isTransNecTurret));
}
private float ClampAngle(float angle, float min, float max, bool isTranslationNecessary)
{
if(!isTranslationNecessary)
{
if(angle < min )
return min;
if(angle > max)
return max;
}
else
{
if(angle > max && angle < min)
{
if(min - angle > angle - max)
return max;
else
return min;
}
}
return angle;
}
}
所以,这是一个类似的设置,如坦克和坦克的枪.... 我已经发布了这个问题here,但似乎很少有人看到这个帖子......任何建议都表示赞赏!感谢。
更新
m_newRotation = Quaternion.LookRotation(m_target.transform.position - towerRotateObj.transform.position).eulerAngles;
m_newRotation.y -= 90f;
m_angles = towerRotateObj.transform.rotation.eulerAngles;
towerRotateObj.transform.rotation = Quaternion.Euler(m_angles.x, m_newRotation.y, m_angles.z);
m_newRotation = Quaternion.LookRotation(m_target.transform.position - turretRotateObj.transform.position).eulerAngles;
m_angles = turretRotateObj.transform.rotation.eulerAngles;
turretRotateObj.transform.rotation = Quaternion.Euler(m_angles.x, m_angles.y, -m_newRotation.x);
问题保持不变:(
答案 0 :(得分:3)
所以我的猜测,万向锁,就像在另一个答案中说的那样。但是,我不确定我会尝试解决这个问题,考虑到你将四元数传递给欧拉,反之亦然。如果我必须这样做,我不会像你那样做,因为在对象之间使用四元数进行父母教育等同于大规模的头痛。
首先,在您为父对象提供教育时,您没有使用该功能!这是Unity的一个非常可靠的功能。育儿育儿:http://docs.unity3d.com/Documentation/ScriptReference/Transform-parent.html
每个炮塔对象仅在一个局部轴上旋转。而Unity则用于处理:http://docs.unity3d.com/Documentation/ScriptReference/Transform-localRotation.html
当一个物体成为另一个物体的父级时,您可以在所需的轴上局部旋转它。 Unity自己处理整体矩阵转换。当您修改对象的全局旋转时,您基本上会覆盖来自父对象的转换。此时,任何层次结构都很容易随着时间的推移而获得错误和不精确。
编辑:通过你的包裹,我能够写出我的意思:
public class WeaponMover : MonoBehaviour
{
public GameObject boat;
public GameObject turretRotateObj;
public GameObject towerRotateObj;
public GameObject target;
private Vector3 lastDirection;
// initialization
void Start()
{
lastDirection = boat.transform.forward;
}
void Update()
{
// Find direction toward our target. Use turret as origin.
Vector3 wantedDirection = target.transform.position - turretRotateObj.transform.position;
// Rotate our last direction toward that new best direction. Change floats to make it move faster or slower.
lastDirection = Vector3.RotateTowards(lastDirection, wantedDirection, 0.01f, 0.01f);
// Find the direction local to the tower as the boat can move around!
Vector3 towerDirection = boat.transform.InverseTransformDirection(lastDirection);
// Remove unwanted axis
towerDirection = new Vector3(-towerDirection.z, 0, towerDirection.x);
towerDirection.Normalize();
// Set local rotation
towerRotateObj.transform.localRotation = Quaternion.LookRotation(towerDirection);
// Find the direction local to the gun, as the tower may have rotated!
Vector3 turretDirection = towerRotateObj.transform.InverseTransformDirection(lastDirection);
// Remove unwanted axis.
turretDirection = new Vector3(turretDirection.x, turretDirection.y, 0);
turretDirection.Normalize();
// Set local rotation
turretRotateObj.transform.localRotation = Quaternion.LookRotation(turretDirection);
}
}
注意:由于我很懒,我不得不将枪管移动到Z轴而不是X轴。因此,如果您只复制粘贴此代码,则枪管将指向框架,但枪将正确跟随目标。
由于旋转现在是本地的,你可以旋转船多年,枪永远不会有任何偏移。
答案 1 :(得分:1)
嗯,我不确定,但似乎你遇到了Gimbal Lock问题。尽管您的计算从四元数开始,但从长远来看,对Mathf.SmoothDampAngle
的两次调用可能是根本原因。
所以我建议首先删除所有平滑,然后,如果这被证明是罪魁祸首,请使用基于纯四元组的方法替换这些方法,如Quaternion.Slerp。
答案 2 :(得分:0)
从更新更改为LateUpdate后,我无法重现您的问题。也许我不是像你那样颠倒旋转,但我认为Gizmo的旋转是在炮塔旋转之前和之后应用的,并且错误正在累积。