Particles question
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Particles question
I want to create an explosion similar in type to what you see in fireworks displays. I have a sprite I want to blow up by having it suddenly disappear and be replaced by a brief particle explosion but I don't know how to go about it. Can anyone give me some direction, possibly a simple example?
BERESHEIT
- Fou-Lu
- Enthusiast
- Posts: 201
- Joined: Tue Jul 12, 2005 8:30 am
- Location: I'm pretty sure this is all a nightmare
- Contact:
You should use a Structure with all variables your particles will use. Then you create a linked list, and everytime you need to add a particle, you add an new element. You can then draw all of them at once. Here's an example:
And you could use sprites instead of the plot command. 
Code: Select all
InitMouse()
InitSprite()
Structure mydot
x.f
y.f
u.f
v.f
life.f
EndStructure
NewList dot.mydot()
id=OpenWindow(1,0,0,640,480,#PB_Window_ScreenCentered,"Boom")
OpenWindowedScreen(id,0,0,640,480,0,0,0)
Repeat
ExamineMouse()
If MouseButton(1) And mousepress=0
mousepress=1
For g=0 To 199
AddElement(dot())
angle.f=Random(359)*3.141592/180
dot()\life=1+Random(254)
dot()\u=Cos(angle)*g/(dot()\life*50)
dot()\v=Sin(angle)*g/(dot()\life*50)
dot()\x=MouseX()+dot()\u*(g-100)
dot()\y=MouseY()+dot()\v*(g-100)
Next g
ElseIf MouseButton(1)=0:mousepress=0:EndIf
ClearScreen(0,0,0)
StartDrawing(ScreenOutput())
Plot(MouseX(),MouseY(),255)
ForEach dot()
dot()\x=dot()\x+dot()\u*dot()\life
dot()\y=dot()\y+dot()\v*dot()\life
If dot()\x=>0 And dot()\x<=639 And dot()\y=>0 And dot()\y<=479
c=dot()\life
c=c+c<<8+c<<16
Plot(dot()\x,dot()\y,c):EndIf
dot()\life=dot()\life-1:If dot()\life<=0:DeleteElement(dot()):EndIf
Next
StopDrawing()
FlipBuffers()
Until MouseButton(2)

- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Thanks very much!! That is quite close to what I'm looking for. The only effect I want that the example doesn't do is applying gravity to the particles so that they bust out and gradually sink, fireworks-style. I could probably figure it out on my own with time and effort, but my math is weak and you can probably just tell me what to add. Also, I noticed that the example dies if you press the left mouse button more than once. With the debugger turned on it doesn't die. I couldn't figure out why that is happening. Thanks again for your help.
BERESHEIT
- Fou-Lu
- Enthusiast
- Posts: 201
- Joined: Tue Jul 12, 2005 8:30 am
- Location: I'm pretty sure this is all a nightmare
- Contact:
It will close only if you press the right mouse button, but you can press the left button as many times as you want, at least, in my pc...
Here's a new example with gravity.
I put the \gr field in the structure. Normally it wouldn't be necessary, but the maths got kind of confused...
But it's not that hard:
~First you put the particles at the mouse position. (\x and \y)
~Then you set their x speed (\u) and y speed (\v). Use Sin and Cos to make to do that using an angle value.
~Last, you have a \life field that diminishes till it reaches zero, then the particle is deleted.
If you look my code you will see I do a lot of other crazy things:
dot()\u=Cos(angle)*g/(dot()\life*50)
dot()\x=dot()\x+dot()\u*dot()\life
You don't need to make things so complicated, I just made this way to get a random result. Try this code, you will understand it better:
See, you don't even need the \gr field, just increase the \v (which moves the particle vertically). 
Here's a new example with gravity.
Code: Select all
InitMouse()
InitSprite()
Structure mydot
x.f
y.f
u.f
v.f
life.f
gr.b
EndStructure
NewList dot.mydot()
id=OpenWindow(1,0,0,640,480,#PB_Window_ScreenCentered,"Boom")
OpenWindowedScreen(id,0,0,640,480,0,0,0)
Repeat
ExamineMouse()
If MouseButton(1) And mousepress=0
mousepress=1
For g=0 To 199
AddElement(dot())
angle.f=Random(359)*3.141592/180
dot()\life=1+Random(254)
dot()\u=Cos(angle)*g/(dot()\life*50)
dot()\v=Sin(angle)*g/(dot()\life*50)
dot()\x=MouseX()+dot()\u*(g-100)
dot()\y=MouseY()+dot()\v*(g-100)
dot()\gr=-32
Next g
ElseIf MouseButton(1)=0:mousepress=0:EndIf
ClearScreen(0,0,0)
StartDrawing(ScreenOutput())
Plot(MouseX(),MouseY(),255)
ForEach dot()
dot()\gr=dot()\gr+1
dot()\x=dot()\x+dot()\u*dot()\life
dot()\y=dot()\y+dot()\v*dot()\life+dot()\gr/10
If dot()\x=>0 And dot()\x<=639 And dot()\y=>0 And dot()\y<=479
c=dot()\life
c=c+c<<8+c<<16
Plot(dot()\x,dot()\y,c):EndIf
dot()\life=dot()\life-1:If dot()\life<=0:DeleteElement(dot()):EndIf
Next
StopDrawing()
FlipBuffers()
Until MouseButton(2)
But it's not that hard:
~First you put the particles at the mouse position. (\x and \y)
~Then you set their x speed (\u) and y speed (\v). Use Sin and Cos to make to do that using an angle value.
~Last, you have a \life field that diminishes till it reaches zero, then the particle is deleted.
If you look my code you will see I do a lot of other crazy things:
dot()\u=Cos(angle)*g/(dot()\life*50)
dot()\x=dot()\x+dot()\u*dot()\life
You don't need to make things so complicated, I just made this way to get a random result. Try this code, you will understand it better:
Code: Select all
InitMouse()
InitSprite()
Structure mydot
x.f
y.f
u.f
v.f
life.f
EndStructure
NewList dot.mydot()
id=OpenWindow(1,0,0,640,480,#PB_Window_ScreenCentered,"Boom")
OpenWindowedScreen(id,0,0,640,480,0,0,0)
Repeat
ExamineMouse()
If MouseButton(1) And mousepress=0
mousepress=1
For g=0 To 199
AddElement(dot())
angle.f=Random(359)*3.141592/180
dot()\life=1+Random(254)
dot()\u=Cos(angle)*random(128)/64
dot()\v=Sin(angle)*random(128)/64
dot()\v=dot()\v-2 ;this will make it go up
dot()\x=MouseX()
dot()\y=MouseY()
Next g
ElseIf MouseButton(1)=0:mousepress=0:EndIf
ClearScreen(0,0,0)
StartDrawing(ScreenOutput())
Plot(MouseX(),MouseY(),255)
ForEach dot()
dot()\x=dot()\x+dot()\u
dot()\y=dot()\y+dot()\v
dot()\v=dot()\v+0.05
If dot()\x=>0 And dot()\x<=639 And dot()\y=>0 And dot()\y<=479
c=dot()\life
c=c+c<<8+c<<16
Plot(dot()\x,dot()\y,c):EndIf
dot()\life=dot()\life-1:If dot()\life<=0:DeleteElement(dot()):EndIf
Next
StopDrawing()
FlipBuffers()
Until MouseButton(2)

- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Thanks again, Fou-Lou. Fabulous piece of code.
Here is a silly little program I made just to test how to implement the particle explosions in an actual game:
Here is a silly little program I made just to test how to implement the particle explosions in an actual game:
Code: Select all
InitSprite()
Structure mydot
x.f
y.f
u.f
v.f
life.f
s.f
EndStructure
NewList dot.mydot()
OpenWindow(1,0,0,640,480,#PB_Window_ScreenCentered,"Boom")
OpenWindowedScreen(WindowID(1),0,0,640,480,0,0,0)
Procedure BlowemUp(spotx,spoty)
For g=0 To 500
AddElement(dot())
angle.f=Random(359)*3.141592/180
dot()\life=1+Random(254)
dot()\u=Cos(angle)*Random(128)/64
dot()\v=Sin(angle)*Random(128)/64
dot()\v=dot()\v-1 ;this will make it go up
dot()\x=spotx
dot()\y=spoty
dot()\s=Random(15)/10
Next g
EndProcedure
myx=0:myy=200:myx2=620
Repeat
If GetAsyncKeyState_(#VK_ESCAPE)<>0
End
EndIf
ClearScreen(0,0,0)
StartDrawing(ScreenOutput())
If CountList(dot())<100
Circle(myx,myy,20,RGB(0,0,255))
If myx>200
Circle(myx2,myy,5,RGB(255,0,0))
EndIf
Else
myx=0:myy=200:myx2=619
EndIf
ForEach dot()
dot()\x=dot()\x+dot()\u
dot()\y=dot()\y+dot()\v
dot()\v=dot()\v+0.05
If dot()\x=>0 And dot()\x<=639 And dot()\y=>0 And dot()\y<=478
c=dot()\life
c=c+c<<8+c<<16
Circle(dot()\x,dot()\y,dot()\s,c)
EndIf
dot()\life=dot()\life-1:If dot()\life<=0:DeleteElement(dot()):EndIf
Next
StopDrawing()
FlipBuffers()
Delay(1)
myx+1
If myx>200
myx2-12
EndIf
If myx >619
myx=0
EndIf
If myx >= myx2-20
BlowemUp(myx+10,myy+10)
EndIf
ForEver
End
Last edited by netmaestro on Sat Aug 27, 2005 7:04 am, edited 2 times in total.
BERESHEIT
- Fou-Lu
- Enthusiast
- Posts: 201
- Joined: Tue Jul 12, 2005 8:30 am
- Location: I'm pretty sure this is all a nightmare
- Contact:
Very nice! I loved it.
And it was a good idea use circles instead of plots.
But if you want to use circles you should create sprites and draw the circles before. The way I've shown you uses the drawing comands, and they are very slow. Try this:
I changed your code a bit. Now it should be faster. You could also try with sprite 3D, you'll get some nice effects. I'll see if I can make an example to show you. 

And it was a good idea use circles instead of plots.
But if you want to use circles you should create sprites and draw the circles before. The way I've shown you uses the drawing comands, and they are very slow. Try this:
Code: Select all
InitSprite()
Structure mydot
x.f
y.f
u.f
v.f
life.f
EndStructure
NewList dot.mydot()
Procedure BlowemUp(spotx,spoty)
For g=0 To 500
AddElement(dot())
angle.f=Random(359)*3.141592/180
dot()\life=1+Random(254)
dot()\u=Cos(angle)*Random(128)/64
dot()\v=Sin(angle)*Random(128)/64
dot()\v=dot()\v-1 ;this will make it go up
dot()\x=spotx+dot()\u*Random(32)
dot()\y=spoty +dot()\v*Random(32)
Next g
EndProcedure
OpenWindow(1,0,0,640,480,#PB_Window_ScreenCentered,"Boom")
OpenWindowedScreen(WindowID(1),0,0,640,480,0,0,0)
myx=0:myy=200:myx2=620
;Let's make some sprites
;the blue circle
CreateSprite(256,40,40)
StartDrawing(SpriteOutput(256))
Circle(20,20,20,255<<16)
StopDrawing()
;the red circle
CreateSprite(257,10,10)
StartDrawing(SpriteOutput(257))
Circle(5,5,5,255)
StopDrawing()
;the circles for explosions
For g=1 To 255
c=g*2:If c>255:c=255:EndIf
c=c+c<<8+c<<16
CreateSprite(g,8,8)
StartDrawing(SpriteOutput(g))
Circle(4,4,1+g*3/255,c)
StopDrawing()
Next g
Repeat
If GetAsyncKeyState_(#VK_ESCAPE)<>0
End
EndIf
ClearScreen(0,0,0)
If CountList(dot())<100
DisplayTransparentSprite(256,myx-20,myy-20)
If myx>200
DisplayTransparentSprite(257,myx2-5,myy-5)
EndIf
Else
myx=0:myy=200:myx2=619
EndIf
ForEach dot()
dot()\x=dot()\x+dot()\u
dot()\y=dot()\y+dot()\v
dot()\v=dot()\v+0.05
If dot()\x=>0 And dot()\x<=639 And dot()\y=>0 And dot()\y<=478
DisplayTransparentSprite(dot()\life,dot()\x-4,dot()\y-4)
EndIf
dot()\life=dot()\life-1:If dot()\life<=0:DeleteElement(dot()):EndIf
Next
FlipBuffers()
Delay(1)
myx+1
If myx>200
myx2-6
EndIf
If myx >619
myx=0
EndIf
If myx >= myx2-20
BlowemUp(myx+10,myy+10)
EndIf
ForEver
End

- Fou-Lu
- Enthusiast
- Posts: 201
- Joined: Tue Jul 12, 2005 8:30 am
- Location: I'm pretty sure this is all a nightmare
- Contact:
Here's the example with sprite 3D. This one is really cool

Code: Select all
InitSprite()
InitSprite3D()
Structure mydot
x.f
y.f
u.f
v.f
life.w
s.w
EndStructure
NewList dot.mydot()
Procedure BlowemUp(spotx,spoty) ;changed that a bit :)
For g=0 To 400
AddElement(dot())
angle.f=Random(359)*3.141592/180
dot()\life=1+Random(254)
dot()\u=Cos(angle)*Random(128)/64
dot()\v=Sin(angle)*Random(128)/64
dot()\v=dot()\v-1 ;this will make it go up
dot()\x=spotx+dot()\u*Random(16)
dot()\y=spoty+dot()\v*Random(16)
dot()\s=Random(7)+1
Next g
For g=1 To 100
AddElement(dot())
angle.f=Random(359)*3.141592/180
dot()\life=1+Random(254)
dot()\u=Cos(angle)*Random(128)/16
dot()\v=Sin(angle)*Random(128)/256
dot()\v=dot()\v-2
dot()\x=spotx-dot()\u*4
dot()\y=spoty
dot()\s=Random(3)+1
Next g
EndProcedure
OpenWindow(1,0,0,640,480,#PB_Window_ScreenCentered,"Boom")
OpenWindowedScreen(WindowID(1),0,0,640,480,0,0,0)
myx=0:myy=200:myx2=620
;Let's make some sprites
;the blue circle
CreateSprite(256,40,40)
StartDrawing(SpriteOutput(256))
Circle(20,20,20,255<<16)
StopDrawing()
;the red circle
CreateSprite(257,10,10)
StartDrawing(SpriteOutput(257))
Circle(5,5,5,255)
StopDrawing()
;the circles for explosions (just one sprite 3d)
CreateSprite(1,16,16,#pb_sprite_texture)
StartDrawing(SpriteOutput(1))
For nx=-8 To 7
For ny=-8 To 7
blue=255-(32*Sqr(nx*nx+ny*ny)):If blue<0:blue=0:EndIf
green=blue*2:If green>255:green=255:EndIf
red=blue*4:If red>255:red=255:EndIf
c=red+green<<8+blue<<16
Plot(nx+8,ny+8,c)
Next ny
Next nx
StopDrawing()
CreateSprite3D(1,1)
Repeat
If GetAsyncKeyState_(#VK_ESCAPE)<>0
End
EndIf
ClearScreen(0,0,0)
If CountList(dot())<100
DisplayTransparentSprite(256,myx-20,myy-20)
If myx>200
DisplayTransparentSprite(257,myx2-5,myy-5)
EndIf
Else
myx=0:myy=200:myx2=619
EndIf
Start3D()
Sprite3DBlendingMode(7,7)
ForEach dot()
dot()\x=dot()\x+dot()\u
dot()\y=dot()\y+dot()\v
dot()\v=dot()\v+0.05
iy.f=dot()\life/dot()\s/8
ix.f=iy+Abs(dot()\u)
TransformSprite3D(1,-ix,-iy,ix,-iy,ix,iy,-ix,iy)
DisplaySprite3D(1,dot()\x,dot()\y,dot()\life)
dot()\life=dot()\life-1:If dot()\life<=0:DeleteElement(dot()):EndIf
Next
Stop3D()
FlipBuffers()
Delay(1)
myx+1
If myx>200
myx2-6
EndIf
If myx >619
myx=0
EndIf
If myx >= myx2-20
BlowemUp(myx+10,myy+10)
EndIf
ForEver
End
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
- Fou-Lu
- Enthusiast
- Posts: 201
- Joined: Tue Jul 12, 2005 8:30 am
- Location: I'm pretty sure this is all a nightmare
- Contact:
netmaestro wrote:You just have to picture in your mind that the blue circle is filled with propane and the red one is packed with dynamite and then you are at least partly prepared for that explosion! Neat!


-
- PureBasic Expert
- Posts: 2812
- Joined: Fri Apr 25, 2003 4:51 pm
- Location: Portugal, Lisbon
- Contact:
Ehehe...
Neat, we now have explosions with and without gravity...
Only thing missing is a view from above / circular (fire like) explosion...
[/b]
Neat, we now have explosions with and without gravity...
Only thing missing is a view from above / circular (fire like) explosion...
Code: Select all
* * * * * *
* * * * * *
* * * * * *