首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用移动设备的陀螺仪制作球平衡游戏

用移动设备的陀螺仪制作球平衡游戏
EN

Stack Overflow用户
提问于 2020-12-30 17:07:10
回答 2查看 274关注 0票数 0

正如标题已经说过的,我目前正在做一个小的球平衡游戏,使用陀螺仪旋转旋转一个带有球的浮动平台。我经常遇到的问题是:我不能锁定y轴。我使用了欧拉角,它工作得很完美,但我必须处理万向节锁。因为我不想处理欧拉的这个问题,所以我试着用四元数代替,它确实是以某种方式起作用的。我可以设置旋转,并可以定义一个校准偏移陀螺仪。如果我不计算这个偏移量,旋转将是绝对的,而不是相对于无名氏的世界空间。但是我总是有某种y旋转,即使我把四元数设置为0。

例如:我开始游戏,校准陀螺仪到我的旋转,但之后,围绕y轴旋转在现实世界的空间。这个平台一直面向着摄像机,但旋转轴也是如此。

正常的行为和它应该是怎样的(在真实的空间里没有y轴的旋转):https://www.nani-games.net/share/umSc6XH1vE.gif

实际行为和它不应该是什么(在现实世界空间中y轴的旋转):https://www.nani-games.net/share/AVicmV4fWe.gif

我已经尝试过的东西列表:

使用欧拉角和四元数组合组成一个新的四元数和所需参数/ rotations

  • Using Quaternion.AngleAxis以改变欧拉axes

  • Checking的顺序--约束下平台刚体的“冻结Y旋转”框(这不起作用,因为我不是用力来旋转,而是直接设置旋转)

如何建立我的场景: https://www.nani-games.net/share/Unity_fAQKW7cfPK.png

我有两个脚本,用来获得陀螺仪的旋转,使它在统一中有用,并用来旋转其他物体。

一个名为DeviceRotation的静态脚本。它激活陀螺仪并从它获得旋转:

代码语言:javascript
复制
using UnityEngine;

static class DeviceRotation
{
    public static Quaternion offsetRotation;

    private static bool gyroInitialized = false;

    public static bool HasGyroscope
    {
        get
        {
            return SystemInfo.supportsGyroscope;
        }
    }

    public static Quaternion Get()
    {
        if (!gyroInitialized)
        {
            InitGyro();
        }

        return HasGyroscope
            ? ReadGyroscopeRotation()
            : Quaternion.identity;
    }

    private static void InitGyro()
    {
        if (HasGyroscope)
        {
            Input.gyro.enabled = true;
            Input.gyro.updateInterval = 0.0167f; // 60Hz
        }
        gyroInitialized = true;
    }

    private static Quaternion ReadGyroscopeRotation()
    {
        return new Quaternion(0.5f, 0.5f, -0.5f, 0.5f) * Input.gyro.attitude * new Quaternion(0, 0, 1, 0);
    }

    public static void calibrateCoords()
    {
        Quaternion deviceRotation = Get();
        offsetRotation = deviceRotation;
    }
}

是附加到platform对象的第二个脚本。它获得一个校准四元数,从校准四元数中计算出一个新的四元数和一个不断更新的四元数(都来自陀螺旋转),然后将平台转换为这个新的旋转:

代码语言:javascript
复制
using UnityEngine;
using UnityEngine.UI;

public class Gyroscope : MonoBehaviour
{
    public Button resetSphere;
    public Button calibrate;
    public GameObject sphere;

    public Text platformCoords;
    public Text gyroOffsetCoords;

    void Start()
    {
        DeviceRotation.calibrateCoords();
        calibrate.onClick.AddListener(DeviceRotation.calibrateCoords);

        setGyroRotation();
        resetSphere.onClick.AddListener(ResetSphere);
    }

    void Update()
    {
        setGyroRotation();

        Vector3 offsetRotationEuler = DeviceRotation.offsetRotation.eulerAngles;
        gyroOffsetCoords.text = "GyroOffset:\n" +
                                "X: " + offsetRotationEuler.x + "\n" +
                                "Y: " + offsetRotationEuler.y + "\n" +
                                "Z: " + offsetRotationEuler.z;
    }

    private void ResetSphere()
    {
        GameObject temp_sphere = Instantiate(sphere);
        temp_sphere.transform.position = new Vector3(0, 3, 0);
    }

    private void setGyroRotation()
    {
        Quaternion deviceRotation = DeviceRotation.Get();
        Quaternion newRotation = Quaternion.Inverse(DeviceRotation.offsetRotation) * deviceRotation;
        transform.localRotation = newRotation;

        Vector3 platformAngles = transform.localRotation.eulerAngles;
        platformCoords.text = "Platform:" + "\n" +
                              "X: " + platformAngles.x + "\n" +
                              "Y: " + platformAngles.y + "\n" +
                              "Z: " + platformAngles.z;
    }
}

所以,总结一切:我的问题是,我不能锁定一个四元数的一个轴(y轴)。我还尝试使用euler进行所需的旋转,然后将其转换为四元数(这就是为什么脚本QuaternionToEuler和EulerToQuaternion中存在这两个函数OffsetGyro的原因),但不幸的是,这导致了gimbal锁定(我猜这是一个多么令人惊讶的事情)。

在这个四元数问题上我真的需要帮助,几天后我就被困住了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-01-01 02:57:50

所以,我玩了一小段时间,并试图随机创造一个可能的解决方案。这是我当前的函数setGyroRotation:

代码语言:javascript
复制
private void setGyroRotation()
{
    Quaternion deviceRotation = DeviceRotation.Get();
    Quaternion newRotation = Quaternion.Inverse(DeviceRotation.offsetRotation) * deviceRotation; // Calculating "initial" rotation
    axisObject.transform.rotation = newRotation; // Setting the axis' rotation to our "initial" rotation
    Vector3 unfixedUp = newRotation * Vector3.up;

    float angle = Vector3.Angle(Vector3.up, unfixedUp);
    Vector3 axis = Vector3.Cross(Vector3.up, unfixedUp);

    if (axis == Vector3.zero)
    {
        transform.rotation = Quaternion.AngleAxis(unfixedUp.y >= 0f ? 0f : 180f, Vector3.right);
    }
    else
    {
        transform.rotation = Quaternion.AngleAxis(angle, axis);
    }

    Vector3 platformAngles = transform.localRotation.eulerAngles;
    platformCoords.text = "Platform:" + "\n" +
                            "X: " + platformAngles.x + "\n" +
                            "Y: " + platformAngles.y + "\n" +
                            "Z: " + platformAngles.z;
}

它几乎像预期的那样工作:没有万向节锁(至少不是很容易发生的)。只有当你的手机在x或z上旋转180度左右,y轴被冻结,但初始/校准旋转轴仍然是一个大问题。这里有一个gif,希望它能比其他的更好地显示问题:https://www.nani-games.net/share/93eHK0Fz1t.gif

平台上方的轴线显示陀螺的旋转,并施加偏移量。

票数 0
EN

Stack Overflow用户

发布于 2020-12-31 21:10:18

评论中的解释:

代码语言:javascript
复制
// FIELDS
// device rotation from last frame
// init with DeviceRotation.Get() where appropriate
private Quaternion prevDeviceRotation; 

//...

// UPDATE LOGIC
// get the new device rotation
Quaternion newDeviceRotation = DeviceRotation.Get();

// Find difference between previous and current device rotation along previous axes
Quaternion relativeDelta = Quaternion.Inverse(prevDeviceRotation) * newDeviceRotation;

// Apply that difference to the transform's rotation to get an unfixed rotation 
// for the transform
Quaternion unfixedTransformRotation = transform.rotation * relativeDelta ;

// determine the unfixed up direction after that rotation is applied.
Vector3 unfixedUp = unfixedTransformRotation  * Vector3.up;

// find angle of up from world up
float angle = Vector3.Angle(Vector3.up, unfixedUp); 
Vector3 axis = Vector3.Cross(Vector3.up, unfixedUp); 

// if up is colinear with world up, use identity or flipped rotation
if (axis == Vector3.zero) 
{ 
    transform.rotation = Quaternion.AngleAxis(unfixedUp.y >= 0f ? 0f: 180f,
            Vector3.right); 
} 
else 
{ 
    transform.rotation = Quaternion.AngleAxis(angle, axis);
}

// update prevDeviceRotation
prevDeviceRotation = newDeviceRotation;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65510810

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档