当子弹在屏幕上时,libgdx播放器加速

时间:2014-03-13 13:56:20

标签: java android libgdx sprite

我正在使用libgdx创建的游戏遇到一个非常奇怪的问题。当我的玩家发射子弹时,他(不必要地)加速了。

起初我认为可能是因为我在创建子弹时不知何故传递了玩家的位置,而不是创建一个新位置,但我已经反复扫描了代码。我并不认为这是导致它的原因。

我认为处理delta计时的方式可能 ,因为这种行为在较低规格的设备上被夸大了:

- 在我的台式计算机上作为LwjglApplication运行,问题要么不明显,要么根本不会发生 - 在四核1.4Ghz平板电脑上,问题是显而易见的,虽然令人讨厌,但它并没有影响游戏的工作流程 - 在一个单核的1Ghz手机上,问题非常明显,以至于玩家通常最终会比屏幕上的子弹快得多(并且偶尔会通过矩形掉落他不应该这样)

我的GameScreen.render类看起来像这样:

@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;
    }
 }

controllerPlayer看起来像这样:

    // 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);

Bullet.getController.Update():

    public void update(float delta) 
    {
        checkCollisions(delta); 

        // TODO Auto-generated method stub
        if(Bullet.this.direction==DIRECTION.RIGHT)
            Bullet.this.position.add(10*delta,0f);
        else
            Bullet.this.position.add(0-(10*delta),0f);

        Bullet.this.bounds.setX(Bullet.this.position.x);
        Bullet.this.bounds.setY(Bullet.this.position.y); //not needed?
    }

以下是创建子弹的地方:

        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);
            }
        }

根据要求,我已在https://dl.dropboxusercontent.com/u/318066/star-assault.zip

上传了一个示例项目

2 个答案:

答案 0 :(得分:1)

所以,首先关闭:你的代码非常混乱。你的BobController课程(我认为真的不需要与Bob分开,虽然这不是真正的问题,但似乎毫无意义)正在做太多。我确定在不同类中的两件事是输入和碰撞检测。并且尽量避免在碰撞检测期间更新Bob的位置,这会使其无组织且难以找到。

很抱歉这么多关于它的讨论,现在问题本身。注意你的子弹的速度是10,鲍勃的最大速度是15.这意味着他应该能够加速经过它们。但那他为什么不以60 FPS这样做呢?

运动中不应依赖delta的运动部分应为DAMP。在60 FPS时,速度降低60倍;在20 FPS,只有20次。这意味着在高FPS时,永远无法达到MAX_VEL。最终鲍勃达到了一个速度,他的每一帧的加速度等于速度阻尼带走了他。如果我们假设固定FPS为60,这意味着他每帧加速ACCELERATION * delta = 20 *(1/60)= 0.33。当这种加速度使他达到3.33的水平速度时,阻尼也会消失0.33 - 达到平衡。因此实际最大速度为3,而不是15.在较低的FPS速率下,此值更高。

所以修复它的第一部分很简单 - 将MAX_VEL更改为3.

这是一项重大改进,但Bob在较低的帧速率下仍然有点快。这是因为他的位置在应用加速后checkCollisions()更新,但在应用DAMPMAX_VEL之前。因此,如果鲍勃的最大速度为3,那么他的实际速度会有所增加,这取决于他每帧加速的程度。

第二次修复 - 将checkCollisions()放到BobController.update()的末尾(或至少在应用MAX_VEL后)。

之后,所有帧速率的最大速度都是相同的,但阻尼仍然取决于帧率 - 他在高帧率上停止得更快。通过将其改为适当的减速度,这更容易解决 - 我们每秒将鲍勃的速度降低固定量 - 例如这是我们给出的值DAMP。为了应用它,我们将Bob的速度的绝对值减少DAMP * delta,或者如果它小于该值,则将其设置为0。这是第三次修复

代码中的所有更改:

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);
}

答案 1 :(得分:0)

之前的速度= 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=9 + (20 * delta)) * 0.9
bobpixels = 15 * delta
bulletv = 10 * delta
bulletpixels = bulletv

仍然是正确的,已经处于最大速度,不能更快。

delta = 0.5;
bobv = (velocity=15 + (20 * delta)) * 0.9
bobpixels = 15 * delta
bulletv = 10 * delta
bulletpixels = bulletv

仍然正确,delta下降。

delta = 0.1;
bobv = (velocity=15 + (20 * delta)) * 0.9
bobpixels = 15 * delta
bulletv = 10 * delta
bulletpixels = bulletv

仍然正确,delta下降更多。

delta = 0.01;
bobv = (velocity=15 + (20 * delta)) * 0.9
bobpixels = 13.68  * delta
bulletv = 10 * delta
bulletpixels = bulletv

所以,如果我找到你所有的数学运算(像我说的那样集中这些东西),看起来你没事,除非三角洲变得足够小以至于bob没有保持&#34; 15&#34;的速度。在第一部分中,bob加速并达到子弹速度的1.5倍,但在结束时,当delta下降时,看起来比率变为1.368比1.问题是你如何尝试将bob加速到他的最高速度。 / p>

解决所有这些问题。首先撕掉你所有的鲍勃速度代码。删除所有加速逻辑。让bob以固定的速度开始,并确保问题消失。我建议定义全球基本速度,例如每秒10米。让子弹和鲍勃获得那个速度并按它们的百分比加倍。 Bob是globalSpeed * 1.5f,bullet是globalSpeed * 1.0f;

当您渲染多个对象时,可以通过增量来计算自上一帧以来它们移动了多少像素。在设备上测试你看到的最大问题。一旦完成所有工作,请添加加速代码。我们需要跟踪我们鲍勃向同一方向走多长时间。你需要鲍勃才能拥有:

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;
}

关于这个问题的一个很酷的事情是你可以改变插值并且你可以获得完全不同的加速度(btw这有时被称为补间)。只需要做更多的工作就可以通过跟踪topSpeedReachedInCurrentDirection和timeSpentDecelerating来增加减速度。

请注意,鲍勃的最高速度是15.这是每秒米或其他游戏世界的速度。这与像素不同,并且由于每个帧都没有显示与最后一个完全相同的增量,我们需要将bob的世界速度转换为每帧的像素。基本上pixelsMoved = speed * NUMERIC_CONST * delta;将NUMERIC_CONST调整为所需的像素与米的比率。