Lachlan's misadventures in games programming

Friday, 29 August 2014

I don't want to set the world on fire

8/29/2014 02:41:00 pm Posted by Lachlan No comments

TL;DR version - Scroll to the bottom for cool fire spewing animations

I've spent the last days adding at least a basic animation framework, and a fairly cool animation to Atlas Warriors. As a test, I added a blue shimmer when a Healer heals another enemy - which worked just fine but isn't particularly interesting.

The primary reason I wanted it was for implementing Dragons. What is a dragon without some good and proper fire breathing? So, without further ado...


Lame, I understand - but at least it wasn't another Arrow In The Knee reference

The first step was an algorithm for determining flame coverage over the area fired. That algorithm can be used (with the actual distance) for determining who to ignite, and (by looping the distance from 0 to the actual distance) for creating the animation.

The algorithm is far more simple then what I've probably made it. My pseudo code also probably gives away that I'm a lawyer - not a compsci or programming major... so I hope you can at least understand it. Also know that some was more trial and error'd then well planned. This is sure as hell not best practice!

  • Given:
    • Source
    • Target
    • Desired Distance
    • Desired Radius at distance
  • Calculate angle between Target and Source
  • Calculate the end point ( end(x,y) = (sin(angle) * distance, cos(angle) * distance) )
  • Calculate angle to the other end points. The other end points are separated by 1 unit, perpendicular to the end point, in distance radius in each direction. Put the angles in list J
  • Create a 2D array (G) initialised to zero from [-distance,distance][-distance,distance]
  • For i in J
    • For k := 1 to Distance
      • x = sin(i) * k
      • y = cos(i) * k
      • If x,y blocks flame then break
    • xpart = frac(x + .5)
    • if (xpart < 0) then xpart = xpart + 1
    • ypart = frac(y + .5)
    • if (ypart < 0) then ypart = ypart + 1
    • xint = floor(x + .5)
    • yint = floor(y + .5)
    • G[xint,yint] = G[xint,yint] + xpart/8 + ypart/8
    • G[xint+1,yint] = G[xint,yint] + (1-xpart)/8 + ypart/8
    • G[xint+1,yint+1] = G[xint,yint] + (1-xpart)/8 +(1-ypart)/8
    • G[xint,yint+1] = G[xint,yint] + xpart/8 + (1-ypart)/8
  • Return G
This returns a grid showing how much flame hit each section. That G will have some fractions where only part of a square was hit by the flame. I'm going to use those fractions as the chance of igniting a monster on those tiles. I also use them in the animation.

A sensible person (including possibly me in the future) would: leverage whatever antialiased line algorithm they had access to (including, for instance the pygame ones), do the drawings of a black line on a white surface and use the darkness as the percentage of the square hit. I may still migrate to this in the future. It does still have to be looped to have the collision detection.

The animation is quite simple. As described already, the above algorithm is looped from 0 to the desired distance. For each frame, it loops over the grid and draws a character in a foreground color  and a background color all selected to reflect the value. Mine use > 3, >2, >1, >.75, >.5, >.25, >0.15 and > 0. It does nothing on a 0.

The end result is reasonably good, if not yet perfect. I will note that it will be coming from Dragons - not from the player as in these gifs. They will hopefully be sufficiently horrifying when you have an encounter with them!

Any comments would be appreciated.


Post a Comment