News:

Building a 3D Ray Tracer  By stevmjon

Main Menu

Odd starfield behaviour.

Started by hatonastick, August 20, 2006, 07:01:11 AM

Previous topic - Next topic

hatonastick

[EDIT] Erm just solved my own question.  Changed the angle, the star x/y storage to Floating Point.  Forgot that GM uses Doubles as standard, and that I had the same issue when I converted this for PureBASIC.  Is it worth me pre-calc'ing the Cos and Sine tables?  PlayBASIC seems so fast to me that its pointless.
----
Ok I must be rustier than I first thought.  I can't see anything wrong with the following code.  It runs fine, but when you use the left and right cursor to spin it around, for some reason some of the stars seem to become out of sync at certain angles.  They are fine at 0, 90, 180, 270, but some other angles they move a little strangely ie. one lot moves in the correct direction, the rest move at odd angles.  So I'm guessing I've forgotten to take something into account with my code.  You may have to play with it a little bit to see what I'm getting at.  I do not believe this to be the fault of PlayBASIC - it's definitely user error.

; PROJECT : StarPilot
; AUTHOR  : Jazz Davis
; CREATED : 19/08/2006
; EDITED  : 20/08/2006

; Notes -----------------------------------------------------------------------

; Originally started in GameMaker, and then converted to PlayBASIC.

; Variables -------------------------------------------------------------------

; Screen width
Constant SW = 800
; Screen height
Constant SH = 600
; Player
Global PlayerX = SW/2
Global PlayerY = SH/2
Global PlayerSpeed = 0
Global PlayerDirection = 90
; Starfield settings
Constant StarsMinSpeed = 1
Constant StarsMaxSpeed = 4
Constant StarsTotal = 800
; Starfield data
Dim StarX(StarsTotal)
Dim StarY(StarsTotal)
Dim StarSpeed(StarsTotal)
Dim StarColour(StarsTotal)

; Setup -----------------------------------------------------------------------

; Set the screen size and refresh rate
OpenScreen SW,SH,16,1
;SetFPS 100
TitleScreen "StarPilot v0.1a"
; Initialise the RNG
Randomize 1234
; Initialise the starfield
InitStarField(StarsTotal,StarsMinSpeed,StarsMaxSpeed)

; Game loop -------------------------------------------------------------------

Do
; Clear the screen to black
Cls RGB(0,0,0)

; Draw starfield
DrawStarField(PlayerDirection)

CheckKeyboard()

; Display current FPS
Print FPS()

; Display the screen
Sync

Loop

; Functions -------------------------------------------------------------------

; Initalise starfield
; No pre-calcs this time because PB is so lightening quick it doesn't need it
Function InitStarField(amount,min,max)
For i = 0 To amount Step 1
StarX(i) = Rnd(SW)
StarY(i) = Rnd(SH)
StarSpeed(i) = Rnd(max-min) + min
; We want grey scale without having stars too dark to see.
; So colour range is forced into the 61 - 255 bracket.
c = 60 + Rnd(195)
StarColour(i) = RGB(c,c,c)
Next i
EndFunction

; Starfield display routine
Function DrawStarField(direction)
; We lock the screen buffer for drawing, to speed it all up
LockBuffer
For i = 0 To StarsTotal Step 1
; Move the star in the given direction and the given speed
StarX(i) = StarX(i) - (StarSpeed(i) * Cos(direction))
StarY(i) = StarY(i) - (StarSpeed(i) * Sin(direction))
; If star has moved off screen, relocate it
If StarX(i) < 0
StarX(i) = SW
StarY(i) = Rnd(SH)
ElseIf StarX(i) >= SW
StarX(i) = 0
StarY(i) = Rnd(SH)
EndIf
If StarY(i) < 0
StarY(i) = SH
StarX(i) = Rnd(SW)
ElseIf StarY(i) >= SH
StarY(i) = 0
StarX(i) = Rnd(SW)
EndIf
; Set the drawing colour
Ink StarColour(i)
; Draw the star
Dot StarX(i),StarY(i)
Next i
UnLockBuffer
EndFunction

; Load our sprites
Function LoadSprites()
EndFunction

; Check for keyboard input (surprise!)
Function CheckKeyboard()
; Update angle depending on keys pushed
if RightKey() = 1
PlayerDirection = WrapAngle(PlayerDirection,2)
elseif LeftKey() = 1
PlayerDirection = WrapAngle(PlayerDirection,-2)
endif
EndFunction
Matthew 5:14-16

kevin


The stars X+Y positions will need to be stored as floating point.  Above their stored in integer arrays. 
So this

Dim StarX(StarsTotal)
Dim StarY(StarsTotal)

Should be

Dim StarX#(StarsTotal)
Dim StarY#(StarsTotal)


Use replace to change them. Ie. replace 'StarX('   with 'StarX#('


kevin


Here's a quick rehash..  I've just shuffled the star routine around a little.  Since effectively operations on variables the quickest operation available in PB.  So therefore it's often more economical to stores calculations in temp variables than writnig them back into the array.  In particular if the results have to be scrutinized.  Well clipped in this case.




; AUTHOR  : Jazz Davis
; CREATED : 19/08/2006
; EDITED  : 20/08/2006

; Notes -----------------------------------------------------------------------

; Originally started in GameMaker, and then converted to PlayBASIC.

; Variables -------------------------------------------------------------------

; Screen width
Constant SW = 800
; Screen height
Constant SH = 600
; Player
Global PlayerX = SW/2
Global PlayerY = SH/2
Global PlayerSpeed = 0
Global PlayerDirection = 90
; Starfield settings
Constant StarsMinSpeed = 1
Constant StarsMaxSpeed = 4
Constant StarsTotal = 800
; Starfield data
Dim StarX#(StarsTotal)
Dim StarY#(StarsTotal)
Dim StarSpeed(StarsTotal)
Dim StarColour(StarsTotal)

; Setup -----------------------------------------------------------------------

; Set the screen size and refresh rate
OpenScreen SW,SH,16,1
;SetFPS 100
TitleScreen "StarPilot v0.1a"
; Initialise the RNG
Randomize 1234
; Initialise the starfield
InitStarField(StarsTotal,StarsMinSpeed,StarsMaxSpeed)

; Game loop -------------------------------------------------------------------

Do
; Clear the screen to black
Cls RGB(0,0,0)

; Draw starfield
DrawStarField(PlayerDirection)

CheckKeyboard()

; Display current FPS
Print FPS()

; Display the screen
Sync

Loop

; Functions -------------------------------------------------------------------

; Initalise starfield
; No pre-calcs this time because PB is so lightening quick it doesn't need it
Function InitStarField(amount,min,max)
For i = 0 To amount Step 1
StarX#(i) = Rnd(SW)
StarY#(i) = Rnd(SH)
StarSpeed(i) = Rnd(max-min) + min
; We want grey scale without having stars too dark to see.
; So colour range is forced into the 61 - 255 bracket.
c = RndRange(60,255)
StarColour(i) = RGB(c,c,c)
Next i
EndFunction

; Starfield display routine
Function DrawStarField(direction)
; We lock the screen buffer for drawing, to speed it all up
LockBuffer

; precalc the Cos+Sino Values
SpeedX#=Cos(Direction)
SpeedY#=Sin(Direction)

For i = 0 To StarsTotal ;Step 1  << Step #1 is the default loop increase

StarSpeed#=StarSpeed(i)

; Move the star in the given direction and the given speed
X# = StarX#(i) - (SpeedX#*StarSpeed#)
Y# = StarY#(i) - (SpeedY#*StarSpeed#)

; Check is the point is outside the Screen ?
if PointInBox(x#,y#,0,0,sw,sh)=false
; If star has moved off screen, relocate it
If X# < 0
X# = SW
Y# = Rnd(SH)
ElseIf X# >= SW
X# = 0
Y# = Rnd(SH)
EndIf
If Y# < 0
Y# = SH
X# = Rnd(SW)
ElseIf Y# >= SH
Y# = 0
X# = Rnd(SW)
EndIf
endif
; Draw the star
DotC X#,Y#,StarColour(i)

; Store the point's new position
StarX#(i)=X#
StarY#(i)=Y#

Next i

UnLockBuffer
EndFunction

; Load our sprites
Function LoadSprites()
EndFunction

; Check for keyboard input (surprise!)
Function CheckKeyboard()
; Update angle depending on keys pushed
if RightKey() = 1
PlayerDirection = WrapAngle(PlayerDirection,2)
elseif LeftKey() = 1
PlayerDirection = WrapAngle(PlayerDirection,-2)
endif
EndFunction



hatonastick

Ok thanks for the tips!  This is the latest version (which I've just updated to use what you gave me above).  However I'm not sure I've got the understanding of how you handle animation and sprites.  Any further suggestions for improvements on what I've got here?  I know this currently is over-simplistic and doesn't allow for a lot of things.  I think I know how I could expand it so we shall see how I go with that.

; PROJECT : StarPilot
; AUTHOR  : Jazz Davis
; CREATED : 19/08/2006
; EDITED  : 21/08/2006

; Notes -----------------------------------------------------------------------

; Originally started in GameMaker, and then converted to PlayBASIC.

; Variables -------------------------------------------------------------------

; Screen width
Constant SW = 600
; Screen height
Constant SH = 600

; Player
Type PlayerData
X
Y
Speed#
Angle#
Frame
Mode
EndType
Dim Player as PlayerData

; Starfield settings
Constant StarsMinSpeed = 2
Constant StarsMaxSpeed = 8
Constant StarsTotal = 800
; Starfield data
Type StarData
X#
Y#
Speed#
Colour
EndType
Dim Starfield(StarsTotal) as StarData

; Setup -----------------------------------------------------------------------

; Set the screen size and refresh rate
OpenScreen SW,SH,16,1
ScreenVSync On
SetFPS 100
TitleScreen "StarPilot v0.1a"

; Initialise the RNG
Randomize 1234

; Initialise the starfield
InitStarField(StarsTotal,StarsMinSpeed,StarsMaxSpeed)

; Load our graphics
LoadSprites()

; Redirect all drawing to the screen (apparently)
RenderToScreen

; Main game loop --------------------------------------------------------------

Do
; Clear the screen to black
Cls 0

; Draw starfield
DrawStarField(Player.Angle#)

; Does exactly what it says it does
CheckKeyboard()

; Display current FPS
Print "FPS: "+str$(FPS())

; Draw player on the screen
DrawPlayer()

; Display the screen
Sync

;Wait 0
Loop

; Functions -------------------------------------------------------------------

; Initalise starfield
; No pre-calcs this time because PB is so lightening quick it doesn't need it
Function InitStarField(amount,min,max)
For i = 0 To amount
Starfield(i).X# = Rnd(SW)
Starfield(i).Y# = Rnd(SH)
Starfield(i).Speed# = Rnd(max-min) + min
; We want grey scale without having stars too dark to see.
; So colour range is forced into the 61 - 255 bracket.
c = 60 + Rnd(195)
Starfield(i).Colour = RGB(c,c,c)
Next i
EndFunction

; Starfield display routine
Function DrawStarField(direction#)
; We lock the screen buffer for drawing, to speed it all up
LockBuffer
; Pre-calc the cos and sine values
SpeedX# = Cos(direction#)
SpeedY# = Sin(direction#)
; Update starfield array
For i = 0 To StarsTotal
; Calculating using variables is faster than arrays.
StarSpeed# = Starfield(i).Speed#
; Move the star in the given direction and the given speed
X# = Starfield(i).X# - (StarSpeed# * SpeedX#)
Y# = Starfield(i).Y# - (StarSpeed# * SpeedY#)
; Has star moved off of the screen?
if PointInBox(X#,Y#,0,0,SW,SH) = false
; If star has moved off screen, relocate it
If X# < 0
X# = SW
Y# = Rnd(SH)
ElseIf X# >= SW
X# = 0
Y# = Rnd(SH)
EndIf
If Y# < 0
Y# = SH
X# = Rnd(SW)
ElseIf Y# >= SH
Y# = 0
X# = Rnd(SW)
EndIf
EndIf
; Draw the star
DotC X#,Y#,Starfield(i).Colour
; Update the starfield entry
Starfield(i).X# = X#
Starfield(i).Y# = Y#
Next i
UnLockBuffer
EndFunction

; Load our images and create our sprites
Function LoadSprites()
; Players Ship - flying straight
; Load player animation frame 1 into image index 1
LoadImage CurrentDir$()+".\Graphics\PS1.bmp",1
; Set image index 1 as "useable with special FX"
PrepareFXImage 1
LoadImage CurrentDir$()+".\Graphics\PS2.bmp",2
PrepareFXImage 2
; Players Ship - turning left
LoadImage CurrentDir$()+".\Graphics\PSL1.bmp",3
PrepareFXImage 3
LoadImage CurrentDir$()+".\Graphics\PSL2.bmp",4
PrepareFXImage 4
; Players Ship - turning right
LoadImage CurrentDir$()+".\Graphics\PSR1.bmp",5
PrepareFXImage 5
LoadImage CurrentDir$()+".\Graphics\PSR2.bmp",6
PrepareFXImage 6

; Create player sprite
CreateSprite 1
; Turn on autocenter for sprite
AutoCenterSpriteHandle 1,True
; Assign our first animation frame image to the sprite
Player.Frame = 1
SpriteImage 1,Player.Frame
; Set sprite draw mode to rotation
SpriteDrawMode 1,2
; Place player in the middle of the screen
Player.X = SW/2
Player.Y = SH/2
PositionSprite 1,Player.X,Player.Y
; Set starting movement angle
Player.Angle# = 270
; Set player starting mode ie. moving forwards
Player.Mode = 1
EndFunction

; Draw player sprite on screen
Function DrawPlayer()
; Update animation frame depending on player mode
; 0 = Forwards
; 1 = Turning Left
; 2 = Turning Right
Select Player.Mode
Case 0
if Player.Frame = 1
Player.Frame = 2
else
Player.Frame = 1
endif
Case 1
if Player.Frame = 3
Player.Frame = 4
else
Player.Frame = 3
endif
Case 2
if Player.Frame = 5
Player.Frame = 6
else
Player.Frame = 5
endif
EndSelect
; Set our current frame of animation
SpriteImage 1,Player.Frame

; Rotate sprite and draw
RotateSprite 1,Player.Angle#
DrawSprite 1
EndFunction

; Check for keyboard input (surprise!)
Function CheckKeyboard()
; Update angle depending on keys pushed
if LeftKey() = 1
Player.Angle# = WrapAngle(Player.Angle#,-2)
Player.Mode = 1
elseif RightKey() = 1
Player.Angle# = WrapAngle(Player.Angle#,2)
Player.Mode = 2
else
Player.Mode = 0
endif
EndFunction


Here's the above plus the required media if you require it:
http://jazz.hal9000.net.au/files/SPPB.zip
Matthew 5:14-16

kevin


Looks cool. 

  To save yourself a little work. Anything code/process that your find yourself  using a lot, it's well worth rolling it into a function.

  Eg.

  Stuff like the frame loading code could be





  LoadFXImage(".\Graphics\PS1.bmp",1)
  LoadFXImage(".\Graphics\PS2.bmp",2)
  LoadFXImage(".\Graphics\PSl1.bmp",3)
  LoadFXImage(".\Graphics\PSl2.bmp",4)
  LoadFXImage(".\Graphics\PSR1.bmp",5)
  LoadFXImage(".\Graphics\PSR2.bmp",6)


etc etc


Function LoadFXImage(Filename$,index)
LoadImage CurrentDir$()+Filename$,index
; Set image index 1 as "useable with special FX"
PrepareFXImage index
EndFUnction



stef

Hi!

Looks great and promisingly!

Greetings
stef

Ian Price

Seems like you're picking up PB pretty quickly! Excellent work

Incidently, you don't need the RenderToScreen command - all drawing is done to the screen unless specified to RenderToImage.
I came. I saw. I played some Nintendo.

hatonastick

Thanks for the suggestions guys!  Now I'm working on adding animation.  It's not going to be anything fancy though.  Was going to try and write a generic animation system, but since it sounds like there may end up being a built-in one I've decided to just make what is needed for this game.  Definitely having fun. :)
Matthew 5:14-16