【发布时间】:2015-03-02 11:35:00
【问题描述】:
我正在开发一款 3D 游戏并尝试正确设置角色移动。交互很简单,屏幕上只有一个模型,用户点击屏幕上的一个点,模型旋转面对点击的点(现在模型是一个带眼睛的小鬼,所以眼睛转向面对点击的点)点),一旦面对该点,模型就会移动到那里。
我使用自己编写的一些代码进行了此操作,但动画并不流畅,模型经常会超出/低于目标位置,然后会向后或向前猛拉到位。我之前只在 2d 动画上使用过 Universal Tween 引擎,但决定试一试。它解决了抖动问题,并且旋转和变换都可以单独工作,但我无法让它们按顺序一起工作。
如果我只启用旋转模型的代码,它可以正常工作(嗯,几乎没问题,在某些角度确定顺时针或逆时针旋转时会有些奇怪,但这是稍后的另一个问题):我点击一个位置时,模型会旋转以面对它并保留新的旋转直到下一次单击,然后它会转向面对该位置。与仅启用翻译相同:我单击一个点,模型移动到它并保留它的新翻译,直到我再次单击,然后它移动到那个位置,等等。
当翻译和旋转都启用时,我遇到了问题。模型将首先旋转以面对点击的点,然后回到它的初始旋转,然后移动到点击的点。在随后的单击中,模型将首先返回其初始平移,然后旋转以面向单击点(实际上是单击点相对于重新初始化位置的位置),然后移动到单击点。
我尝试重新排列代码,使用回调,将新的平移和旋转缓存到游戏模型类的成员,然后在开始补间之前使用 set() 及其值,但没有任何效果。
这是我TweenAccessor的相关代码:
public class GameModelTweenAccessor implements TweenAccessor<DynamicModel> {
public int getValues(DynamicModel target, int tweenType, float[] returnValues) {
trans = target.model.transform.getTranslation(trans);
switch (tweenType) {
...
case POSITION_XYZ:
returnValues[0] = trans.x;
returnValues[1] = trans.y;
returnValues[2] = trans.z;
return 3;
case ROTATION:
axisVec = new Vector3();
angle = target.model.transform.getRotation(new Quaternion()).getAxisAngle(axisVec) * axisVec.nor().y;
returnValues[0] = angle;
return 1;
...
}
}
public void setValues(DynamicModel target, int tweenType, float[] newValues) {
trans = target.model.transform.getTranslation(trans);
switch (tweenType) {
...
case POSITION_XYZ:
target.model.transform.setToTranslation(newValues[0], newValues[1], newValues[2]);
break;
case ROTATION:
target.model.transform.setToRotation(Vector3.Y, newValues[0]);
break;
...
}
}
}
这是启动时间线和补间的代码(在this file):
Timeline.createSequence()
.push(Tween.to(screen.ghost, GameModelTweenAccessor.ROTATION, Math.abs(angle - newRotation) / 200)
.target(newRotation)
.ease(TweenEquations.easeNone))
.push(Tween.to(screen.ghost, GameModelTweenAccessor.POSITION_XYZ, duration).
target(intersection.x, intersection.y, intersection.z)
.ease(TweenEquations.easeNone))
.start(screen.ghostManager);
谁能指出我的解决方案?
编辑:
似乎每个补间完成后设置的转换在另一个补间完成后重置为 0。这些是来自getValues 和setValues 函数的这些值的日志TweenAccessor:
Get Rot: 0.0
Get Trans: x: 0.0 y: 0.0 z: 0.0
Get Rot: 0.0
Get Trans: x: 0.0 y: 0.0 z: 0.0
Get Rot: 0.0
Set Rot: 9.598349
Set Rot: 9.814415
Set Rot: 10.052449
...
Set Rot: 39.99417
Set Rot: 43.397423
Set Rot: 46.62333
Get Trans: x: 0.0 y: 0.0 z: 0.0
Set Trans: x: 0.0012489144 y: 0.0 z: 0.001180494
Set Trans: x: 0.024489587 y: 0.0 z: 0.023147952
Set Trans: x: 0.04921494 y: 0.0 z: 0.04651875
...
Set Trans: x: 6.4197707 y: 0.0 z: 6.06807
Set Trans: x: 6.444479 y: 0.0 z: 6.091425
Set Trans: x: 6.453598 y: 0.0 z: 6.1000443
Get Rot: 0.0
Get Trans: x: 6.453598 y: 0.0 z: 6.1000443
Get Rot: 0.0
Get Trans: x: 6.453598 y: 0.0 z: 6.1000443
Get Rot: 0.0
Set Rot: 3.4318955
Set Rot: 6.795984
Set Rot: 10.0074415
...
Set Rot: 156.79567
Set Rot: 159.99591
Set Rot: 162.38742
Get Trans: x: 0.0 y: 0.0 z: 0.0
Set Trans: x: 0.03550978 y: 3.836017E-8 z: 0.021066409
Set Trans: x: 0.15527377 y: 1.6773768E-7 z: 0.092117175
...
Set Trans: x: 6.848614 y: 7.3983565E-6 z: 4.062985
Set Trans: x: 6.961268 y: 7.5200533E-6 z: 4.129818
Set Trans: x: 7.0624847 y: 7.6293945E-6 z: 4.189865
Get Rot: 0.0
Get Trans: x: 7.0624847 y: 7.6293945E-6 z: 4.189865
Get Rot: 0.0
Get Trans: x: 7.0624847 y: 7.6293945E-6 z: 4.189865
Get Rot: 0.0
Set Rot: -3.2620814
Set Rot: -6.8205137
Set Rot: -9.834579
...
Set Rot: -76.57533
Set Rot: -79.91388
Set Rot: -80.610855
Get Trans: x: 0.0 y: 0.0 z: 0.0
Set Trans: x: 0.01940876 y: 0.0 z: 0.033669088
Set Trans: x: 0.04174851 y: 0.0 z: 0.07242267
Set Trans: x: 0.06332677 y: 0.0 z: 0.109855264
...
Set Trans: x: 2.7853239 y: 0.0 z: 4.8318033
Set Trans: x: 2.808029 y: 0.0 z: 4.8711905
Set Trans: x: 2.827034 y: 0.0 z: 4.9041595
getValues 在补间开始之前会为每种类型的补间(平移和旋转)调用两次。在这一点上,翻译的值仍然是它们在最后一个翻译补间结束时设置的值。不过,旋转的值已设置回 0(我猜是因为下一轮调用 setValues 进行旋转)。
setValues 然后被调用几次进行旋转,直到它到达目标旋转。这(除了重置旋转)按我的期望和希望工作。在getRotation 调用之后,转换被设置回0,0,0,但不是通过调用setValues(没有它的日志)。然后通过多个setValues 调用将翻译动画到目标。
在此之后,再次单击会重新启动循环,并再次调用 getValues 两次以进行旋转和平移。 Translation 具有在最后一次调用 setValues 时在最后一次 Timeline 中设置的值,但仅在旋转(返回 0)通过其补间之前。
对getValues 的 4 次调用可能是什么。我不确定我的设置中的什么会导致Timeline 会在其补间开始之前获取翻译的值,如果它们应该在它们被推入Timeline 时按顺序运行。我也不确定为什么 getValues 会为每个补间调用两次,但补间引擎在补间过程中调用它两次并非不可行。
我很确定我正在使用的来自 LibGDX 的翻译/旋转功能很好,它们“粘”在模型上,我使用与非 Tween-Engine 版本相同的翻译。旋转类似,但功能不一样。
不过,在第二次翻译期间不断变化的 Y 值是值得研究的。
【问题讨论】:
-
需要注意的一点是,您的代码可能会在游戏循环中某处的补间引擎之外自行修改这些属性。好像就是这么回事。
-
谢谢,我一直在查看我的旧代码以删除任何其他改变位置和旋转的东西。我想我已经掌握了一切,但再看一眼也无妨。
-
这是通过 getter 和 setter 改变值的一种情况。很容易设置断点或 sysout(就像您在上面所做的那样)并监视 getter 或 setter 中属性的所有更改。如果您使用没有 getter 和 setter 的公共变量,您将无法轻易看到这些值何时发生变化。也许有一种方法可以用调试器做到这一点,但我不熟悉。我想您可以尝试将属性设置为私有,然后您的 IDE 应该将您指向您设置它的所有位置,而无需使用 getter/setter。
标签: java libgdx tween translate-animation rotateanimation