Now that I had collision detection working its was time to deal with what happens if the LEM comes in too hot! Before I started implementing an explosion animation I had a look at what my precursors did. First the venerable Spacewar!
Not bad, but as Norbert Landsteiner points out in his ICSS blog Addendum: All New Pyrotechnics of his initial explosions based on Spacewar! they were just "pretty clouds of saucer dust, almost as if they were painted onto the display". So Mr. Landsteiner set out to do better.
I definitely think that he succeeded. The explosion looks great and is much more three-dimensional as is appropriate for a space environment. I can't shake the thought that I have seen something similar on the movie screen.
I wanted to put my own "signature" on the Lunar Lander explosion. Since LL takes place on the moon I knew that my explosions had to reflect the effect of gravity. I based the explosion of Norbert's implementation where each particle (48 in my case) had their own persistent delta, but in my code over time gravity is also applied to those deltas.
My explosion code is broken up into two parts. The first section sets up the explosion "table" with initial start coordinates, plus x and y deltas.
/ Explosion stuff.
nep=70 / Number of explosion particles.
exx, . nep/ / Particle x coordinate.
exy, . nep/ / Particle y coordinate.
edx, . nep/ / Particle delta x.
edy, . nep/ / Particle delta y.
nel, 0 / Number of times to go through the explosion loop.
skp, 0 / Explosion frames to skip.
egr, 0 / Gravity imposed on each particle.
dx, 0 / Delta x applied to particles.
dy, 0 / Delta y applied to particles.
/ Setup for an explosion.
exp, dap ext / Deposit return address.
law exx / Load address x origin into AC.
dap ex1 / Deposit AC in address part at label ex1.
law exy / Load address y origin into AC.
dap ex2 / Deposit AC in address part at label ex2.
law edx / Load address x delta into AC.
dap ex3 / Deposit AC in address part at label ex3.
law edy / Load address y delta into AC.
dap ex4 / Deposit AC in address part at label ex4.
lac xmn / Explosion starts from the LEM center.
add xmx / Calculate center x of bounding box.
sar 1s / Divide by 2.
dac scx / Save center x.
lac ymn
add ymx / Calculate center y of bounding box.
sar 1s / Divide by 2.
dac scy / Save center y.
elp, random / Create a random x start offset.
and (17
sub (10
add scx / Add the x origin.
ex1, dac . / Save the particle x coordinate.
random / Create a random y start offset.
and (17
sub (10
add scy / Add the y origin.
ex2, dac . / Save the particle y coordinate.
random / New random number.
and (17 / Reduce to 0 to 15.
add (1 / Range 1 to 16.
dac dy
random / Get a new random number.
and (17 / Reduce to 0 to 15.
sub (10 / Range -8 to 7.
dac dx / Save as x delta.
ex3, dac . / Save the particle dx.
lac dy / Get the particle dy.
ex4, dac . / Save the particle dy.
idx ex1 / Increment all the pointers.
idx ex2
idx ex3
idx ex4 / Increment value in ex4, leave it in AC.
sas (dac edy+nep / Table full?
jmp elp / No - Keep going.
ext, jmp . / Yes - Return.
To summarize:
- Pointers to the beginnings of the four arrays that comprise the table are set.
- x coordinate of the particle
- y coordinate of the particle
- delta to be applied to x
- delta to be applied to y
- Establish the current center point of the LEM (scx, scy) in 0-1023 screen coordinates.
- For each particle in the table:
- Set the start x coordinate to scx plus a random offset between -8 and 7.
- Set the start y coordinate to scy plus a random offset between -8 and 7.
- Set the x delta value with a random number between -8 and 7.
- Set the y delta value with a random number between 1 and 16.
Using this scheme the starting points of the particles are randomly placed within the body of the LEM. Similarly the particle "vectors" are also nicely randomized.
The second piece of code gets called repeatedly from the main loop when an explosion is "in progress". Each time it is called all of the particles in the table are advanced one position by their individual deltas then displayed on the screen.
/ Draw an explosion frame.
dex, dap det / Deposit return address.
law exx / Load address x origin into AC.
dap dx1 / Setup in dx1.
dap dx3 / Setup in dx3.
law exy / Load address y origin into AC.
dap dx4 / Setup in dx4.
dap dx6 / Setup in dx6.
law edx / Load address x delta into AC.
dap dx2 / Setup in dx2
law edy / Load address y delta into AC.
dap dx5 / Setup in dx5.
lac egr / Gravital velocity to impose on each particle.
add acc / Add moon's acceleration.
dac egr / Save.
dx1, lac . / Load the x particle position.
dx2, add . / Add the x delta.
dac scx / Save new x.
dx3, dac . / Update particle x position.
dx4, lac . / Load the y particle position.
dx5, add . / Add the y delta.
sub egr / Apply moon's gravity.
dac scy / Save new y.
dx6, dac . / Update particle y position.
spa / Don't plot negative values of y.
jmp spl
lac scx / Don't plot negative values of x.
spa
jmp spl
sub (1777 / Check for x > 1023.
sma
jmp spl / Don't plot x values > 1023.
PLOT scx,scy / Draw the particle.
spl, idx dx1 / Increment all the pointers.
idx dx2
idx dx3
idx dx4
idx dx5
idx dx6
sas (dac exy+nep / Table done?
jmp dx1 / No - Keep going.
det, jmp . / Return.
To summarize:
- Pointers to the beginnings of the four arrays that make up the table are set.
- x coordinate of the particle
- y coordinate of the particle
- delta to be applied to x
- delta to be applied to y
- For each particle in the table:
- Delta x is added to the x coordinate.
- Delta y is added to the y coordinate.
- The accumulated acceleration due to the moon's gravity is subtracted from the y coordinate.
- If the particle is still "visible" on the screen plot it at the newly calculated coordinate.
Here are the snippets of calling code.
...
/ If we get here the point is inside the LEM's bounding box.
jsp exp / Setup for explosion.
lac (40 / Bunch of loops for explosion.
dac nel / Set explosion frame counter.
lac (20 / Bunch of frames to skip.
dac skp / Set explosion frame skip.
dzm egr / Clear gravity imposed on particles.
jmp vvl / Continue drawing status.
...
/ Check for explosion in progress.
lac nel / Get the explosion loop counter.
sza i / Not Zero?
jmp plm / No - Normal draw LEM.
/ Draw the explosion.
dzm vx / Clear velocities.
dzm vy
lac skp / Check for skip frame.
add (-1
dac skp
sza / Zero?
jmp vvl / No - Skip drawing explosion.
jsp dex / Yes - Draw an explosion frame.
lac (20 / Update skip.
dac skp
lac nel / Update counter.
add (-1
dac nel
sza i / Not Zero?
jmp a2 / No - Restart game.
jmp vvl / Yes - Loop.
...
When an explosion is enabled, the the variable nel is set to a non-zero value that represents the number of frames in which the explosion is to be shown. At the same time a variable skp is set with the number of frames to skip between showing explosion frames. It is the "skip frames" value skp that makes the explosion animation appear to be in slow motion.
So why slow motion Mike?
- Because it's cinematic ;-)
- Hints at the moon's weaker gravity.
- More practically, when the explosion animation is displayed at "full speed":
- The "particles" are drawn as solid arcs because of the Type 30 display persistence. Even with skipped frames the fading arcs are still visible, but the particle at the tip of the arc is still brighter.
- Similarly when the explosion animation finished, the fading outline of the LEM was still visible. Didn't "sell" the whole destroyed thing.
One happy unanticipated result of my implementation is that when the "particles" fall below the terrain line, it looks like they are "in front" of the ground. This makes them feel 3-dimensional, like they are coming towards you. Weird.
Michael Gardi
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.