Java 2d游戏 - 增量时间和碰撞的问题

时间:2013-08-09 13:33:24

标签: java collision 2d-games timedelta

我正在尝试制作一个java 2d游戏,而且它似乎总体上运作良好。唯一的问题是,我无法弄清楚如何设置我的“三角洲”时间,以使动作在30 FPS和1000 FPS上移动相同。

这是我的Entity类的代码:

import java.awt.Rectangle;

import map.Tile;
import graphics.Sprite;

public class Entity {
private String name;
private float positionx, positiony; // Current coordinate
private int targetx,targety; // Target coordinate
private double vx, vy; // Current vector
private double lx, ly; // Last vector

private float speed;
private Sprite sprite;

public Entity(String name, int x, int y, Sprite sprite){
    this.name = name;
    this.speed = 1f;

    this.positionx = x;
    this.positiony = y;

    this.sprite = sprite;

    main.Main.e.addEntity(this); // These kind of calls are ugly, and should be fixed.
}

public void remove(){
    main.Main.e.removeEntity(this);
    sprite.remove();
}

public void setVector(double vx, double vy){
    this.vx = vx;
    this.vy = vy;
}

public void update(long delta){
    //Multiply modifier to make it act the same on 30 fps as 1000 fps.
    vx = vx*delta;
    vy = vy*delta;

    // Calculate vector
    double distance = Math.sqrt((vx * vx) + (vy * vy));

    if(distance > 0){ // Have we reached the target yet?
        vx = ((vx / distance));
        vy = ((vy / distance));
    }else{
        vx = 0;
        vy = 0;
    }

    //Check collision with objects:
    Rectangle rx = new Rectangle((int) (vx+positionx), (int)positiony, 32, 32);
    Rectangle ry = new Rectangle((int) positionx, (int)(vy+positiony), 32, 32);

    for(Entity e : main.Main.e.getEntities()){
        if(this != e){
            if(isIntersecting(rx, e.getBounds())){
                vx = 0; // Disallow x direction.
            }
            if(isIntersecting(ry, e.getBounds())){
                vy = 0; // Disallow y direction.
            }
        }
    }

    //Check tiles:
    for(Tile t : main.Main.m.getNeighbours(positionx,positiony)){
        if(t.isBlocking()){
            if(isIntersecting(rx, t.getBounds())){
                vx = 0;
            }
            if(isIntersecting(ry, t.getBounds())){
                vy = 0;
            }
        }
    }

    //Update the position:
    positionx += vx*speed;
    positiony += vy*speed;

    //Animate:
    animate(vx, vy);
}

public boolean isIntersecting(Rectangle r1, Rectangle r2){
    return r1.intersects(r2);
}

public Rectangle getBounds(){
    return new Rectangle((int) positionx,(int) positiony,32,32);
}

public void setMoveTo(int x, int y){
    this.targetx = x;
    this.targety = y;
}

//This function is used by the bots, and not on players (they are setting the vector and use update directly):
public void moveTo(long delta){
    setVector((targetx-positionx),(targety-positiony));
    update(delta);
}

public void animate(double dx, double dy){
    sprite.setPosition((int)positionx, (int)positiony);

    if(dx > 0){
        sprite.setAnimation(0, 7, 100); // Walk right.
    }else if(dx < 0){
        sprite.setAnimation(1, 7, 100); // Walk left.
    }else{
        if(lx > 0){
            sprite.setAnimation(2, 3, 200); // Stand right.
        }else if(lx < 0){
            sprite.setAnimation(3, 3, 200); // Stand left.
        }
    }

    lx = dx;
    ly = dy;
}
}

我经常遇到的两个问题:

1#游戏在60FPS上的运行方式与500FPS不同。

2#游戏在60FPS和500FPS上运行相同,但我的碰撞搞砸了,我距离另一个物体的距离不能超过15px。我想我需要实现类似的东西:如果我不能将10px拉近,那么将其移近10px,但我不知道如何实现它。

如何正确实施?这会有很大的帮助!

1 个答案:

答案 0 :(得分:2)

最简单的方法是考虑如果你想要一个恒定速度的恒定位移,你可以相对于30 FPS的增量来缩放所有增量,如下所示:

enter image description here

因此,如果您以60 FPS运行,但想要与30FPS alpha相同的位移,那么(1/30)/(1/60) = 2

所以 删除vx = vx*delta; vy = vy*delta;

并将您的位置更新更改为

alpha = (1.0/30)*delta;
positionx += alpha*vx*speed;
positiony += alpha*vy*speed;

这只是一个粗略的解决方案,让我知道它是如何工作的,我将稍后介绍并更新以获得更正确的解决方案(考虑到由于渲染和计算花费一些时间,delta并不总是1 / FPS)

编辑:变量delta将在稍后出现。但有些优化:

  1. 您不需要在Y和X中构造一个矩形用于碰撞检测,尝试绘制两个矩形,如果它们相交,则它们在两个轴上都这样做。只需从vx + posx, vy+posy创建一个矩形,然后检查是否与此相交。
  2. 以上应该是碰撞检查的一半。要进一步优化,请考虑使用QuadTree可以找到here的实现。

  3. 针对“块状”碰撞测试的问题(从阻塞对象中停止X像素)。您可以使用伪代码执行以下操作:

     if(new position will make this colide)
       while(this.position is more than one pixel away from blocking object)
         keep moving one pixel
    
  4. 这会让你从目标停止1px。