Particles question

Just starting out? Need help? Post your questions and find answers here.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Particles question

Post by netmaestro »

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
User avatar
Fou-Lu
Enthusiast
Enthusiast
Posts: 201
Joined: Tue Jul 12, 2005 8:30 am
Location: I'm pretty sure this is all a nightmare
Contact:

Post by Fou-Lu »

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:

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)
And you could use sprites instead of the plot command. :wink:

~Fou-Lu (aka Lørd Cinneris (actually Elias Sant'Ana))

Image Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

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
User avatar
Fou-Lu
Enthusiast
Enthusiast
Posts: 201
Joined: Tue Jul 12, 2005 8:30 am
Location: I'm pretty sure this is all a nightmare
Contact:

Post by Fou-Lu »

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.

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)
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:

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)
See, you don't even need the \gr field, just increase the \v (which moves the particle vertically). :wink:

~Fou-Lu (aka Lørd Cinneris (actually Elias Sant'Ana))

Image Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

That is perfect! Exactly what I wanted. If you ever need a hand with something, just let me know and I'll get somebody who knows how to do stuff to help you :D
BERESHEIT
User avatar
Fou-Lu
Enthusiast
Enthusiast
Posts: 201
Joined: Tue Jul 12, 2005 8:30 am
Location: I'm pretty sure this is all a nightmare
Contact:

Post by Fou-Lu »

Ok, be sure I'll ask! :P
And if you are making a game I want to play it! Mail me it when it's done! :D

~Fou-Lu (aka Lørd Cinneris (actually Elias Sant'Ana))

Image Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

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:

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
User avatar
Fou-Lu
Enthusiast
Enthusiast
Posts: 201
Joined: Tue Jul 12, 2005 8:30 am
Location: I'm pretty sure this is all a nightmare
Contact:

Post by Fou-Lu »

Very nice! I loved it. :wink:
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 
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. :P

~Fou-Lu (aka Lørd Cinneris (actually Elias Sant'Ana))

Image Image
User avatar
Fou-Lu
Enthusiast
Enthusiast
Posts: 201
Joined: Tue Jul 12, 2005 8:30 am
Location: I'm pretty sure this is all a nightmare
Contact:

Post by Fou-Lu »

Here's the example with sprite 3D. This one is really cool 8)

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

~Fou-Lu (aka Lørd Cinneris (actually Elias Sant'Ana))

Image Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

That is pretty cool. 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!
BERESHEIT
User avatar
Fou-Lu
Enthusiast
Enthusiast
Posts: 201
Joined: Tue Jul 12, 2005 8:30 am
Location: I'm pretty sure this is all a nightmare
Contact:

Post by Fou-Lu »

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!
:lol: I was wondering what where those balls made of. Now, let's make a green one and fill it with plutonium to see what happens. :shock:

~Fou-Lu (aka Lørd Cinneris (actually Elias Sant'Ana))

Image Image
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

lol. And pretty neat!

Edit: re Q: nvm :) worked it out.
@}--`--,-- A rose by any other name ..
va!n
Addict
Addict
Posts: 1104
Joined: Wed Apr 20, 2005 12:48 pm

Post by va!n »

@Fou-Lu:
Very amazing! Cool work! Keep it on... :wink:
va!n aka Thorsten

Intel i7-980X Extreme Edition, 12 GB DDR3, Radeon 5870 2GB, Windows7 x64,
Num3
PureBasic Expert
PureBasic Expert
Posts: 2812
Joined: Fri Apr 25, 2003 4:51 pm
Location: Portugal, Lisbon
Contact:

Post by Num3 »

Ehehe...

Neat, we now have explosions with and without gravity...

Only thing missing is a view from above / circular (fire like) explosion...

Code: Select all


 * *       *    *           *      *
*   *    *        *     *              *
 * *       *    *           *      *

[/b]
User avatar
Fou-Lu
Enthusiast
Enthusiast
Posts: 201
Joined: Tue Jul 12, 2005 8:30 am
Location: I'm pretty sure this is all a nightmare
Contact:

Post by Fou-Lu »

That wouldn`t be hard... I`ll try when I`ve got time.

~Fou-Lu (aka Lørd Cinneris (actually Elias Sant'Ana))

Image Image
Post Reply