Question

I'm trying to make a java 2d game, and it seems to work out fine in general. The only problem is, that I can't figure out how to place my "delta" time, to make the movements move the same on 30 FPS as on 1000 FPS.

This is my code for the Entity class:

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

The two problems, that I always run into:

1# The game runs differently on 60FPS than on 500FPS.

2# The game runs the same on 60FPS as 500FPS, but my collision screws up, and I can't move closer than 15px from the other object. I think I need to implement something like: If I can't get 10px closer, then move it 10px closer, but I don't know how to implement it.

How can I implement it correctly? That would help a lot!

Was it helpful?

Solution

The easiest way would be to consider that if you want a constant displacement with a constant velocity you can scale all the deltas relative to the delta of 30 FPS like so:

enter image description here

So if you run at 60 FPS but want the same displacement as on 30FPS alpha would be (1/30)/(1/60) = 2

So Remove vx = vx*delta; vy = vy*delta;

and change your position update to

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

This is only a crude solution, let me know how it works, I will drop in later and update for a more correct solution (taking into account that delta is not always 1/FPS due to rendering and computation taking some time).

Edit: Variable delta will come later. But some optimizations:

  1. You don't need to construct a rectangle in both Y and X for collisiondetection, try drawing two rectangles, if they intersect they do so on both axis. Just create a rectangle from vx + posx, vy+posy and check for intersection with this.
  2. The above should half your collisionchecks. For further optimization consider using a QuadTree an implementation can be found here.

  3. For the problem of "blocky" collision testing (where you stop X pixels from the blocking object). You can do the following, in pseudocode:

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

This will make you stop 1px from the target.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top