224. World of Warships – Fast moving shots
[NOTE – After making my previous post about figuring out where gun shells explode, I realised I had left something out – and not got it quite right. So I moved that discussion into this post, and corrected it].
If you’ve worked with physics in Codea, you may have seen how, if your objects move too fast, they can go right through solid walls, and you have to set a property called bullet to prevent this. I had much the same problem – that shots were clearly passing right through the ship, but I wasn’t detecting that they hit the ship.
And I think the solution (if I got it right) is really interesting. I hope you do, too.
My gun shots are moving at 5 pixels per frame when they leave the barrel, and, since the ships are narrow, it is possible for a shot to never be inside its target when I measure it, ie it can “skip over” it without exploding.
Even if this doesn’t happen, and I do manage to identify all the shots which hit the target ship, I have the problem that if the shell is on the far side of the ship when I measure it (ie it has gone through most of the ship already), the explosion is going to be on the wrong side of the ship, or maybe out of sight inside the ship. Now I know that sometimes, shells do go through a ship before exploding, but it just doesn’t look right. Users want to know where their shots hit, so I want the explosion to be where the shell first hits the ship, as shown below.
What I need is to measure the position more accurately, and explode the shell when it gets within a given distance of any ship vertex. I could, for example, store the previous shell position, and interpolate between that position and the current position, say in ten steps, looking for the first step which brings the shell within exploding distance of a vertex.
However, it would be much nicer to directly calculate the exact point where the shell first gets within the exploding distance of any vertex.
Transforming the shot positions
The ship was originally built facing to the right, but is now rotated at an angle. The ship vertices are still in their original positions and not rotated, and we need to correct this, before comparing their positions with the path of the gun shell. (If you know about these things, the ship vertices are in object space, while the gun shell positions are in world space).
Actually, there’s a simpler way to get all the rotations the same, which is to rotate the two gun shell positions instead, rather than all the ship vertices. To do this, we need to
- subtract the position of the ship from both gun shell positions (which effectively translates them to the ship position)
- rotate by the negative of the ship angle
If this isn’t clear, get a couple of pencils, set them up like a (rotated) ship and the path of a gun shot, and try the steps above. (Confession – I did this myself, to test my thinking. I really suck at rotations).
We can now compare the resulting positions with the ship vertices.
 Calculating the explosion point
We start by drawing a line between the previous and current positions of the shell. Then, for each vertex, we calculate the point on that line (if any) where the shell reaches the minimum distance for exploding (eg 3 pixels). The final explosion occurs at the earliest of all these points, ie at the first point where the shell is within the minimum distance of any vertex. This acts like the proximity fuse used in many gun shells.
The picture below shows what we are trying to do. The red line is drawn between the old and current positions of the shell. We draw a circle round the vertex with a radius equal to the minimum explosion distance, and calculate where it crosses the red line, which could happen twice, or once, or not at all. (If it happens twice, we’ll use the earlier of the two).
How do we calculate the intersection of a circle and a line? I drop a line from the vertex onto the path of the gun shell at a right angle (this is also the shortest distance between them), as shown below. I provided a function for doing that, here, which also gives us the length of the line (marked d below). If this line is longer than the explosion distance, then there is no intersection.
Now it’s easy to calculate the length of the lines from a-b and a-c, using Pythagoras (the square of the hypotenuse, ie the exploding distance, equals the sum of the squares of line d and a-b [or a-c]). Once we have the points b and c, we know exactly where the gun shell first gets within exploding range.
While this is a bit of work to do for each shell, it is accurate, and we only do it once they get within a certain distance of the ship, and we avoid the alternative of having to do a number of interpolations between the old and current shell positions.
So I think it’s really interesting. It also shows the value of the playing around I have done in the past. Already in this project, I’ve used a water technique, and now the function above, which have saved me a lot of time.