我正在制作一个团结的3D游戏,当Android设备在Z轴上移动/加速时,对象应该向前和向后移动。即。当玩家沿+ ve Z轴方向移动设备时,物体应向前移动,当玩家沿-ve Z轴方向移动设备时,物体应向后移动。
这款游戏是一款多人游戏,玩家将在大型足球场上移动。
我的想法是使用加速计来计算设备的加速度,然后整合加速度数据以获得Z轴上的设备速度。并使用速度移动设备。
使用此等式
V 2 = V 1 +ΔA。 ΔT
其中
V 2 :最终速度 V 1 :初始速度 ΔA:初始加速度和最终加速度之间的差异 ΔT:初始和最终时间之间的差异。
起初我尝试使用运动学方程来计算最终速度,但我意识到它只能在加速度不变时使用。因此,我的一位研究物理学的朋友将这个等式区分开来让我在加速变化时使用它。
我知道在计算精确位移时会出现一些错误,并且在加速度积分后误差会增加,但这个小百分比的误差对我的应用来说是可以的;我首先想到的是使用GPS而不是加速度计,但我发现GPS精度会低于传感器。
我也知道错误会在一段时间后非常高,所以我每隔10秒重置一次加速度和速度值。我也使用低通滤波器来降低传感器的噪音。
public class scriptMove : MonoBehaviour
{
const float kFilteringFactor = 0.1f;
public Vector3 A1;
public Vector3 A2;
public Vector3 A2ramping; // for the low-pass filter
public Vector3 V1;
public Vector3 V2;
public int SpeedFactor=1000; //this factor is for increasing acceleration to move in unity world
void resetAll()
{
Input.gyro.enabled = true;
A2 = Vector3.zero;
V1 = Vector3.zero;
V2 = Vector3.zero;
A2ramping = Vector3.zero;
}
// Use this for initialization
void Start()
{
InvokeRepeating("resetAll", 0, 10);
}
//http://stackoverflow.com/a/1736623
Vector3 ramping(Vector3 A)
{
A2ramping = A * kFilteringFactor + A2ramping * (1.0f - kFilteringFactor);
return A - A2ramping;
}
void getAcceleration(float deltaTime)
{
Input.gyro.enabled = true;
A1 = A2;
A2 = ramping(Input.gyro.userAcceleration) * SpeedFactor;
V2 = V1 + (A2 - A1) * deltaTime;
V1 = V2;
}
//Update is called once per frame
void Update()
{
getAcceleration(Time.deltaTime);
float distance = -1f;
Vector3 newPos = transform.position;
transform.Translate(Vector3.forward * Time.deltaTime * V2.z * distance);
}
}
当我移动设备时,我的代码无法按预期工作;
答案 0 :(得分:0)
此动作基于加速度,因此取决于您旋转设备的速度。这也是为什么当你这样做时物体不会停止的原因。突然停止你的设备是一个很大的加速度,然后加到对象翻译的数量,这导致它移动的距离远远超过你想要的距离。
我认为对你来说更容易的是使用陀螺仪的姿态而不是userAcceleration。态度返回设备旋转的四元数。 https://docs.unity3d.com/ScriptReference/Gyroscope-attitude.html
(你必须做一些实验,因为我不知道态度是什么(0,0,0,0)。这可能意味着设备在桌子上是平的,或者它是侧面被放在你面前,或者它可能只是应用程序刚开始时设备的方向,我不知道Unity如何初始化它。)
一旦你有了Quaternion,你应该可以根据用户旋转设备的任何方向直接调整速度。因此,如果它们旋转+ ve Z轴,你向前移动,如果它们移动得更多,它移动得更快,如果它们移动-ve Z轴,它会减速或向后移动。
关于GPS坐标,您需要使用LocationService。 http://docs.unity3d.com/ScriptReference/LocationService.html 您需要启动LocationServices,等待它们初始化(这一点很重要),然后您可以使用LocationService.lastData查询不同的部分
答案 1 :(得分:0)
我正在尝试和你做同样的事情。使用一个传感器获得设备的线性加速并非易事。您需要使用加速度计和陀螺仪(传感器融合)实施解决方案。谷歌有一个特定于Android的解决方案,根据您的设备的复杂程度而有所不同。它使用多个传感器以及低通/高通滤波器(参见Android TYPE_LINEAR_ACCELERATION sensor - what does it show?)。 谷歌的Tango平板电脑应该有传感器来解决这些问题。
如果您想在Unity中获取加速计数据,请尝试:
public class scriptMove : MonoBehaviour{
private float accelX;
private float accelY;
private float accelZ;
void Update(){
accelX = Input.acceleration.x;
accelY = Input.acceleration.y;
accelZ = Input.acceleration.z;
//pass values to your UI
}
}
我目前正在尝试使用IKVM将Google的解决方案移植到Unity。
此链接也可能有用: Unity3D - Get smooth speed and acceleration with GPS data
答案 2 :(得分:0)
我不知道你是否仍然需要它,但如果将来有人需要我会发布我发现的内容:
当我第一次使用Unity加速度计时,我认为输出只是设备的旋转,在某种程度上是,但不仅仅是它给了我们加速度,但是为了让这个值成为必须过滤重力然后你有值。
我为Android创建了一个插件,并获得了Android的加速度计和线性加速度计,标准的加速度计为我们提供了类似的Unity加速度计值,主要的区别在于它是原始的,而且统一给我们一些精确的输出,例如,如果您的游戏是横向统一,则会自动反转X和Y轴,而Android原始信息则不会。而线性加速度计是包括标准加速度计在内的传感器的融合,输出是没有重力的加速但速度很差,而两个(Unity和Android)加速度计每帧都更新,线性加速度计每4到5更新一次确定了用户体验的可怕速度。
但是对于Android插件来说非常棒,因为它提供了如何解决我从Unity Accelerometer中移除重力的问题,你可以在这里找到: https://developer.android.com/reference/android/hardware/SensorEvent.html 在Sensor.TYPE_ACCELEROMETER下
如果我们倾斜设备,Unity Accelerometer会为您提供一个值,例如6,当您保持在该位置时,这是值,不是波浪,如果您向后倾斜非常快或非常慢,它会给出从6到0的值(假设你回到零),我想要和我在下面分享的代码完成的是,当你把它变成波浪时,返回加速度并返回到零,所以是加速减速曲线,如果你把它转得很慢,返回的加速度几乎为零,如果你把它快速转动,响应反映了这个速度。如果这是你要找的结果,你只需要创建这个类:
using UnityEngine;
public class AccelerometerUtil
{
public float alpha = 0.8f;
public float[] gravity = new float[3];
public AccelerometerUtil()
{
Debug.Log("AccelerometerUtil Init");
Vector3 currentAcc = Input.acceleration;
gravity[0] = currentAcc.x;
gravity[1] = currentAcc.y;
gravity[2] = currentAcc.z;
}
public Vector3 LowPassFiltered()
{
/*
https://developer.android.com/reference/android/hardware/SensorEvent.html
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
linear_acceleration[0] = event.values[0] - gravity[0];
linear_acceleration[1] = event.values[1] - gravity[1];
linear_acceleration[2] = event.values[2] - gravity[2];
*/
Vector3 currentAcc = Input.acceleration;
gravity[0] = alpha * gravity[0] + (1 - alpha) * currentAcc.x;
gravity[1] = alpha * gravity[1] + (1 - alpha) * currentAcc.y;
gravity[2] = alpha * gravity[2] + (1 - alpha) * currentAcc.z;
Vector3 linearAcceleration =
new Vector3(currentAcc.x - gravity[0],
currentAcc.y - gravity[1],
currentAcc.z - gravity[2]);
return linearAcceleration;
}
}
有了这门课,只需在MonoBehaviour中创建它:
using UnityEngine;
public class PendulumAccelerometer : MonoBehaviour
{
private AccelerometerUtil accelerometerUtil;
// Use this for initialization
void Start()
{
accelerometerUtil = new AccelerometerUtil();
}
// Update is called once per frame
void Update()
{
Vector3 currentInput = accelerometerUtil.LowPassFiltered();
//TODO: Create your logic with currentInput (Linear Acceleration)
}
}
请注意,MonoBehaviour上的TODO将被实现,由你创建一个如何处理这个值的算法,在我的情况下,我发现创建一个Graphic输出并在编写之前分析我的加速度非常有用。
真的希望有所帮助