- The basic idea is that we draw a line between two points.
- Then, loop through every line in the map, and see if the line we've just drawn intersects the line on the map.
- If it does, use pythagoras' equation to calculate the linear distance between the starting point and the point of contact.
- If this distance is shorter than any previous collision point (it's quite possible that one, long line can intersect a number of points on the map) then we remember this point and continue testing the other lines in the map.
- At the end of all this testing, if there's been a collision, we should have stored the first point along the line that meets with a wall.
- We then calculate the linear distance between the point of collision and the destination point. This represents the amount of travel "still to complete" after we ricochet/rebound off the wall.
- The next thing to do is to calculate the potential destination point, after applying rebound at the point of contact.
- The line-of-sight function is called a second time, with the starting point now the earlier collision point, and the end point the new, calculated destination point (after applying the rebound/ricochet function to the original line). This new line is then tested against every line in the map, and any more collisions calculated in the same manner.
(we marked each collision point on the map during testing)
For further testing, we overwrote the "recalculate distance after collision" routine, and made it a (large) fixed amount. This meant that every time the line-of-sight hit a wall in the map, it would always ricochet by a large amount - the idea being to test how it would react over a large distance.
It was to some relief that the ricochet/rebound algorithm correctly drew the expected path. It was noted at this point that the angle of rebound appears similar on every collision point. This is actually to be expected - since we're using only walls that are either vertical and horizontal, and our algorithm calculates a "perfect rebound" (the angle of approach is also the angle it leaves the collision point) it makes sense that we see the same angle throughout the whole screen.
Confident that the rebound function was working correctly, we started to add different functionality to different walls.
Using an online editor made earlier, we can describe our map as a number of "lines with properties" as an xml document. As shown in the image above, one of the properties that we can apply to our lines/walls is "can shoot through". Different lines with different properties can be used to describe different types of walls in our game maps.
For example, a line which can be "seen through" but not "can shoot through" could be used to indicate bullet-proof glass, or - in a sci-fi game - a force-field. Similarly, a line which the player "can shoot through" but not "see through" could be used to indicate a line of fog or smoke.
To further test our line-of-sight/bullet-path routines, we made one of the walls (specifically, in the image above, line 4) "passable" by setting "can shoot through" to "yes". The resulting test looked crazy - but after investigating a bit further, it actually appears to be correct too!
So we've tested our line-of-sight/bullet path routine with simple and complex paths, and proven that we can change the properties of different walls in the map, to alter the way the bullets ricochet and bounce around the map. It's starting to look like we've got the basis of a pretty impressive engine for our board game....