我正在开发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
两次以进行旋转和平移。平移具有在最后一个setValues
中最后一次调用Timeline
时设置的值,但是直到旋转(返回0)经过其补间为止。getValues
的4个调用可能是某些东西。我不确定在我的设置中什么会导致Timeline
会在补间开始之前获取转换的值,如果它们应按在Timeline
中的顺序执行的话。我也不确定为什么每个补间调用getValues
两次,但是在补间过程中Tween引擎会两次调用它并不是不可行的。我很确定我使用的LibGDX的平移/旋转功能很好,它们“粘”在模型上,并且我使用的翻译与非Tween-Engine版本相同。旋转相似,但功能不同。
不过,在第二次转换期间要更改的Y值值得研究。
最佳答案
因此,该解决方案与Universal Tween Engine或实现方式无关。只是我对LibGDX中的矩阵转换功能的了解不多。对setToRotation
的调用将重置变换矩阵,然后仅应用旋转,从而将先前平移归零。 setToTranslation
相同,导致旋转丢失。
对于翻译,我改用setTranslation
,并且旋转不会丢失。我认为没有类似的旋转功能(使用rotate
会引起各种问题),所以我得到一个新的Vector3
,其中存储了模型的位置,然后应用setToRotation
,然后设置平移到新向量。这是TweenAccessor
中的更新代码:
public void setValues(DynamicModel target, int tweenType, float[] newValues) {
trans = target.model.transform.getTranslation(trans);
switch (tweenType) {
...
case POSITION_XYZ:
target.model.transform.setTranslation(newValues[0], newValues[1], newValues[2]);
break;
case ROTATION:
// store the position
Vector3 position = target.model.transform.getTranslation(new Vector3());
// then set the rotation and reset the translation
target.model.transform.setToRotation(Vector3.Y, newValues[0]).setTranslation(position);
break;
default:
assert false;
break;
}
}
关于java - 通用补间引擎/LibGDX:模型会按顺序丢失补间之间的变换和旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27770920/