Page 1 of 1

The starfield! I broke it :(

Posted: Thu May 12, 2011 7:44 pm
by Nituvious
I got to thinking "how do those guys make their particle engines? They look so neat!" and figured the first step would be the common starfield program. So I gave it shot. At first I was going to use a list, but failed. Then I used an array and failed with results.

It makes some pretty neat effects but it's definitely not a random particle generator. I don't know why, I guess this is because I am unable to generate a random float. How would I make a Random float, anyway?

Code: Select all

If Not InitSprite()
	End
EndIf

Declare Stars(count.l)
mainWindow = OpenWindow(#PB_Any, 0,0,500,500,"Failed Starfield", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(mainWindow), 0,0,500,500,1,0,0)

Repeat : Delay(1)
	eventID = WaitWindowEvent(1)
	ClearScreen(RGB(0,0,0))
	
	Stars(2000)
	
	FlipBuffers()

Until eventID = #PB_Event_CloseWindow

Procedure Stars(count.l)
	Structure obj
		a.f
		x.l
		layer.b
		y.l
		speed.f
	EndStructure
	Static Dim Star.obj(1)
	Static initiated.l,sprite0,sprite1,sprite2, sprite3, circumference
	ReDim Star.obj(count.l)
	
	If initiated.l = #True		
		For y = 0 To count.l-1
			If Star(y)\x <= 490 And Star(y)\x >= 10 And Star(y)\y <= 490 And Star(y)\y >= 10
				Star(y)\x = Star(y)\x + (Star(y)\speed * Cos(Star(y)\a.f))
				Star(y)\y = Star(y)\y + (Star(y)\speed * Sin(Star(y)\a.f))
			Else
				Star(y)\a = 0.01 + Random(360) / 47.123
				Star(y)\speed = 1+Random(10)
				Star(y)\x = 250
				Star(y)\y = 250
			EndIf
			If Star(y)\layer = 0 : DisplaySprite(sprite0,Star(y)\x, Star(y)\y)
			ElseIf Star(y)\layer = 1 : DisplaySprite(sprite1,Star(y)\x, Star(y)\y)
			ElseIf Star(y)\layer = 2 : DisplaySprite(sprite2,Star(y)\x, Star(y)\y)
			ElseIf Star(y)\layer = 3 : DisplaySprite(sprite3,Star(y)\x, Star(y)\y)
			EndIf
		Next y

	Else
		sprite0 = CreateSprite(#PB_Any, 2,2)
		StartDrawing(SpriteOutput(sprite0)) : Box(0,0,2,2,RGB(255,255,255)) : StopDrawing()
		sprite1 = CreateSprite(#PB_Any, 2,2)
		StartDrawing(SpriteOutput(sprite1)) : Box(0,0,2,2,RGB(200,200,200)) : StopDrawing()
		sprite2 = CreateSprite(#PB_Any, 2,2)
		StartDrawing(SpriteOutput(sprite2)) : Box(0,0,2,2,RGB(150,150,150)) : StopDrawing()
		sprite3 = CreateSprite(#PB_Any, 2,2)
		StartDrawing(SpriteOutput(sprite3)) : Box(0,0,2,2,RGB(100,100,100)) : StopDrawing()

		For z = 0 To count.l-1
			Star(z)\layer = Random(3)
			Star(z)\speed = 0.1+Random(10)
			Star(z)\a = 0.01 + Random(360) / 47.123
		Next z
		initiated.l = #True
	EndIf
EndProcedure

Re: The starfield! I broke it :(

Posted: Thu May 12, 2011 8:09 pm
by TomS
First of all, I would use Sin() and Cos().
So that you get a nice circle.

Second: The "stars" need to get faster towards the edge. Right now they have a linear speed.
Think of it like a racing car that drives by in front of you with 200 M/h and another car with the same speed, but several miles away.

Having never done something like this before, this are the only contributions I can make right now.

Re: The starfield! I broke it :(

Posted: Thu May 12, 2011 11:20 pm
by djes
It's nice to see that, it makes me fly in the past :)

The only thing to know to achieve this effect is a simple perspective algo. The easiest comes from a formula

Code: Select all

XScreen = X / Z
YScreen = Y / Z
Actually, we can go farther (by memory) :

Code: Select all

XScreen = (X * DistFromCamera) / (DistFromCamera + PerspectiveRatio + Z) 
YScreen = (Y * DistFromCamera) / (DistFromCamera + PerspectiveRatio + Z) 
I let you do the rest by yourself :)

Re: The starfield! I broke it :(

Posted: Fri May 13, 2011 4:54 am
by Demivec
Nituvious wrote:It makes some pretty neat effects but it's definitely not a random particle generator. I don't know why, I guess this is because I am unable to generate a random float. How would I make a Random float, anyway?
Random float

Code: Select all

x.f = Offset.f + Random(Range) * Scale.f    ;formula
y.f = Random(500) * 1/1000                  ;example use of formula

Re: The starfield! I broke it :(

Posted: Fri May 13, 2011 7:03 am
by Kukulkan
This is what I did a few years ago (forum search helped me to find):

Code: Select all

; 3D-Stars (V. Schmid) 
Dim Punkte.f(2000,3)    ; Punkte mit X,Y und Z Koordinaten 
Dim BildPixel.l(2000,2) ; Berechnete Bildpunkte 
Dim d.l(3)              ; Hilfsvariable 
Dim Fluchtpunkt.f(3)    ; Fluchtpunktkoordinaten (X,Y,Z) 
; 
Global PKTAnz.l 
Global Counter.f 
; 
PKTAnz.l = 2000 
; Sterne generieren (zufällige Koordinaten) 
For x.l = 1 To PKTAnz.l 
  Punkte(x.l, 1) = Random(2000) - 1000 ; X 
  Punkte(x.l, 2) = Random(2000) - 1000 ; Y 
  Punkte(x.l, 3) = Random(2000) ; Z 
Next 
; 
If InitKeyboard() = 0 Or InitMouse() = 0 Or InitSprite() = 0 
  MessageRequester("Error", "Kann nicht initialisieren!") 
  End 
EndIf 
; 
; Initialisieren 
Fluchtpunkt(1) = 0    ; X 
Fluchtpunkt(2) = 0    ; Y 
Fluchtpunkt(3) = 2000 ; Z 
ZEbene.l = 1540 
; Welche Richtung wird gerade bewegt? 
BewegeX.b = 0 
BewegeY.b = 0 
BewegeZ.b = 1 
; 
If OpenScreen(1024, 768, 16, "Stars") 
  xOffset.l = 512 
  yOffset.l = 384 
  ExamineKeyboard()
  While KeyboardPushed(#PB_Key_Escape) = 0 
    FlipBuffers() 
    ClearScreen(RGB(0,0,0))

    ; Sterne bewegen 
    For x.l = 1 To PKTAnz.l 
      ; Z-Koordinaten der Sterne 
      If BewegeZ.b = 1 
        Punkte(x.l, 3) = Punkte(x.l, 3) + 5 
        If Punkte(x.l, 3) > 2000: Punkte(x.l, 3) = 0: EndIf 
      EndIf 
      ; Y-Koordinaten der Sterne 
      If BewegeY.b = 1 
        Punkte(x.l, 2) = Punkte(x.l, 2) + 5 
        If Punkte(x.l, 2) > 1000: Punkte(x.l, 2) = -1000: EndIf 
      EndIf 
      ; X-Koordinaten der Sterne 
      If BewegeX.b = 1 
        Punkte(x.l, 1) = Punkte(x.l, 1) - 5 
        If Punkte(x.l, 1) < -1000: Punkte(x.l, 1) = 1000: EndIf 
      EndIf 
    Next 
    
    ; Transfer der Sterne nach 2D 
    For x.l = 1 To PKTAnz.l 
      For j.l = 1 To 3 
        d(j.l) = Fluchtpunkt(j.l) - Punkte(x.l, j.l) 
      Next 
      Lambda.f = (ZEbene.l - Punkte(x.l, 3)) / d(3) 
      BildPixel(x.l, 1) = xOffset.l + Punkte(x.l, 1) + Lambda.f * d(1) ; X 
      BildPixel(x.l, 2) = yOffset.l + Punkte(x.l, 2) + Lambda.f * d(2) ; Y 
    Next 
    
    ; Zeichnen der Sterne 
    StartDrawing(ScreenOutput()) 
    
    
    Counter.f = Counter.f + 0.005; only used, if you uncomment the three lines later...
     
    If Counter.f > 3.1415 * 2: Counter.f = 0: EndIf 
    For x.l = 1 To PKTAnz.l 
      If BildPixel(x.l, 1) > 0 And BildPixel(x.l, 1) < 1023 And BildPixel(x.l, 2) > 0 And BildPixel(x.l, 2) < 767 
        Farbe.l = Punkte(x.l, 3) / 8 
        If Farbe.l > 100 
          ; Stern 
          Farbwert2.l = RGB(Farbe.l - 60,Farbe.l - 60,Farbe.l - 60) 
          Plot(BildPixel(x.l, 1), BildPixel(x.l, 2), RGB(Farbe.l, Farbe.l, Farbe.l)) 
          Plot(BildPixel(x.l, 1) - 1, BildPixel(x.l, 2), Farbwert2.l) 
          Plot(BildPixel(x.l, 1) + 1, BildPixel(x.l, 2), Farbwert2.l) 
          Plot(BildPixel(x.l, 1), BildPixel(x.l, 2) - 1, Farbwert2.l) 
          Plot(BildPixel(x.l, 1), BildPixel(x.l, 2) + 1, Farbwert2.l) 
        Else 
          ; Punkt 
          Plot(BildPixel(x.l, 1), BildPixel(x.l, 2), RGB(Farbe.l, Farbe.l, Farbe.l)) 
        EndIf 
      EndIf 
    Next 
    StopDrawing() 
    
    ; Tasten für Ein-Auschalten der Richtungen 
    
    ;--------- these control left, right up down movement
    If KeyboardPushed(#PB_Key_X) 
      BewegeX.b = BewegeX.b + 1: If BewegeX.b = 2: BewegeX.b = 0:EndIf 
      Delay(150) 
    EndIf 
    
    If KeyboardPushed(#PB_Key_Y) 
      BewegeY.b = BewegeY.b + 1: If BewegeY.b = 2: BewegeY.b = 0:EndIf 
      Delay(150) 
    EndIf 
    
    If KeyboardPushed(#PB_Key_Z) 
      BewegeZ.b = BewegeZ.b + 1: If BewegeZ.b = 2: BewegeZ.b = 0:EndIf 
      Delay(150) 
    EndIf 
    
    ; Fluchtpunkt nach Maus ausrichten 
    ;------- this controls the stars by the mouse
    Fluchtpunkt(1) = Fluchtpunkt(1) + MouseDeltaX() 
    Fluchtpunkt(2) = Fluchtpunkt(2) + MouseDeltaY() 
    
    ; Fluchtpunkt(1) = Fluchtpunkt(1) + Sin(Counter.f)*2 
    ; Fluchtpunkt(2) = Fluchtpunkt(2) + Cos(Counter.f)*2 
    ; Fluchtpunkt(3) = Fluchtpunkt(3) + Sin(Counter.f)*2 
    
    ; Tastatur abfragen 
    ExamineKeyboard() 
    ExamineMouse() 
  Wend 
  CloseScreen() 
  End 
Else 
  MessageRequester("Error", "Kann Bildschirm nicht öffnen!") 
EndIf
Runs out of the box on 4.51. Sadly, the comments are in german...

Kukulkan

Re: The starfield! I broke it :(

Posted: Sun May 15, 2011 6:25 am
by Rook Zimbabwe
RANDOM FLOAT GENERATOR
This is my heavy handed method!

Code: Select all

Enumeration
  #Window_0
EndEnumeration
;}
;{ Gadgets
Enumeration
  #Button_0
  #String_1
EndEnumeration
;}
Define.l Event, EventWindow, EventGadget, EventType, EventMenu
;}
Procedure OpenWindow_Window_0()
  If OpenWindow(#Window_0, 450, 200, 400, 164, "Window_0", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_TitleBar)
    ButtonGadget(#Button_0, 10, 80, 370, 60, "FLOAT ME")
    StringGadget(#String_1, 10, 15, 365, 30, "Gadget_1")
  EndIf
EndProcedure

OpenWindow_Window_0()

;{- Event loop
Repeat
  Event = WaitWindowEvent()
  Select Event
    ; ///////////////////
    Case #PB_Event_Gadget
      EventGadget = EventGadget()
      EventType = EventType()
      If EventGadget = #Button_0
        num1 = Random(100)
        num2 = Random(10)
        num$ = Str(num1)
        numSTR$ = "0."+num$
        newvalu.f = ValF(numSTR$)
        newfloat.f = num2+newvalu.f
        output$ = StrF(newfloat.f,3)
        SetGadgetText(#String_1, output$)
      EndIf
    ; ////////////////////////
    Case #PB_Event_CloseWindow
      EventWindow = EventWindow()
      If EventWindow = #Window_0
        CloseWindow(#Window_0)
        Break
      EndIf
  EndSelect
ForEver
Coded in PureFORM

Re: The starfield! I broke it :(

Posted: Sun May 15, 2011 6:32 am
by kenmo
Rook Zimbabwe wrote:RANDOM FLOAT GENERATOR
This is my heavy handed method!
So heavy! Why not something like

Code: Select all

output$ = StrF(Random(10000)/1000,3)

Re: The starfield! I broke it :(

Posted: Sun May 15, 2011 6:26 pm
by Nituvious
kenmo wrote:
Rook Zimbabwe wrote:RANDOM FLOAT GENERATOR
This is my heavy handed method!
So heavy! Why not something like

Code: Select all

output$ = StrF(Random(10000)/1000,3)
Hi Kenmo! I took your code and turned it into a function like the original Random.

Code: Select all

Procedure.f RandomF(max.l)
	result.f = ValF(StrF(Random(max.l*1000)/1000))
	ProcedureReturn result.f	
EndProcedure

Repeat
	r.f = Randomf(10) ; 100)
	Debug r.f
Until r.f >= 9.9 ; 99.9)
Debug "done"

Re: The starfield! I broke it :(

Posted: Sun May 15, 2011 6:36 pm
by djes
Believe me, you don't want a "good" random function. Why? Because no random function can assure you that two stars will not be next each other. What you want is a linear function assuring you that stars are at a sufficient distance one from the others, and a random sort to disperse them.

Re: The starfield! I broke it :(

Posted: Mon May 16, 2011 1:41 am
by kenmo
@djes - That's a good point. But if you are using a large number of stars (100? 1000? more???) I think the distribution might be fine, since a few next to each other wouldn't really be noticeable (especially in motion).

@Nituvious - You could include an offset too, like Demivec posted above, or even a Min and Max, like I posted in this thread: http://www.purebasic.fr/english/viewtop ... ndom+float

Re: The starfield! I broke it :(

Posted: Thu May 26, 2011 1:15 pm
by Nituvious
kenmo wrote:@Nituvious - You could include an offset too, like Demivec posted above, or even a Min and Max, like I posted in this thread: http://www.purebasic.fr/english/viewtop ... ndom+float

Code: Select all

10+RandomF(20)
:twisted: