父轮换的统一轮换问题

时间:2012-10-23 19:43:55

标签: c# rotation unity3d

首先,这里是问题的视频: link to videopackage 这是hierachey的截图: enter image description here 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);

问题保持不变:(

3 个答案:

答案 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的旋转是在炮塔旋转之前和之后应用的,并且错误正在累积。