2

Java 2D ゲームを作成しようとしていますが、一般的にはうまくいくようです。唯一の問題は、30 FPS で 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;
}
}

私がいつも遭遇する2つの問題:

1# 60FPS と 500FPS ではゲームの動作が異なります。

2# ゲームは 60FPS と 500FPS で同じように実行されますが、衝突が台無しになり、他のオブジェクトから 15 ピクセル以内に近づくことができません。次のようなものを実装する必要があると思います: 10px 近づけることができない場合は、10px 近づけますが、実装方法がわかりません。

どうすれば正しく実装できますか? それは大いに役立ちます!

4

1 に答える 1

2

最も簡単な方法は、一定の速度で一定の変位が必要な場合は、次のように 30 FPS のデルタに対してすべてのデルタをスケーリングできることを考慮することです。

ここに画像の説明を入力

したがって、60 FPS で実行しているが、30 FPS アルファと同じディスプレイスメントが必要な場合は、次のようになります。(1/30)/(1/60) = 2

だから削除vx = vx*delta; vy = vy*delta;

位置の更新を次のように変更します

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

これは大まかな解決策にすぎません。どのように機能するか教えてください。後で立ち寄り、より正確な解決策を更新します (レンダリングと計算に時間がかかるため、デルタが常に 1/FPS であるとは限らないことを考慮してください)。

編集:変数デルタは後で来るでしょう。しかし、いくつかの最適化:

  1. 衝突検出のために Y と X の両方で長方形を作成する必要はありません。交差する場合は、両方の軸で 2 つの長方形を描画してみてください。から長方形を作成し、vx + posx, vy+posyこれとの交差を確認するだけです。
  2. 上記により、衝突チェックが半分になるはずです。さらに最適化するにはQuadTree、実装を使用することを検討してください

  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
    

これにより、ターゲットから 1px 停止します。

于 2013-08-09T15:09:40.283 に答える