Exploding lemming effect.

Blitz3D Forums/Blitz3D Beginners Area/Exploding lemming effect.

SheepOnMintSauce(Posted 2005) [#1]
I'm having a bit of a problem with my sines and cosines. I thought I'd have a go at making an effect like the exploding lemmings from 'Lemmings', and I've nearly sort of succeeded.

Type bits ;type for the particles
Field x
Field y
Field angle
Field power
Field r
Field g
Field b
End Type
fps=CreateTimer(10)
anglenumber=180 ;set angle to 180 for the first particle
AppTitle("Exploding Lemming Type Thing","Quit?")
Graphics 800,600,0,2
SetBuffer BackBuffer()

While Not KeyDown(1)
	WaitTimer(fps)
	Cls
	If MouseDown(1) ;when mouse is down
		For n=1 To 15 ;make dots from 180 to 360
			If anglenumber=<360 ;at 15 degree intervals
				anglenumber=anglenumber+15
			Else
				anglenumber=180
			EndIf
			explode.bits=New bits
			explode\x=MouseX() ;where the mouse is
			explode\y=MouseY()
			explode\r=Rnd(0,255)
			explode\g=Rnd(0,255)
			explode\b=Rnd(0,255)
			explode\angle=anglenumber
			explode\power=1	
		Next
	EndIf
	For explode.bits=Each bits
		If explode\power>=10
			If explode\angle<=90
				explode\x=explode\x+explode\power*Cos(explode\angle)
				explode\y=explode\y+explode\power*Sin(explode\angle)
			Else
				explode\x=explode\x+explode\power*Cos(explode\angle)
				explode\y=explode\y+explode\power*Sin(explode\angle)
				explode\angle=explode\angle-15
			EndIf
		Else
			explode\x=explode\x+explode\power*Cos(explode\angle)
			explode\y=explode\y+explode\power*Sin(explode\angle)
			explode\power=explode\power+1
		EndIf
		Color explode\r,explode\g,explode\b
		Rect explode\x,explode\y,2,2,1
		If explode\y>610
			Delete explode
		EndIf
	Next
	Flip
Wend
End


The problem is, when the bits finally run out of gas and start falling back down to earth they all loop around the left. I want them really to just fall straight downwards instead of looking like some sort of pixel aerial acrobatics team.

Does anyone have any advice on how I could do this?


Baystep Productions(Posted 2005) [#2]
[ code ] & [ / code ]

Ahh but yes, I had a problem with this to. Well I believe it's in the function that you used to turn it (obviously) and you need to limit so it stops turning, usualy when it points straight down. Using maybe EntityPitch, but I have'nt looked through your code.


SheepOnMintSauce(Posted 2005) [#3]
Ah cheers. Didn't notice that. =)

The program won't use EntityPitch since it's in 2D. I'm using sin and cos to do turning, but it usually confuses me a bit. I usually end up messing about with it, until I get it right. But I'm stumped as to what I should do now though.

I've got a feeling it's something to do with this bit :

			If explode\angle<=90
				explode\x=explode\x+explode\power*Cos(explode\angle)
				explode\y=explode\y+explode\power*Sin(explode\angle)
			Else
				explode\x=explode\x+explode\power*Cos(explode\angle)
				explode\y=explode\y+explode\power*Sin(explode\angle)
				explode\angle=explode\angle-15
			EndIf


Especially that last but one line.


SheepOnMintSauce(Posted 2005) [#4]
After waking up in the middle of the night, and jotting a few things down on a notepad. I think I've got it sussed.

I've added

If explode\angle<=90 Or explode\angle>=450
				explode\x=explode\x+explode\power*Cos(explode\angle)
				explode\y=explode\y+explode\power*Sin(explode\angle)
			Else
				explode\x=explode\x+explode\power*Cos(explode\angle)
				explode\y=explode\y+explode\power*Sin(explode\angle)
				If explode\angle<270
					explode\angle=90
				ElseIf explode\angle>270
					explode\angle=90
				ElseIf explode\angle=270
					explode\angle=90
				EndIf
			EndIf


It now seems to look similar to exploding lemmings. Just not quite right.


VP(Posted 2005) [#5]
I remember Lemmings on the Amiga and the explosion effect had nothing at all to do with sines and cosines during the explosion. Use them to precalculate the start-points, nothing else.

I believe this is what you're looking for:

**EDIT** Obviously, change the writepixel to a rect and replace the argb% with separate r% g% and b% values.

This is about the most expandable and fastest way I can think of to accomplish the effect you needed. I took a shortcut with precalculating the explosion, the initial veocities for the particles depend solely on the starting position. I think that works quite well though.

**EDIT #2** Giving the lemmings their own x and y coords and having the particles x and y separate is a good idea if you want to impletement this in a real game.

**EDIT #3** The way the explosion is calculated is just by creating a 180 degree arc so that it is more or less symmetrical. This means it looks good with only a few particles (no lopsided explosions). With too many particles, you can see that it just forms a semi-circular explosion.

To get the 180 degree arc, I just divided 180 degrees into EXPLOSION_PARTICLES% which is a constant (needs to be!).



For an explanation on the use of Types, please see http://www.blitzbasic.com/Community/posts.php?topic=51581


sswift(Posted 2005) [#6]
I think you're might be going about this wrong. You should probably use vectors. It makes everything much simpler.

A vector is like a line pointing in a direction with an arrow on one end. You can imagine the starting point of the vector is at 0,0 which is the center of whatever object you are moving.

So:

Cx, Cy = The center of your lemming.
Px, Py = The location of the pixel.

Each pixel in the lemming should fly away from the center.

The direction it goes is defined by a vector.
That vector will be pointing in the same direction as the point is in relation to the center of the lemming.

So, we calculate our vector like so:

Vx# = Px# - Cx#
Vy# = Py# - Cy#

Then, we need to normalize our vector. Normalizing means making the vector's length equal 1. We do this so we can use it as a direction, and multiply it by a speed to tell us how far to move the pixel.

Get the length of the vector:
D# = Sqr(Vx#^2 + Vy#^2)

And divide the X and Y components of the vector by the length:
Nx# = Vx# / D#
Ny# = Vy# / D#

If we now calculate D again we would get 1. We now have a NORMAL.

The normal tells us how far and in which direction the point should move on each axis for each 1 unit of speed.

If we want to the pixel to move at 10 pixels per second, we multiply Nx and Ny by 10, and then add Nx and Ny to the position of our pixel each frame.

Anyway, we now have a normal for each pixel. Calculate this and put it in your type. In addition, store a value Speed#.

You may want to store the value D# which you calculate when creating your normal, in Speed#. You may want to multiply it by some constant though. If you do this, then pixels which are 4 pixela away from the center of the lemming will move at a speed of 4 pixels per second away from the center. Pixels near the center will not move as quickly. This will look realistic and cool. If you multiply it by like 10, that is. So:

Pixel\Speed# = D# * 10.0

Once you have stored all your pixels in your type, loop through them each frame, and move them like so:

Pixel\Px# = Pixel\Px# + (Pixel\Nx# * Pixel\Speed# * SecondsPassed#)
Pixel\Py# = Pixel\Py# + (Pixel\Ny# * Pixel\Speed# * SecondsPassed#)

SecondsPassed# is the number of seconds the last frame took to render.

To calculate it, store the time at which the last frame was rendered, and subtract that from the tme at which the current frame is being rendered. That is the number of milliseconds which has passed. Divide this number by 1000 to get the number of seconds, which will be much less than 1.0.

Like so:
SecondsPassed# = Float(MillisecondsPassed) / 1000.0

There's one other major thing you need to do though. If you just do the above, everything will fly out from the center, but never fall. You need to add gravity.

Before moving the pixel each frame, add gravity to it's normal and speed like so:

Vx# = Pixel\Nx# * Pixel\Speed#
Vy# = Pixel\Ny# * Pixel\Speed#

Vy# = Vy# + Gravity#*SecondsPassed#

Then convert back to speed and direction like so:

Pixel\Speed# = Sqr(Vx#^2 + Vy#^2)

Pixel\Nx# = Vx# / Pixel\Speed#
Pixel\Ny# = Vy# / Pixel\Speed#

THEN move the pixel.

Now the center pixels will just fall from where they are, and the putside ones will fly out with great force, and then fall.


VP(Posted 2005) [#7]
sswift: Pretty sure that Psygnosis weren't calculating square roots for their lemming explosions, not on a 7MHz Amiga ;)

Nice solution though.


SheepOnMintSauce(Posted 2005) [#8]
Cor! That looks loads better! It also looks more like the lemmings I remember now too.

I'll have a look through that code, and try to figure out how it all fits together. Thanks! =)


VP(Posted 2005) [#9]
If you want to ask how or why concerning any of the code, I'll be at the keyboard for most of the day ;)


SheepOnMintSauce(Posted 2005) [#10]
After reading through it, it's fairly straight forward. Although the first line..

Const EXPLOSION_PARTICLES% = 10  -1


..has me a bit puzzled. Is the -1 meant to be there? If so, what does it do? I took EXPLOSION_PARTICLES% as being 10 when I looked through the code.


VP(Posted 2005) [#11]
That's just a habit of mine. I like to make my code as readable as possible. I read that line as:

EXPLOSION_PARTICLES% gives me 10 when using an array.



octothorpe(Posted 2005) [#12]
sswift: I think trig is a simpler.

vinylpusher: Personally, I prefer:

Const EXPLOSION_PARTICLES% = 10
Dim startexplosion_x#(EXPLOSION_PARTICLES - 1)
For i = 0 to EXPLOSION_PARTICLES - 1
etc.

Finally, here's my remix of vinylpusher's code:




VP(Posted 2005) [#13]
Hmm, yes. You've removed the distinction between an explosion and the particles associated with it.

Your version is nicer to read and easier to follow. I had the Lemmings game in mind when I was scribbling my code. Could expand my code quite nicely into an unlimited Lemming state machine thingy without too much head-scratching.

Yours as well, of course, but I still like mine ;)


Damien Sturdy(Posted 2005) [#14]
Hmm

Why would you NEED to do any SQRing?


You could cheat and just use

CX#=Rnd(-1,1):CY#=RND(.2,1)
[code]

For each pixel and just use
[code]
cy#=cy#-.1


on each frame which adds gravity.


I will code it a bit simpler later, its not difficult at all and i dont understand why Sswift is using SQR and squaring at all, though his general technique is goo.


sswift(Posted 2005) [#15]
You don't NEED to use square root, but if you want to do things the RIGHT way, you should. :-)


Damien Sturdy(Posted 2005) [#16]
Don't need to do things the Right way for it to look good! ;)

[edit]

By the way- I meant Good, not goo :)


octothorpe(Posted 2005) [#17]
You've removed the distinction between an explosion and the particles associated with it.


Once an explosion has occurred, I can't think of any reason to need to know which particles came from which lemming or vice versa. Also, the lemming that exploded will likely no longer exist. ;)

Each pixel in the lemming should fly away from the center.


Oh, I somehow missed this statement. sswift is going for a completely different effect than the rest of us. It's been too long since I played the game, so I don't recall which is correct (I'm betting on sswift though.) An alternate approach would involve Atan() to find the angle to the pixel, then Sin() and Cos(). sswift's method (involving Sqr()) is probably simpler.


sswift(Posted 2005) [#18]
Here is a picture of a lemming exploding:
http://home.wanadoo.nl/lemmings-solution/lemmings/images/lemmings%20tricky/18%20-%20It's%20Lemmingentry%20Watson.gif

Apparently whatever dirt they take out is also part of the explosion. That means that the center of the explosion must be below the surface of the ground beneath the lemming.


Leto(Posted 2006) [#19]
Hey thanks for these little explosion effects! Quite useful even to apply to a single object, giving it a random angle.