Some design goals:
The simulation should be fairly efficient - we might have a hundred arrows being launched over the heads of a hundred enemy units, and we don't want to slow the game down by doing ten thousand collision tests per turn. It's better to do a bit more computation when launching the projectile and then have it ignore changes to the world while it's flying, than to try to hack together a more realistic physics simulation for detecting hits.
The simulation code needs to be independent of the graphics code (for reliable synchronised multiplayer).
We should have some level of control over the gameplay aspects of projectile weapons, e.g. making Elite units more accurate so they are ~10% more effective than normal units.
If someone is injured or killed by a projectile, the graphics need to convince the player they really got hit by it.
For performance reasons, the simulation 'turns' are fairly slow (currently about 3 turns per second; could be increased to maybe 5 per second to reduce player input latency) and unit positions are simply interpolated when rendered between turns. Projectiles travel at a constant speed, so it might take e.g. 2.5 turns to reach the target. To make it look good, they need to be rendered so that they hit whatever unit they hit at its interpolated position between turns 2 and 3, but the actual simulation computations have to occur in either turn 2 or 3, and the unit could move by half a tile in that time. So just doing a test for "what unit is currently at the point where the projectile landed?" is not going to match what it looks like it hit.
It should be possible to avoid getting hit by projectiles if you're quick.
the gameplay element of moving away to dodge a volley of projectiles seems worth keeping, it'd be a shame to lose that in 0ad. Consider micromanaging a hero unit - it'd be a shame if his destiny were pre-determined, rather than at least partially dependent on skillful dodging/weaving.
AOM kind of cheats by making arrows follow their targets.
I looked at AoM, and arrows diverge from their normal path in order to track their target unit. (It's much easier to see if you reduce the velocity of arrows, and then make a guy run around while being shot at - the arrows move really weirdly to make sure they land on him.) AoM actually has a "TrackRating" in proto.xml which affects this - if it's high (which it is by default) then the arrows try hard to follow their target, and if it's low then they lag behind and are more likely to hit the ground behind a running unit. It's got some values for accuracy and spread too. I'm not sure exactly what it's doing (there's a lot of variables and it's hard to test), though I can see it's not the same as what I'm thinking of, but it does the same trick with making in-flight arrows track their target instead of doing a realistic physics simulation.
Walls should block projectiles. Trees should perhaps partially block arrows and javelins.
Description of old (pre-simulation2) projectile implementation:
In the old system, it does an actual physics simulation - it moves the projectile according to gravity each simulation turn, finds all the entities whose footprints it crosses (in 2D), then looks for the first one (by entity ID) whose bounding box is tall enough to reach the arrow, and if it finds one then it hits it.
A few problems I see with this (in decreasing importance):
- We get very little gameplay control - we might want to say there's 75% less chance to hit units that are hidden in a forest, or a 25% greater chance to hit friendly units if you fire into the middle of a melee, etc, but it's hard to do that if we're doing turn-by-turn collision detection.
- Bounding boxes are a very rough approximation, and many objects are not shaped like boxes, so things will get hit even if it looks like the arrow is nowhere near a solid part of them.
- To make things look nice, the projectile ought to be launched from an appropriate prop point on the actor (currently it's just launched from 2.5 units above the ground), but we don't want the simulation to depend on the actor mesh data (because of floating-point inaccuracies, and because it's good to keep them independent).
- The collision detection sounds fairly expensive - it won't be much fun when you build a hundred archers and tell them to aim across the entire enemy army, and it has to check every arrow against every unit every turn, even if we have some optimised spatial data structures.
- It's lots of floating-point code, which is annoying to translate into fixed-point.
Current plan based on discussions, copied from comments in the source code:
To implement (in)accuracy, for arrows and javelins, we want to do the following:
- Compute an accuracy rating, based on the entity's characteristics and the distance to the target
- Pick a random point 'close' to the target (based on the accuracy) which is the real target point
- Pick a real target unit, based on their footprint's proximity to the real target point
- If there is none, then harmlessly shoot to the real target point instead
- If the real target unit moves after being targeted, the projectile will follow it and hit it anyway
In the future this should be extended:
- If the target unit moves too far, the projectile should 'detach' and not hit it, so that players can dodge projectiles. (Or it should pick a new target after detaching, so it can still hit somebody.)
- Obstacles like trees could reduce the probability of the target being hit
- Obstacles like walls should block projectiles entirely
- There should be more control over the probabilities of hitting enemy units vs friendly units vs missing, for gameplay balance tweaks
- Larger, slower projectiles (catapults etc) shouldn't pick targets first, they should just hurt anybody near their landing point
None of the accuracy stuff is implemented properly. There's just a 50% chance of hitting the target the player selected, and 50% chance of hitting nothing.