@blueznl: Well, this should get you started...but let me digress for a moment. I noticed that SetFrameRate() also eats up the CPU time and by using the method demonstrated in the following code, it is also unnecessary.
I realized after the former comment I posted that all the work I was going through to determine the display frequency wasn't needed (though I suceeded in doing it anyway). bluznl you had found the method for me by using ExamineDesktops() and DesktopFrequency(). Again, if I had only found those sooner.
So what I will end up demonstrating is only a lazy, but precise timer to use with FlipBuffers(#PB_Screen_WaitSynchronization). The timing method was given in the link that Kaeru had posted and no doubt it has been shown elsewhere as well. It uses API functions to change the timing resolution of Delay() as well as needing a high performance timer. If need be you may be able to do away with the high performance timer. The method gives away program time while it waits for the next screen refresh. When the time gets close it then sits and waits until it is refreshed. The result is it shares time with other programs, doesn't hog the CPU (good for laptop batteries too) and avoids tears and screwy sprite animations.
I decided to post the demonstration with your code instead. I didn't mess with the code too much, though I did add a few things. When you run it you can push "+" to add more sprites up to the maximum of 1000 or push "-" to take sprites away. With 1000 sprites it uses only about 38% of the CPU and with 10 it uses 6%.
When you test it tell me if you can let your ship sit there on the screen with trying to dodge something. There's no collision detection, so no worries.
Code: Select all
;most of game code is blueznl's
;Demivec (added screen timing method) and the code marked with ;---start ;---stop
Enumeration
#w_main
;
#f_exit
#f_none
;
#i_arrow ; image used for player
#i_rock1 ; image used for rock1
#i_rock2 ; image used for rock2
#i_rock3 ; image used for rock3
;
EndEnumeration
;
Global i_arrow_h.l
;
Structure spr
alive.l ; set to #false to disable this sprite
sprite2d_nr.l ; 2d sprite used
sprite3d_nr.l ; 3d sprite used
a.f ; object orientation
Rotation.f ; rotation speed in degrees / second, does not affect vector
Z.f ; object size factor (1 = original size)
x.f ; x-coordinate
y.f ; y-coordinate
w.l ; width in pixels
h.l ; height in pixels
v_angle.f ; vector angle in degrees
v_speed.f ; speed in pixels per second
v_mode.l ; #true to use vector, #false to use x / y components
v_x.f ; horizontal speed in pixels per second
v_y.f ; same vertical
EndStructure
;--start (deals with timing method)
Global highPerfTimerFreq.q ;holds frequency of the high performance timer
Define prevEndOfFrame.q, timer.q
Define ticksToWait.q, ticksPassed.q, i.l, gapTicks.q
Define.l framerate, timeGap
QueryPerformanceFrequency_(@highPerfTimerFreq.q)
If highPerfTimerFreq = 0
MessageRequester("Warning:","High performance timer not available",0)
End
EndIf
;this will enable finer resolution of time when using Delay(), must use timeEndPeriod_(1) before program ends
timeBeginPeriod_(1)
gapTicks = (highPerfTimerFreq * 10) / 1000 ;this is 10 ms to shorten the wait time by, just to be safe
QueryPerformanceCounter_(@timer)
prevEndOfFrame = timer
;--stop
;
InitSprite()
InitSprite3D()
InitKeyboard()
;
ExamineDesktops()
framerate = DesktopFrequency(0)
;--start (deals with timing method)
ticksToWait = highPerfTimerFreq / framerate - gapTicks
;--stop
framelength.f = 1 / framerate ; time per frame in seconds
; Debug framerate
;
screen_w.l = 1280 ; screen width
screen_h.l = 1024 ; screen height
screen_z.l = 32 ; color depth
OpenScreen(screen_w,screen_h,screen_z,"SpriteEngine")
;SetFrameRate(framerate)
;
; sorry, no luck with windowed screens yet...
;
; screen_w.l = 800
; screen_h.l = 600
; screen_z.l = 32
; w_main_h.l = OpenWindow(#w_main,10,10,screen_w,screen_h,"SpriteEngine",#PB_Window_ScreenCentered)
; OpenWindowedScreen(w_main_h,0,0,screen_w,screen_h,0,0,0)
; SetFrameRate(framerate)
;
Sprite3DQuality(0)
;
; player sprite
;
#spr_player = 0
;
i_arrow_h = CreateImage(#i_arrow,32,32,32)
StartDrawing(ImageOutput(#i_arrow))
Box(0,0,31,31,RGB(0,0,0))
FrontColor(RGB(0,255,0))
LineXY(2,30,16,2)
LineXY(16,2,30,30)
LineXY(30,30,16,8)
LineXY(16,8,2,30)
StopDrawing()
;
CreateSprite(#spr_player,32,32,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(#spr_player))
DrawImage(i_arrow_h,0,0)
StopDrawing()
CreateSprite3D(#spr_player,#spr_player)
;
;--start
; rock sprites
;
#spr_rock1 = 1
i_rock1_h = CreateImage(#i_rock1,128,128,32)
StartDrawing(ImageOutput(#i_rock1))
Box(0,0,127,127,RGB(0,0,0))
FrontColor(RGB(255,255,255))
LineXY(14,38,14,73):LineXY(15,39,15,73):LineXY(16,40,16,73)
LineXY(14,73,40,112):LineXY(15,73,40,111):LineXY(16,73,40,110):LineXY(17,73,41,110)
LineXY(40,112,78,98):LineXY(40,111,78,97):LineXY(40,110,78,96)
LineXY(78,98,90,111):LineXY(78,97,90,110):LineXY(78,96,90,109):LineXY(79,96,91,109)
LineXY(90,111,112,86):LineXY(90,110,111,86):LineXY(90,109,110,86):LineXY(89,109,109,86)
LineXY(112,86,79,63):LineXY(111,86,78,63):LineXY(110,86,78,62):LineXY(108,86,76,62)
LineXY(79,63,112,50):LineXY(78,63,111,50):LineXY(78,62,110,50):LineXY(78,61,110,49)
LineXY(112,50,112,39):LineXY(111,50,111,39):LineXY(110,50,110,39)
LineXY(112,39,77,14):LineXY(111,39,77,15):LineXY(110,39,77,16)
LineXY(77,14,39,14):LineXY(77,15,40,15):LineXY(77,16,41,16)
LineXY(39,14,51,38):LineXY(40,15,52,39):LineXY(41,16,53,40)
LineXY(51,38,14,38):LineXY(52,39,15,39):LineXY(53,40,16,40)
StopDrawing()
;
CreateSprite(#spr_rock1,128,128,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(#spr_rock1))
DrawImage(i_rock1_h,0,0)
StopDrawing()
;
#spr_rock2 = 2
i_rock2_h = CreateImage(#i_rock2,128,128,32)
StartDrawing(ImageOutput(#i_rock2))
Box(0,0,127,127,RGB(0,0,0))
FrontColor(RGB(255,255,255))
LineXY(14,41,14,88):LineXY(15,41,15,88):LineXY(16,40,16,88)
LineXY(14,88,36,110):LineXY(15,88,36,109):LineXY(16,88,36,108)
LineXY(36,110,78,110):LineXY(36,109,78,109):LineXY(37,108,79,108)
LineXY(78,110,110,89):LineXY(78,109,109,89):LineXY(79,108,109,88):LineXY(79,107,108,88)
LineXY(110,89,98,66):LineXY(109,89,97,66):LineXY(109,88,97,65):LineXY(107,87,97,66)
LineXY(98,66,112,41):LineXY(97,66,111,41):LineXY(97,65,111,40)
LineXY(112,41,87,18):LineXY(111,41,87,19):LineXY(111,40,88,19):LineXY(109,40,87,20):LineXY(108,40,86,20)
LineXY(87,18,64,40):LineXY(87,19,64,41):LineXY(88,19,65,41):LineXY(89,19,64,43)
LineXY(64,40,38,18):LineXY(64,41,38,19):LineXY(65,41,39,19):LineXY(64,42,38,20):LineXY(63,42,37,20)
LineXY(38,18,14,41):LineXY(38,19,15,41):LineXY(39,19,17,40)
StopDrawing()
CreateSprite(#spr_rock2,128,128,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(#spr_rock2))
DrawImage(i_rock2_h,0,0)
StopDrawing()
#spr_rock3 = 3
i_rock3_h = CreateImage(#i_rock3,128,128,32)
StartDrawing(ImageOutput(#i_rock3))
Box(0,0,127,127,RGB(0,0,0))
FrontColor(RGB(255,255,255))
LineXY(14,41,25,67):LineXY(15,41,26,67):LineXY(16,41,27,67)
LineXY(25,67,14,89):LineXY(26,67,15,89):LineXY(27,67,16,89)
LineXY(14,89,39,110):LineXY(15,89,39,109):LineXY(16,89,39,108):LineXY(17,89,40,108)
LineXY(39,110,52,100):LineXY(39,109,52,99):LineXY(39,108,52,98)
LineXY(52,100,87,110):LineXY(52,99,87,109):LineXY(52,98,87,108)
LineXY(87,110,110,79):LineXY(87,109,109,79):LineXY(87,108,108,79):LineXY(87,107,107,79)
LineXY(110,79,88,54):LineXY(109,79,87,54):LineXY(108,79,86,54)
LineXY(88,54,112,40):LineXY(87,54,111,40):LineXY(86,54,110,40):LineXY(85,53,109,40)
LineXY(112,40,88,18):LineXY(111,40,88,19):LineXY(110,40,88,20):LineXY(110,41,88,21)
LineXY(88,18,64,31):LineXY(88,19,64,32):LineXY(88,20,64,33)
LineXY(64,31,39,18):LineXY(64,32,39,19):LineXY(64,33,39,20)
LineXY(39,18,14,41):LineXY(39,19,15,41):LineXY(39,20,16,41)
StopDrawing()
CreateSprite(#spr_rock3,128,128,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(#spr_rock3))
DrawImage(i_rock3_h,0,0)
StopDrawing()
;--stop
;
#spr_max = 1000
Dim spr.spr(#spr_max)
;
With spr(0)
\alive = #True
\sprite2d_nr = #spr_player
\sprite3d_nr = #spr_player
\a = 0
\Rotation = 0
\Z = 1
\x = screen_w / 2
\y = screen_h / 2
\w = SpriteWidth( \sprite2d_nr)
\h = SpriteHeight( \sprite2d_nr)
\v_angle = 0
\v_speed = 0
\v_mode.l = #False
\v_x.f = 0
\v_y.f = 0
EndWith
;--start
Procedure setRock(index.l,sprite2d.l,Size.f = 1.0)
Protected sprite3d.l
Shared spr()
sprite3d = CreateSprite3D(#PB_Any,sprite2d)
With spr(index)
\alive = #True
\sprite2d_nr = sprite2d
\sprite3d_nr = sprite3d
\a = 0
\Rotation = -0.45 / Size + 0.225 * Random(1)
If Random(1): \Rotation = -\Rotation: EndIf
\Z = 1
\x = (3 * screen_w / 10) - Random(screen_w / 5) + (Random(1) * screen_w * 0.6)
\y = (3 * screen_h / 10) - Random(screen_h / 5) + (Random(1) * screen_h * 0.6)
\w = SpriteWidth( \sprite2d_nr) * Size
\h = SpriteHeight( \sprite2d_nr) * Size
\v_angle = Random(360)
\v_speed = 75 + Random(25) / Size
\v_mode.l = #True
\v_x.f = 0
\v_y.f = 0
EndWith
EndProcedure
setRock(1,#spr_rock1)
setRock(2,#spr_rock2)
setRock(3,#spr_rock3)
setRock(4,#spr_rock1,0.5)
setRock(5,#spr_rock3,0.5)
setRock(6,#spr_rock1,0.25)
setRock(7,#spr_rock2,0.25)
setRock(8,#spr_rock3,0.25)
setRock(9,#spr_rock1,0.25)
;--stop
;
spr_number.l = 10 ; number of sprites to process
;
action = #f_none
Repeat
;
; calculate movement etc.
;
n = 0
While n < spr_number
With spr(n)
If \alive
\a = \a + \Rotation
ZoomSprite3D( \sprite3d_nr, \w, \h)
RotateSprite3D( \sprite3d_nr , \a , 0)
If \v_mode
\v_x = \v_speed * Sin( \v_angle / 180 * #PI )
\v_y = 0 - \v_speed * Cos( \v_angle / 180 * #PI )
EndIf
\x = \x + \v_x * framelength
\y = \y + \v_y * framelength
;
; wrap outside screen borders
;
If \x > screen_w + \w
\x = 0 - \w
ElseIf \x < 0 - \w
\x = screen_w + \w
EndIf
If \y > screen_h + \h
\y = 0 - \h
ElseIf \y < 0 - \h
\y = screen_h + \h
EndIf
;
EndIf
EndWith
n = n+1
Wend
;
; display all active sprites
;
ClearScreen(0)
Start3D()
n = 0
While n < spr_number
With spr(n)
If \alive
DisplaySprite3D( \sprite3d_nr , \x , \y , 255)
EndIf
EndWith
n = n+1
Wend
Stop3D()
;
;FlipBuffers(#PB_Screen_WaitSynchronization)
;--start (deals with timing method)
While 1
QueryPerformanceCounter_(@timer);
ticksPassed = timer - prevEndOfFrame
timeGap = ticksToWait - ticksPassed
If timer < prevEndOfFrame Or timeGap <= 0: Break: EndIf
If (timeGap > highPerfTimerFreq * 1 / 1000)
Delay(1)
Else
For i = 0 To 9
Delay(0) ; causes thread to give up its timeslice
Next
EndIf
Wend
; ** the rest will wait FlipBuffers
FlipBuffers(#PB_Screen_WaitSynchronization)
prevEndOfFrame = timer
;--stop
;
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Escape)
action = #f_exit
EndIf
If KeyboardPushed(#PB_Key_Add)
If spr_number < #spr_max
sprite.l = Random(2)
Select sprite
Case 0
sprite = #spr_rock1
Case 1
sprite = #spr_rock2
Case 2
sprite = #spr_rock3
EndSelect
Select Random(6)
Case 0
setRock(spr_number,sprite)
Case 1,2
setRock(spr_number,sprite,0.5)
Default
setRock(spr_number,sprite,0.25)
EndSelect
spr_number + 1
EndIf
EndIf
If KeyboardPushed(#PB_Key_Subtract)
If spr_number > 2
spr_number - 1
FreeSprite3D(spr(spr_number)\sprite3d_nr)
spr(spr_number)\alive = 0
EndIf
EndIf
With spr(0)
;
; move the player object using A / W / S / D / UP / DN / LFT / RGHT
;
If KeyboardPushed(#PB_Key_Left)
\Rotation = \Rotation - 10 * framelength ; with inertia
; \a = \a - 300 * framelength ; without inertia
ElseIf KeyboardPushed(#PB_Key_Right)
\Rotation = \Rotation + 10 * framelength
; \a = \a + 300 * framelength
ElseIf KeyboardPushed(#PB_Key_Up)
\v_x = \v_x + 500 * Sin( \a / 180 * #PI ) * framelength
\v_y = \v_y - 500 * Cos( \a / 180 * #PI ) * framelength
ElseIf KeyboardPushed(#PB_Key_Down)
\v_x = \v_x - 100 * Sin( \a / 180 * #PI ) * framelength
\v_y = \v_y + 100 * Cos( \a / 180 * #PI ) * framelength
ElseIf KeyboardPushed(#PB_Key_A)
; \x = \x - 100 * framelength ; without inertia
\v_x = \v_x - 100 * framelength ; with inertia
ElseIf KeyboardPushed(#PB_Key_D)
; \x = \x + 100 * framelength
\v_x = \v_x + 100 * framelength
ElseIf KeyboardPushed(#PB_Key_W)
; \y = \y - 100 * framelength
\v_y = \v_y - 100 * framelength
ElseIf KeyboardPushed(#PB_Key_S)
; \y = \y + 100 * framelength
\v_y = \v_y + 100 * framelength
EndIf
EndWith
;
Until action = #f_exit
CloseScreen()
;--start (deals with timing method)
timeEndPeriod_(1)
;--stop