Skip to content

Game logic

Heiko Brumme edited this page Dec 31, 2018 · 2 revisions

By now we know how to render the game and how to handle input, but what about updating the game? In this tutorial we will take a look at game logic.

Updating Entity Position

By now you should already know that the delta time is, it is the elapsed time between two loops. You need it for updating an entity according to the elapsed time.

For updating the position you need a bit of physics. One of the fundamental equations of physics is that the force is the mass multiplied by acceleration (F = m*a). By rearranging the this equation you will see that acceleration is force divided by mass (a = F/m). The acceleration can also be described as the rate of change in velocity over time, so mathematically a = dv/dt, where dt is our delta time. Now we just have to define velocity, this is the rate of change in position over time: v = dx/dt.

Euler integration

Now with these definitions we can update position and velocity of an entity. The delta time is obvious and the velocity can get calculated by using a speed variable. This variable tells what distance the object is moving per second. We also need the direction for that movement which should be a normalized vector. Now we can calculate the velocity like in following pseudo code.

// You shouldn't normalize a null vector
if (direction.length() != 0) {
    direction = direction.normalize();
}
velocity = direction * speed;

Updating position and velocity of an entity can be done by using Euler integration like in the following pseudo code.

position += velocity * delta;
velocity += (force / mass) * delta;

In the example application there is no acceleration, so the update method for entities looks like this:

public void update(float delta) {
    previousPosition = new Vector2f(position.x, position.y);
    if (direction.length() != 0) {
        direction = direction.normalize();
    }
    Vector2f velocity = direction.scale(speed);
    position = position.add(velocity.scale(delta));
}

The first line is optional and only needed if you want to use interpolation, where you need the previous and the current state.

Checking for collision

For checking collisions there are many algorithms like the Separating Axis Theorem (SAT) or Axis-Aligned Bounding Boxes (AABB). For simple applications AABB is good enough, but if you need more control you should use an algorithm like SAT.

Axis-Aligned Bounding Boxes (AABB)

Defining an AABB is pretty easy, all you have to do is creating a rectangle between two points. These two points are called the minimum and maximum vectors. For a 2D application you can assume that the bottom left point of an entity is the minimum vector and the top right point is the maximum vector.

Now with these points we can check two AABBs if they have collided.

boolean intersects(AABB first, AABB second) {
    if (first.max.x < second.min.x)
        return false;

    if (first.max.y < second.min.y)
        return false;

    if (first.min.x > second.max.x)
        return false;

    if (first.min.y > second.max.y)
        return false;

    // All tests failed, we have a intersection
    return true;
}

Another method to use AABBs is by defining a center vector and using the half-widths of the rectangle.

boolean intersects(AABB first, AABB second) {
    if (Math.abs(first.center.x - second.center.x) > first.halfWidth.x + second.halfWidth.x)
        return false;

    if (Math.abs(first.center.y - second.center.y) > first.halfWidth.y + second.halfWidth.y)
        return false;

    // All tests failed, we have a intersection
    return true;
}

It is up to you which would be better suited for your application. Of course you also need to update the AABB with every new position.

After detecting a collision you have to adjust the entity position. Assuming you have the origin of an entity at the lower left, you can adjust the position like this pseudo code:

if (entity.collided(otherEntity) == COLLISION_TOP_SIDE)
    entity.position.y = otherEntity.y + otherEntity.height;

if (entity.collided(otherEntity) == COLLISION_BOTTOM_SIDE)
    entity.position.y = otherEntity.y - entity.height;

if (entity.collided(otherEntity) == COLLISION_LEFT_SIDE)
    entity.position.x = otherEntity.x - entity.width;

if (entity.collided(otherEntity) == COLLISION_RIGHT_SIDE)
    entity.position.x = otherEntity.x + otherEntity.width;

If you don't do that you will have another collision in the next loop and the entity will slowly slide through the other entity.

Next Steps

Since this is the last tutorial the next steps depend to you. If you just started creating games you may want to try creating some simple games first, like Tetris or Space Invaders.
If you want to learn more of LWJGL3 you should check the demos in the LWJGL3 GitHub repository.

You may also want to use a library like libGDX or jMonkeyEngine for creating games, it will do the boilerplate code for you.
For collision detection you could take a look at JBox2D or JBullet, if you don't want to implement your own physic engine.
But of course you could also create your own little game library from scratch.

It's up to you what you try next, so have fun and thanks for reading this tutorial!


Source

References