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

Java 2d游戏-增量时间和碰撞问题,java,collision,2d-games,timedelta,Java,Collision,2d Games,Timedelta,我正在尝试制作一个Java2D游戏,总体来说效果不错。唯一的问题是,我不知道如何放置我的“delta”时间,以使移动速度与1000 FPS相同 这是我的实体类代码: import java.awt.Rectangle; import map.Tile; import graphics.Sprite; public class Entity { private String name; private float positionx, positiony; // Current coordin

我正在尝试制作一个Java2D游戏,总体来说效果不错。唯一的问题是,我不知道如何放置我的“delta”时间,以使移动速度与1000 FPS相同

这是我的实体类代码:

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;
}
}
导入java.awt.Rectangle;
导入地图.Tile;
导入图形。精灵;
公共类实体{
私有字符串名称;
专用浮点位置X,位置Y;//当前坐标
private int targetx,targety;//目标坐标
专用双vx,vy;//当前向量
私有双lx,ly;//最后一个向量
私人浮动速度;
私人雪碧;
公共实体(字符串名称、整数x、整数y、精灵){
this.name=名称;
这个速度=1f;
这个位置x=x;
这个位置y=y;
this.sprite=精灵;
main.main.e.addEntity(this);//这种调用很难看,应该修复。
}
公共空间删除(){
main.main.e.移动实体(this);
sprite.remove();
}
公共无效设置向量(双vx,双vy){
这是vx=vx;
this.vy=vy;
}
公共无效更新(长增量){
//“倍增”修改器使其在30 fps和1000 fps上的动作相同。
vx=vx*δ;
vy=vy*delta;
//计算向量
双距离=数学sqrt((vx*vx)+(vy*vy));
如果(距离>0){//我们达到目标了吗?
vx=((vx/距离));
vy=((vy/距离));
}否则{
vx=0;
vy=0;
}
//检查与对象的碰撞:
矩形rx=新矩形((int)(vx+positionx),(int)positiony,32,32);
矩形ry=新矩形((int)位置x,(int)(vy+positiony),32,32);
for(实体e:main.main.e.getEntities()){
如果(此!=e){
如果(isIntersecting(rx,e.getBounds())){
vx=0;//不允许x方向。
}
if(isIntersecting(ry,e.getBounds())){
vy=0;//不允许y方向。
}
}
}
//检查瓷砖:
用于(瓷砖t:main.main.m.getNeights(位置X,位置Y)){
if(t.isBlocking()){
if(isIntersecting(rx,t.getBounds())){
vx=0;
}
if(isIntersecting(ry,t.getBounds())){
vy=0;
}
}
}
//更新职位:
位置X+=vx*速度;
位置Y+=vy*速度;
//制作动画:
制作动画(vx、vy);
}
公共布尔isIntersecting(矩形r1,矩形r2){
返回r1。相交(r2);
}
公共矩形getBounds(){
返回新矩形((int)位置x,(int)位置y,32,32);
}
公共void setMoveTo(整数x,整数y){
this.targetx=x;
this.targety=y;
}
//此功能由机器人使用,而不是在玩家身上(他们正在设置向量并直接使用更新):
公共空间移动到(长三角洲){
设置向量((targetx位置x),(targety位置y));
更新(增量);
}
公共空间动画(双dx,双dy){
设置位置((内部)位置X,(内部)位置Y);
如果(dx>0){
设置动画(0,7100);//向右走。
}else if(dx<0){
设置动画(1,7100);//向左走。
}否则{
如果(lx>0){
设置动画(2,3200);//站在右边。
}else if(lx<0){
setAnimation(3,3200);//站在左边。
}
}
lx=dx;
ly=dy;
}
}
我经常遇到的两个问题:

1#游戏以60帧/秒的速度运行与以500帧/秒的速度运行不同

2#游戏以60帧/秒的速度运行,与500帧/秒的速度运行,但我的碰撞出错,并且我无法移动到距离另一个对象15像素的距离。我想我需要实现一些类似的东西:如果我不能让10px更接近,那么把它移近10px,但我不知道如何实现它


我如何正确地实施它?那会很有帮助的

因此,如果您以60 FPS的速度运行,但需要与30 FPS相同的位移,则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将稍后提供。但有一些优化:

  • 对于碰撞检测,您不需要同时在Y和X上构造矩形,可以尝试绘制两个矩形,如果它们在两个轴上相交,则在两个轴上都这样做。只需从vx+posx,vy+posy创建一个矩形
  • ,并检查与此相交
  • 以上应该是碰撞检查的一半。对于进一步的优化,考虑使用<代码>四叉树< /代码>可以找到一个实现。

  • 针对“块状”碰撞测试的问题(即停止块对象的X像素)。您可以在伪代码中执行以下操作:

     if(new position will make this colide)
       while(this.position is more than one pixel away from blocking object)
         keep moving one pixel
    

  • 这将使您从目标停止1px。

    我们需要知道如何获得长增量,是1/FPS吗?长增量是渲染最后一帧所需的时间。60FPS,delta为16.6,100FPS,delta为10。其想法是FPS越低,delta越高,实体移动的次数越多,反之亦然。这应该进行调整,使30FPS计算机和500FPS计算机的移动速度相同(当然它会滞后于30FPS)。实际上,它似乎在10FPS和1000FPS中以相同的速度运行,这很好!关于碰撞的问题仍然存在,尽管这可能是碰撞本身的问题:撞到墙上,撞到墙上时停止,但不知何故y轴也会锁定(只是有时!),并且您被卡住的唯一选项是返回,而不是向上或向下。我的理论是,由于delta,它允许一个单独的帧