Java 当子弹出现在屏幕上时,libgdx播放器加速
我在libgdx中创建的一个游戏遇到了一个非常奇怪的问题。当我的玩家发射子弹时,他(毫不犹豫地)加速 起初,我认为这可能是因为我在创建子弹时,以某种方式传递了对玩家位置的引用,而不是创建一个新位置,但我一遍又一遍地扫描代码,我不认为这是导致它的原因 我相信这可能与delta计时的处理方式有关,因为在低规格设备上这种行为被夸大了: -在我的台式计算机上作为LWJGLAP应用程序运行时,问题要么不明显,要么根本没有发生 -在1.4Ghz的四核平板电脑上,这个问题是显而易见的,但尽管令人讨厌,但它并不影响游戏的工作流程 -在单芯1Ghz手机上,这个问题非常明显,以至于玩家通常会比屏幕上的子弹快很多(偶尔会从他不应该的矩形中掉下来) 我的GameScreen.render类如下所示:Java 当子弹出现在屏幕上时,libgdx播放器加速,java,android,libgdx,sprite,Java,Android,Libgdx,Sprite,我在libgdx中创建的一个游戏遇到了一个非常奇怪的问题。当我的玩家发射子弹时,他(毫不犹豫地)加速 起初,我认为这可能是因为我在创建子弹时,以某种方式传递了对玩家位置的引用,而不是创建一个新位置,但我一遍又一遍地扫描代码,我不认为这是导致它的原因 我相信这可能与delta计时的处理方式有关,因为在低规格设备上这种行为被夸大了: -在我的台式计算机上作为LWJGLAP应用程序运行时,问题要么不明显,要么根本没有发生 -在1.4Ghz的四核平板电脑上,这个问题是显而易见的,但尽管令人讨厌,但它并不
@Override
public void render(float delta)
{
if((!(this.isPaused)&&(!(this.renderInProgress))))
{
this.renderInProgress = true;
Gdx.gl.glClearColor(0.35f, 0.15f, 0.1f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
//update players with delta passed in
controllerPlayer.update(delta);
//update bullets with delta passed in
for(Bullet b:world.getLevel().getBullets())
{
b.getController().update(delta);
}
world.getLevel().updateObjectStateTimes(delta);
rendererWorld.render();
rendererOverlay.render();
this.renderInProgress = false;
}
}
// Processing the input - setting the states of Bob
processInput();
// If Bob is grounded then reset the state to IDLE
if (grounded && bob.getState().equals(State.JUMPING))
{
bob.setState(State.IDLE);
}
// Setting initial vertical acceleration
bob.getAcceleration().y = GRAVITY;
// Convert acceleration to frame time
bob.getAcceleration().mul(delta);
// apply acceleration to change velocity
bob.getVelocity().add(bob.getAcceleration().x, bob.getAcceleration().y);
// checking collisions with the surrounding blocks depending on Bob's velocity
checkCollisions(delta);
// apply damping to halt Bob nicely
bob.getVelocity().x *= DAMP;
// ensure terminal velocity is not exceeded
if (bob.getVelocity().x > MAX_VEL) {
bob.getVelocity().x = MAX_VEL;
}
if (bob.getVelocity().x < -MAX_VEL) {
bob.getVelocity().x = -MAX_VEL;
}
// simply updates the state time
bob.update(delta);
controllerPlayer如下所示:
@Override
public void render(float delta)
{
if((!(this.isPaused)&&(!(this.renderInProgress))))
{
this.renderInProgress = true;
Gdx.gl.glClearColor(0.35f, 0.15f, 0.1f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
//update players with delta passed in
controllerPlayer.update(delta);
//update bullets with delta passed in
for(Bullet b:world.getLevel().getBullets())
{
b.getController().update(delta);
}
world.getLevel().updateObjectStateTimes(delta);
rendererWorld.render();
rendererOverlay.render();
this.renderInProgress = false;
}
}
// Processing the input - setting the states of Bob
processInput();
// If Bob is grounded then reset the state to IDLE
if (grounded && bob.getState().equals(State.JUMPING))
{
bob.setState(State.IDLE);
}
// Setting initial vertical acceleration
bob.getAcceleration().y = GRAVITY;
// Convert acceleration to frame time
bob.getAcceleration().mul(delta);
// apply acceleration to change velocity
bob.getVelocity().add(bob.getAcceleration().x, bob.getAcceleration().y);
// checking collisions with the surrounding blocks depending on Bob's velocity
checkCollisions(delta);
// apply damping to halt Bob nicely
bob.getVelocity().x *= DAMP;
// ensure terminal velocity is not exceeded
if (bob.getVelocity().x > MAX_VEL) {
bob.getVelocity().x = MAX_VEL;
}
if (bob.getVelocity().x < -MAX_VEL) {
bob.getVelocity().x = -MAX_VEL;
}
// simply updates the state time
bob.update(delta);
这里是创建项目符号的地方:
this.fireReleased();
if(world.getLevel().getBullets().size() < Bob.MAX_BULLETS)
{
Bullet b = bullPool.obtain();
Rectangle bobRect = rectPool.obtain();
bobRect.set(bobRect.set(bob.getBounds().x, bob.getBounds().y, bob.getBounds().width, bob.getBounds().height));
Vector2 bobCent = new Vector2();
bobRect.getCenter(bobCent);
this.sndFire.play(0.4f);
if(bob.isFacingLeft())
{
b.set(bobCent, DIRECTION.LEFT, world);
world.getLevel().addBullet(b);
}
else
{
b.set(bobCent, DIRECTION.RIGHT, world);
world.getLevel().addBullet(b);
}
}
this.fireReleased();
if(world.getLevel().get子弹头().size()
根据要求,我上传了一个示例项目,其速度为0
从不动到右转
delta = 0.5;
bobv = (velocity=0 + (20 * delta)) * 0.9
bobpixels = 9 * delta
bulletv = 10 * delta
bulletpixels = bulletv
仍然在进行,现在我们达到了最大速度(15)
仍然向右行驶,已经达到最大速度,不能再快了
delta = 0.5;
bobv = (velocity=15 + (20 * delta)) * 0.9
bobpixels = 15 * delta
bulletv = 10 * delta
bulletpixels = bulletv
仍然正常,德尔塔下降
delta = 0.1;
bobv = (velocity=15 + (20 * delta)) * 0.9
bobpixels = 15 * delta
bulletv = 10 * delta
bulletpixels = bulletv
德尔塔仍在正常运行,下降幅度更大
delta = 0.01;
bobv = (velocity=15 + (20 * delta)) * 0.9
bobpixels = 13.68 * delta
bulletv = 10 * delta
bulletpixels = bulletv
所以,如果我找到了你所有的数学(像我说的那样集中这些东西),看起来你没事,除非增量足够小,以至于bob不能保持“15”的速度。在第一部分中,bob加速并达到子弹速度的1.5倍,但在最后,当delta下降时,比率看起来变成了1.368:1。问题是你如何试图加速鲍勃达到他的最高速度
解决这一切。先把你所有的bob velocity代码都撕下来。删除所有加速逻辑。让bob以固定的速度开始,并确保问题已解决。我建议定义一个全局基本速度,例如10米/秒。让bullet和bob达到这个速度,然后乘以他们的百分比。鲍勃是全球速度*1.5f,子弹是全球速度*1.0f
渲染时,将对象速度乘以增量,以计算自上一帧以来它们移动了多少像素。在您看到最大问题的设备上进行测试。一旦一切正常,添加加速代码。我们需要记录我们鲍勃在同一个方向上走了多久。您需要bob具备:
int direction = 0; // -1 for left, 0 for still, 1 for right
float timeInSameDirection = 0f;
final float timeToTopSpeed = 100f; //find the number that works for you
final topSpeed = Globals.topSpeed * 1.5f;
现在,当您更新bob时,您将执行以下操作:
if(currentDirection == direction) {
timeInSameDirection += delta;
} else {
timeInSameDirection = delta;
direction = currentDirection;
}
float speed = 0;
// are we moving
if(direction != 0) {
Interpolation interpolation = Interpolation.linear;
float accelRatio = timeInSameDirection/timeToTopSpeed;
accelRatio = accelRatio > 1 ? 1 : accelRatio;
float speed = interpolation.apply(0, topSpeed, accelRatio);
speed = direction == -1 ? -speed : speed;
}
很酷的一点是,你可以改变插值,你会得到一个完全不同的感觉,bobs加速度(顺便说一句,这有时被称为tweening)。只需再多做一点工作,您就可以通过跟踪TopSpeedCachedCurrentDirection和TimePents减速来增加减速
注意,鲍勃的最高速度是15。这是米每秒或其他一些游戏世界的速度。这与像素不同,因为每帧显示的增量与上一帧的增量不完全相同,我们需要将bob的世界速度转换为每帧像素。基本上
pixelsMoved=速度*数值常数*增量代码>将数值常数调整到所需的像素/米比率。因此,首先:您的代码非常混乱。您的BobController类(我认为它确实不需要与Bob分离,尽管这不是一个真正的问题,只是看起来毫无意义)做得太多了。我肯定会把两件事放在另一个类中,那就是输入和冲突检测。尽量避免在碰撞检测过程中更新Bob的位置,这样会使其变得杂乱无章,难以找到
很抱歉这么多人谈论这个问题,现在谈谈问题本身。注意你的子弹的速度是10,鲍勃的最大速度是15。这意味着他应该能够加速超越他们。但是为什么他不以每秒60帧的速度这样做呢
运动的一部分,它不依赖于delta
何时应为DAMP
。在60 FPS时,它将速度降低60倍;每秒20帧,仅20次。这意味着在高FPS时,MAX_VEL
根本无法达到。最终,鲍勃达到了一个速度,在这个速度下,他的每一帧加速度等于阻尼从他身上带走的速度。如果我们假设固定FPS为60,这意味着他每帧加速加速度*delta
=20*(1/60)=0.33。当这个加速度把他带到3.33的水平速度时,阻尼也带走了0.33-达到平衡。所以实际的最大速度是3,而不是15。在较低的FPS速率下,该值较高
因此,修复它的第一部分很简单-将MAX_VEL
更改为3
这是一个显著的改进,但是Bob在较低的帧速率下仍然要快一点。这是因为在施加加速度后,但在施加阻尼和最大水平之前,他的位置在checkCollisions()
中更新。
private static final float DAMP = 10f;
private static final float MAX_VEL = 3f;
(...)
public void update(float delta) {
(...)
// apply damping to halt Bob nicely
float decel = DAMP*delta;
if (Math.abs(bob.getVelocity().x) < decel) {
bob.getVelocity().x = 0;
} else {
bob.getVelocity().x -= decel*(bob.getVelocity().x < 0 ? -1 : 1);
}
(...)
// checking collisions with the surrounding blocks depending on Bob's velocity
checkCollisions(delta);
// simply updates the state time
bob.update(delta);
}