Predictive firing (in a tile-based game)

I have a (turn-based) tile-based game, in which you can shoot at entities.

You can move around with mouse and keyboard, it's all tile-based, except that bullets move "freely".

I've got it all working just fine except that when I move, and the creatures shoot towards the player, they shoot towards the previous tiles.. resulting in ugly looking "miss hits" or lag.

I think I need to implement some kind of predictive firing based on the bullet speed and the distance, but I don't quite know how to implement such a thing...

Here's a simplified snip of my firing code.

class Weapon {

public void fire(int x, int y) {
...
...
...
Creature owner = getOwner();
Tile targetTile = Zone.getTileAt(x, y);

float dist = Vector.distance(owner.getCenterPosition(), targetTile.getCenterPosition());

Bullet b = new Bullet();
b.setPosition(owner.getCenterPosition());

// Take dist into account in the duration to get constant speed regardless of distance
float duration = dist / 600f;

// Moves the bullet to the centre of the target tile in the given amount of time (in seconds)
b.moveTo(targetTile.getCenterPosition(), duration);

// This is what I'm after
// Vector v = predict the position
// b.moveTo(v, duration);

Zone.add(bullet); // Now the bullet gets "ticked" and moveTo will be implemented
}
}


Movement of creatures is as simple as setting the position variable.

• an alternative option would be to have it fire a burst shot sometimes, so that it will at least be firing one of the shots closer to you Sep 12 '12 at 15:42

At its core you are going to have to predict which tile the target will be on.

A simple solution would be to take the current velocity of the target, figure out where the target would be in the amount of time it would take the bullet to traverse to the player (to get a rough estimate you could use the current distance to the target), and then aim at that tile.

• Some games cheat by altering (a diagonal offset) the instantaneous velocity of the bullet. One of them is Age of Empires (although not tile based), where a javelin was thrown and it followed a moving character till it hit almost dead on. It was annoying to see it, but at least one wouldn't complain that the arrow fell 3 meters back and then their unit died. Sep 12 '12 at 15:42
• Your answer sounds like a nice and simple solution... but I must admit my math skills are, well... a bit rusty! A pseudo-code, or a more detailed explanation behind the - probably quite straightforward math - would be very helpful. Thanks for your time and answer! Sep 12 '12 at 20:45
• Calculate distance from you to the player. You have the speed of the bullet, from that determine the time it'll take to reach the player (distance/speed). You have the velocity of the player. Predicted position = current player position + ( player velocity * time for bullet to hit player ). Aim at predicted position. Sep 12 '12 at 21:10
• OK, I got it almost working now... one more silly question though, how do I actually calculate the velocity of the player for predicting to work correctly? I currently have a simple move(Direction)-method in my player class. The turn gets processed afterwards. The player moves Tile.SIZE at a time. I tried some things, off the top my head, but they didn't work quite right; the best result got the predicting to hit 1-4 tiles ahead of the wanted tile. The predicting itself should work now, though! Sep 13 '12 at 22:47
• I dont think the shooting angle depends on the distance. It depends only on the velocities of bullet, player and the relative angle of player with respect to the enemy. Sep 14 '12 at 7:23

Sounds like ballistics technology in Age of Empires. You need to find the correct angle of fire.

         A
| \\
|  \ \
|   \  \
| vb \   \
|     \   \
|      \    \
D------ B--->C
vp

Here A = enemy
B = player current position
C = player future position
vb = speed of bullet
vp = speed of player


Hope you understood the graph. If I got the problem correct, then your enemy is shooting at B, but you want it to shoot at C.

Let angle(DAB) = o
angle(DAC) = p


Clearly,

vb*sin(o) + vp = vb*sin(p)
p = inv_sin( sin(o) + vp/vb )


Here is the angle you needed to shoot.

NOTE

I does not depend on the distance between enemy and player