Page 1 of 1

Particles question

Posted: Sun Aug 14, 2005 5:07 pm
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?

Posted: Sun Aug 14, 2005 6:24 pm
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:

Posted: Sun Aug 14, 2005 7:22 pm
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.

Posted: Sun Aug 14, 2005 7:50 pm
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:

Posted: Sun Aug 14, 2005 7:56 pm
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

Posted: Sun Aug 14, 2005 8:03 pm
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

Posted: Mon Aug 15, 2005 12:31 am
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


Posted: Mon Aug 15, 2005 2:20 am
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

Posted: Mon Aug 15, 2005 3:13 am
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

Posted: Mon Aug 15, 2005 3:24 am
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!

Posted: Mon Aug 15, 2005 4:01 am
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:

Posted: Mon Aug 15, 2005 4:05 am
by Dare2
lol. And pretty neat!

Edit: re Q: nvm :) worked it out.

Posted: Mon Aug 15, 2005 8:01 am
by va!n
@Fou-Lu:
Very amazing! Cool work! Keep it on... :wink:

Posted: Mon Aug 15, 2005 11:36 am
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]

Posted: Mon Aug 15, 2005 3:01 pm
by Fou-Lu
That wouldn`t be hard... I`ll try when I`ve got time.