One of the fun parts of personal projects is, well, you can do whatever you want. Come up with a silly or even dumb idea and you can implement it if you want. That is effectively how I’ve approached BASeBlock. Iit’s sort of depressing to play- held back by older technologies like WindowsForms and GDI+, and higher resolution screens make it look quite awful too. Even so, when I fire it up I can’t help but be happy with what I did. Anyway, I had a lot of pretty crazy ideas for things to add into BASeBlock, some fit and were even rather fun to play- like adding a “Snake” boss that was effectively made out of bricks- others were sort of- well, strange, like my Pac man boss which attempts to eat the ball. At some point, I decided that the paddle being able to shoot lightning Palpatine-style wasn’t totally ridiculous.
Which naturally led to the question- how can we implement lightning in a way that sort of kind of looks believable in a mostly low-resolution way such that if you squint at the right angle you go “yeah I can sort of see that possible being lightning?” For that, I basically considered the recursive “tree drawing” concept. One of the common examples of recursionm is drawing a tree; f irst you draw the trunk, then you draw some branches coming out of the trunk, and then branches from those branches, and so on. For lightning, I adopted the same idea. The eesential algorithm I came up with was thus:
- From the starting point, Draw a line in the specified direction in that direction at the specified “velocity”
- From that end point, choose a random number of forks. For each fork, pick an angle up to 45 degrees of difference from the angle between the starting point and the second point, and take the specified velocity and randomly add or subtract up to a maximum of 25% of it.
- If any of the generated forks now have a velocity of 0 or less, ignore them
- otherwise, recursively call this same routine and start another “lightning” from this position at the specified velocity from the fork position.
- Proceed until there are no forks to draw or a specified maximum number of recursions has been reached
of course as I mentioned this is a very crude approximation; lightning doesn’t just randomly strike and stop short of the ground and this doesn’t really seek out a path to ground or anything along those lines. Again, crude approximation to at least mimic lightning. The result in BASeBlock looked something like this:
Now, there are a number of other details in the actual implementation- first it is written against the game engine so it “draws” using the game’s particle system, and also uses other engine features to for example stop short on blocks and do “damage” to blocks that are impacted, and there are short delays between each fork (which again is totally not how lightning works but I’m taking creative license). The result does look far more like a tree when you look at it but the animation and how quickly it disappears (paired with the sound effect) is enough, I think, to at least make it “passably” lightning.
But All this talk, and no code, huh? Well, since this starts from the somewhat typical “Draw a shrub” concept applied recursively and with some randomization, let’s just build that- the rest, as they say, will come on their own. And by that, I suppose they mean you can adjust and tweak it as needed until it gets the desired effect. Or maybe you want to draw a shrubbery, I’m not judging. With that in mind here’s a quick little method that does this against a GDI+ Graphics object. Why a GDI+ Graphics Object? Well, there isn’t really any other way of doing standard Bitmap drawing on a Canvas type object as far as I know. Also as usual I just sort of threw this together so I didn’t have time to paint it and it might not be to scale or whatever.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
static float MaximumLength = 300f; private static Pen LightningPen = new Pen(Color.Blue,2); static Random rgen = new Random(); private static void DrawLightning(Graphics Target, PointF StartPosition,PointF Velocity,double CurrentLength = 0) { PointF EndPosition = new PointF(StartPosition.X+Velocity.X,StartPosition.Y+Velocity.Y); Target.DrawLine(LightningPen,StartPosition,EndPosition); //choose random number of forks double CurrentAngle = GetAngle(new PointF(0, 0), Velocity); double CurrentVel = Distance(new PointF(0,0), Velocity); int MaxForks = rgen.Next(0, 5); for(int i=0;i<MaxForks;i++) { double useAngle = CurrentAngle + (rgen.NextDouble() * (Math.PI / 4)) - (Math.PI / 8); double useVelocity = CurrentVel+ (rgen.NextDouble() * CurrentVel*.25)- CurrentVel * .125; PointF usePoint = new PointF((float)((Math.Cos(useAngle)*useVelocity)),(float)((Math.Sin(useAngle)*useVelocity))); if(useVelocity > 5 && useVelocity+CurrentLength < MaximumLength) DrawLightning(Target,EndPosition,usePoint,CurrentLength+useVelocity); } } private static double GetAngle(PointF PointA, PointF PointB) => Math.Atan2(PointB.Y - PointA.Y, PointB.X - PointA.X); public static double Distance(PointF PointA, PointF PointB) => Math.Sqrt(Math.Pow(PointB.X - PointA.X, 2) + Math.Pow(PointB.Y - PointA.Y, 2)); |
What amazing beautiful output do we get from this? Whatever this is supposed to be:
It does sort of look like a shrubbery I suppose. I mean, aside from it being blue, that is. It looks nothing like lightning, mind you. Though in my defense if electricity tunnels through certain things it often leaves tree-like patterns like this. Yeah, so it’s totally electricity related.
This is all rather unfulfilling, so as a bonus- how about making lightning in Photoshop:
Have something to say about this post? Comment!