Page 1 of 1

Super-Fast (tiny) Projectile

PostPosted: Mon Aug 07, 2017 5:41 pm
by Matt
The problem
FastProjectiles are too slow. There's no theoretical limit to their speed, true enough, but the problem is performance.

Every single tic, a fastprojectile must check every possible position along its trajectory for that tic until it hits something, in increments equal to its radius.

This is usually not too bad. The Hexen MageWandMissile, the first of all fastprojectiles, has a radius of 12 and a speed of 184, for a total of 184 / 12 = 15 movement, position, collision, sky, etc. checks every tic. Even without multithreading you can have plenty of these flying around without problem.

Things get much worse with faster and smaller projectiles, however. Assuming 16 DUs is equivalent to about a foot, we can place the (typical, sea-level) speed of sound around 512 DUs per tic: 512*35/16=1120 feet per second. This is much faster than your typical pistol load, but Doom has a shotgun and shotgun loads are very frequently around this speed or faster.

Meanwhile, a typical bullet is about a fifth to a third of an inch, and not that much longer. That is a small fraction of a Doom unit.

Let's say then that we had a shotgun that fired 7 pellets of 00 buckshot at 1120 fps. That's a radius of ~0.2 DUs, or 1/5 of a DU, at a speed of 512. That adds up to 7*5*512 = 17,290 movement, collision and other interaction checks in a single tic, all on the virtual machine, just from firing one shot from one gun! Don't even think about trying to fight a couple spider masterminds on the other side of a big map...

The solution
Hitscans. Instead of just firing straight forwards until it hits something or maxes out and fizzles to nothing, we can do as follows:

  1. limit the range of the hitscan to the projectile's desired speed.
  2. have the projectile shoot the hitscan in its movement direction to check for collisions.
  3. if there is a collision, warp the projectile to where the puff would be and have it behave as though it were a normal projectile colliding with whatever the hitscan had hit.
  4. if there is no collision, warp the projectile to the end of the hitscan's reach, alter the trajectory as required (turbulence, gravity, deceleration, seeking, etc), and fire the hitscan again for the next tic, repeating the process until something is hit or the actor is destroyed.

The example
The code posted here is a replacement for the plasma rifle ball. It is set to fire at about 3 times the speed of sound, though the reader is encouraged to play with different numbers to see how this works.

There is extensive additional code for not only the FastProjectile-style trail, but also:
  • gravity and turbulence.
  • spawning sound actors to represent supersonic cracks wherever the projectile's path nears a player.
  • movement tracking for projectiles that have been fired into the sky. (please remember to remove this code for any projectiles that do not in fact fall back down again!)
  • damage and blood.
  • generating puff actors, though in principle there is nothing preventing you from simply using the death state.

Nearly everything has some kind of audiovisual expression in this example, just for demonstration purposes.

I have not included ripping, ricochets or wall penetration in this demonstration. All of these can be done through modifying BulletImpact(); if it is required that a projectile rip through a target that it has not killed, I believe the best way is to temporarily make that target unshootable in a similar manner to the method that allows the projectile to leave the shooter (as it is the projectile that is firing the hitscan not the shooter).

Obviously this is not intended to be used "straight out of the box" - I do expect anyone using this to be capable of doing their own tweaking. That said, please let me know if there are any bugs or obvious omissions and I will update the code accordingly.

Re: Super-Fast (tiny) Projectile

PostPosted: Fri Aug 11, 2017 12:13 pm
by Brohnesorge
Gonna have to check this out once I get home, but it seems supremely useful. Thanks for this