smooth animation in a window - not possible?

Advanced game related topics
Thalius
Enthusiast
Enthusiast
Posts: 711
Joined: Thu Jul 17, 2003 4:15 pm
Contact:

Post by Thalius »

I also tried playing these movies in the "MoviePlayer.pb" example - they play back smoothly, but I suppose that's because they're being played back by an operating system component? I don't see any calls to FlipBuffers() in that example...
Keep in Mind that this Example along with otehr Movie Players use a Video Overlay to display Video. Which is quiet more performant than simple drawing Functions and also uses Hardware Collor Correction, Filtering, Color Format Translation ...

More Info:
http://en.wikipedia.org/wiki/Video_overlay
what is it you do differently then? if you're not using the same Win32-API workaround demonstrated here...?
:roll:

Thalius
"In 3D there is never enough Time to do Things right,
but there's always enough Time to make them *look* right."
"psssst! i steal signatures... don't tell anyone! ;)"
mp303

Post by mp303 »

Thalius wrote:Keep in Mind that this Example along with otehr Movie Players use a Video Overlay to display Video. Which is quiet more performant than simple drawing Functions and also uses Hardware Collor Correction, Filtering, Color Format Translation ...
doh. right, of course - overlays... didn't think of that.
Thalius wrote:
what is it you do differently then? if you're not using the same Win32-API workaround demonstrated here...?
:roll:
I don't get it, what's wrong with that question? is he doing something different, or does the FlipBuffers() command for some reason work "out of the box" for him? ... am I missing something here?

...

anyway, while DirectX may not be much help when it comes to windowed operation, perfect updates with GDI certainly is possible - here's an example I found:

http://www.codeproject.com/gdi/tearingfreedrawing.asp

this one works - even if I run ten of these (right-click the exe and choose "run as", otherwise only one instance will be allowed), they're all running pixel-perfect, I've been staring at them for minutes, and they never drop a frame.

and this example seems to use only GDI and creates a high-resolution timer to control the updates.

it also uses nearly no CPU at all, since it doesn't block - of course, it's using a very small window, but that just demonstrates that the timing iself is inexpensive.
Brice Manuel

Post by Brice Manuel »

mp303, I am not trying to bust your chops. I am concerned that my games could be problematic for some people, based on your experience.

I am familiar with the problem you describe as I had it with other languages over the years. I honestly haven't run into it with PB.

I have been programming since '79, but I still consider myself a newbie to PB, especially its gaming side and especially 4.0. Things are just done differently than in gaming only languages I was using before PB, and there has been a learning curve for me.
I tried "Examples/Sources/WindowedScreen.pb" which is implemented in the same way I did - which is also the way it's demonstrated in the manual. And it displays the exact same issue -
I don't have a problem with that example animation wise, but it is not hard for me to imagine that method being problematic. Due to the method being used, on all of my systems, the buttons next to the dx screen are abnormally slow to respond. Slow enough that I notice the issue (I am sure others wouldn't notice) and I don't use this method for that reason.
I couldn't find the ladybug example
http://www.reelmediaproductions.com/lady
http://www.reelmediaproductions.com/pb

The original source might be on the second link or at pure area. I use that method, but modified to support menus and buttons, etc:

Code: Select all

;============================================== 
;= LADY'S GARDEN ©2001 Reel Media Productions = 
;= programmed by Paul Leischow Sept.15 /2001 = 
;============================================== 
;= MODIFIED BY KAISER TO SHOW A MENU EXAMPLE = 
;= = 
;= I've added the Handle_Menu sub-routine to = 
;= show how can you handle window events in = 
;= the way you would do with any window. = 
;= = 
;= I added the sub-routine in every loop that = 
;= needed a FlipBuffers(), because here were = 
;= so many, but it can be used at the main = 
;= loop so you won't have problems. = 
;= = 
;============================================== 


;If InitSprite(99) = 0 Or InitKeyboard() = 0 | Removed due that it has no parameters now. 
If InitSprite() = 0 Or InitKeyboard() = 0 
MessageRequester("Error", "Can't open DirectX 7 or later", 0) 
End 
EndIf 
;If InitSound(10) = 0 | Removed due that it has no parameters now. 
If InitSound() = 0 
MessageRequester("Error", "Can't open DirectX 7 Or Sound Card is not present", 0) 
End 
EndIf 
;========SYSTEM SPECS ARE OK 


Procedure text(txtx.l,txty.l,txt.s) ;x/y screen coordinates are send along with a text string 
For tmp=1 To Len(txt) ;loop for the length of the string 
txtasc=Asc(Mid(txt,tmp,1)) ;get the ASCII value of each character in the string 
If txtasc<>32 ;if its not a space, display the sprite on the screen 
DisplayTransparentSprite(txtasc+5,txtx,txty) 
EndIf 
txtx=txtx+16 ;move the width of the sprite so we can display the next one 
Next 
txty=txty+25 ;move down to the next line 
EndProcedure 

Structure ladybug ;create a structure to hold all Lady's info 
lpx.w ;x position of Lady 
lpy.w ;y position of Lady 
lpxpos.w ;x position in the lookup table 
lpypos.w ;y position in the lookup table 
ldir.w ;direction Lady is moving 
lmove.w ;counter for movement to next tile 
lx.w ;x speed of Lady 
ly.w ;y speed of Lady 
EndStructure 

;ADDED BY KAISER 
;=========================================== 
Global DoQuit 
;=========================================== 

Global txtx.l ;x position of text 
Global txty.l ;y position of text 
Global txt.s ;string that hold text 
#mazewidth=12 ;width of maze (12 tiles) 
#mazeheight=13 ;hight of maze (13 tiles) 
level=1 ;current game level 
bugs=1 ;number of Lady bugs in the maze 
frmbee=0 ;what frame of Bee to display 
score.l=0 ;current score 

Dim lady.ladybug(4) ;set up 4 Lady bugs 
Dim maze(#mazewidth,#mazeheight) ;set up an array to hold maze tiles 
Dim track(#mazewidth,#mazeheight) ;set up an array to hold Lady movement data 

OpenWindow(100,0,0,640,480,#PB_Window_ScreenCentered | #PB_Window_SystemMenu,"Lady's Garden") 

If OpenWindowedScreen(WindowID(100),0,0,640,480,0,0,0) 
;If OpenScreen(640,480,16,"Lady's Garden") ;open a 640x480 graphic window | We don't need this, it's gonna be windowed. 

;============================= 
;Add menus (By Kaiser) 
;============================= 
CreateMenu(1,WindowID(100)) 
MenuTitle("Game") 
MenuItem(1,"New Game") 
MenuItem(2,"Load Game") 
MenuItem(3,"Save Game") 
MenuItem(4,"About") 
MenuBar() 
MenuItem(5,"Exit") 
;============================= 
;============================= 

LoadSprite(1,"data\bush1.bmp",0) ;load all the game sprites 
LoadSprite(2,"data\bush2.bmp",0) 
LoadSprite(3,"data\black.bmp",0) 
LoadSprite(4,"data\clear.bmp",0) 
LoadSprite(5,"data\flower.bmp",0) 
LoadSprite(6,"data\ladyl.bmp",0) 
LoadSprite(7,"data\ladyr.bmp",0) 
LoadSprite(8,"data\ladyu.bmp",0) 
LoadSprite(9,"data\ladyd.bmp",0) 
LoadSprite(10,"data\level.bmp",0) 
LoadSprite(11,"data\over.bmp",0) 
LoadSprite(12,"data\diz1.bmp",0) 
LoadSprite(13,"data\diz2.bmp",0) 
LoadSprite(14,"data\diz3.bmp",0) 
For tmp=20 To 59 
LoadSprite(tmp,"data\bee"+Str(tmp)+".bmp",0) ;load all the Bee sprites 
Next 
For tmp=60 To 69 
LoadSprite(tmp,"data\num"+Str(tmp)+".bmp",0) ;load all the number sprites for score 
Next 
For tmp=70 To 95 
LoadSprite(tmp,"data\a"+Str(tmp)+".bmp",0) ;load all the alphabet sprites for text 
Next 
LoadSound(1,"data\blip.wav") ;load all the sound effects 
LoadSound(2,"data\catch.wav") 
LoadSound(3,"data\level.wav") 
LoadSound(4,"data\intro.wav") 


;===========================MAINLOOP 
mainloop: 

Gosub init_data ;initialize game data / all starting positions 
Gosub load_maze ;load the first maze 
Gosub load_data ;load the first movement table 

If level=1 And bugs=1 ;if we're on level 1 and there is 1 Lady bug 
hold=0 
While hold=0 ;display instructions until space is pressed 
Gosub Handle_Menu 
DisplaySprite(4,0,0) 
text(80,90,"GUIDE BUMBLE THROUGH") 
text(80,115,"THE HEDGE MAZE AND") 
text(80,140,"PICK ALL THE FLOWERS") 
text(80,215,"IF LADY CATCHES YOU") 
text(80,240,"ITS GAME OVER") 
text(130,350,"PRESS SPACEBAR") 
frmbee=frmbee+1 
If frmbee>9:frmbee=0:EndIf ;cycle through all 9 frames of Bee flying 
DisplayTransparentSprite(frmbee+50,30,90) ;display Bee sprite 
DisplayTransparentSprite(8,30,220) ;display Lady sprite 
FlipBuffers() ;Flip screen buffer into view 
ExamineKeyboard() 
If KeyboardPushed(#PB_Key_Space) Or KeyboardPushed(#PB_Key_Escape):hold=1:EndIf 
Wend 
EndIf 
PlaySound(4) ;play starting tune 

While quit=0 
Gosub Handle_Menu 
If flower=0:quit=1:EndIf ;loop until all flowers have been collected 
ExamineKeyboard() 
If KeyboardPushed(#PB_Key_Escape):Gosub draw_credits:End:EndIf ;if ESC is pressed show credits and end 
If KeyboardPushed(#PB_Key_Left):mm=1:EndIf ;check for left/right/up/down arrows keys 
If KeyboardPushed(#PB_Key_Right):mm=2:EndIf 
If KeyboardPushed(#PB_Key_Up):mm=3:EndIf 
If KeyboardPushed(#PB_Key_Down):mm=4:EndIf 
Select mm 
Case 1 
If mve=0 And maze(cpxpos-1,cpypos)>2 ;move Bee according to the direction you've selected 
cx=-2:cy=0:cpdir=1:cpxpos=cpxpos-1:mve=32 
Gosub check_flower ;check if you've plucked any flowers along the way 
EndIf 
Case 2 
If mve=0 And maze(cpxpos+1,cpypos)>2 
cx=2:cy=0:cpdir=3:cpxpos=cpxpos+1:mve=32 
Gosub check_flower 
EndIf 
Case 3 
If mve=0 And maze(cpxpos,cpypos-1)>2 
cx=0:cy=-2:cpdir=2:cpypos=cpypos-1:mve=32 
Gosub check_flower 
EndIf 
Case 4 
If mve=0 And maze(cpxpos,cpypos+1)>2 
cx=0:cy=2:cpdir=4:cpypos=cpypos+1:mve=32 
Gosub check_flower 
EndIf 
EndSelect 
If mve<>0:cpx=cpx+cx:cpy=cpy+cy:mve=mve-2:EndIf 

Gosub move_lady ;Ladybug movement routine and AI 
Gosub draw_board ;draw the maze on the screen 
Gosub draw_bugs ;draw the Lady bugs on the screen 
Gosub set_score ;draw the score on the screen 

If quit>0 
If quit=1 ;if quit=1 then we've finished the level 
tmpy=480 ;place the 'level' sign at the bottom of screen 
PlaySound(3) 
For nextlevel=0 To 190 
Gosub Handle_Menu 
Gosub draw_board ;draw the maze on the screen 
Gosub set_score ;draw the score on the screen 
DisplaySprite(10,134,tmpy) ;draw the 'level complete' sign 
FlipBuffers() ;flip screen buffer into view 
tmpy=tmpy-3 ;move the sign up 3 pixels 
Next 
EndIf 
If quit=2:PlaySound(2):EndIf ;if quit=2 then Lady gottcha / play gottcha sound 
EndIf 

FlipBuffers() ;flip screen buffer into view 
Wend 
Else 
MessageRequester("Error","Could Not Initialize 640x480x16 Display",0) 
End 
EndIf 

If quit=2 ;Lady gottcha 
diz=0 ;current frame of dizzy bee 
Restore level1 ;reset the maze data to load level 1 
For hold=1 To 400 ;hold this screen till we count to 400 
Gosub Handle_Menu 
Gosub draw_board ;draw the maze on the screen 
Gosub set_score ;draw the score on the screen 
Gosub draw_diz ;draw the dizzy bee on the screen 
DisplaySprite(11,134,110) ;draw the game over sign 
Delay(50) ;small delay so bee doesn't flap to fast 
ExamineKeyboard() 
If KeyboardPushed(#PB_Key_Space):hold=400:Delay(500):EndIf ;press space to start again 
If KeyboardPushed(#PB_Key_Escape):Gosub draw_credits:End:EndIf ;press ESC to display credits and end 
FlipBuffers() ;flip screen buffer into view 
Next 
level=0 ;reset all data 
bugs=0 
score=0 
EndIf 
level=level+1 ;advance level 
bugs=bugs+1 ;add another Lady bug to screen 
If bugs>4:bugs=4:EndIf ;if we have 4 Lady bugs, then that's enough 
If level>4:level=1:Restore level1:EndIf ;if we've finished level 4 then start over again at level 1 
Goto mainloop 


;=============SPECIAL ROUTINES 
init_data: 
cpx=32*2 ;position Bee on the screen 
cpy=32*2 ;tiles are 32x32 so we need to multiply maze data by 32 
cpxpos=2 ;position Bee in the maze array 
cpypos=2 
cpdir=1 
cpmve=0 
cx=0 
cy=0 
quit=0 
mve=0 
mm=0 
For tmp=1 To 4 ;reset data for all 4 Lady bugs 
lady(tmp)\ldir=4 
lady(tmp)\lmove=0 
lady(tmp)\lx=0 
lady(tmp)\ly=0 
Next 
lady(1)\lpx=32*11 ;place all 4 Lady bugs in their starting positions 
lady(1)\lpy=32*12 
lady(1)\lpxpos=11 
lady(1)\lpypos=12 

lady(2)\lpx=32*11 
lady(2)\lpy=32*6 
lady(2)\lpxpos=11 
lady(2)\lpypos=6 

lady(3)\lpx=32*11 
lady(3)\lpy=32*8 
lady(3)\lpxpos=11 
lady(3)\lpypos=8 

lady(4)\lpx=32*11 
lady(4)\lpy=32*4 
lady(4)\lpxpos=11 
lady(4)\lpypos=4 
Return 

load_maze: 
For y=1 To #mazeheight ;load the maze tile data into an array 
For x=1 To #mazewidth 
Read maze(x,y) 
Next 
Next 
Read flower ;see how many flowers we need to pluck 
Return 
load_data: 
For y=1 To #mazeheight ;load Lady's movement lookup table into an array 
For x=1 To #mazewidth 
Read track(x,y) 
Next 
Next 
Return 

check_flower: 
If maze(cpxpos,cpypos)=5 ;if we've reached a flower (5) 
maze(cpxpos,cpypos)=3 ;then change it to a blank (3) 
flower=flower-1 ;decrement flower counter by 1 
score=score+5 ;increment score by 5 points 
PlaySound(1) ;play the flower plucking sound 
EndIf 
Return 

set_score: 
tempscore$=Str(score) 
If Len(tempscore$)=1:newscore$="0000"+tempscore$:EndIf ;place leading zeros in the score 
If Len(tempscore$)=2:newscore$="000"+tempscore$:EndIf 
If Len(tempscore$)=3:newscore$="00"+tempscore$:EndIf 
If Len(tempscore$)=4:newscore$="0"+tempscore$:EndIf 
If Len(tempscore$)=5:newscore$=tempscore$:EndIf 
xscore=448 ;x position to start drawing score 
For tmp=1 To Len(newscore$) ;break apart score 1 character at a time 
DisplayTransparentSprite(Val(Mid(newscore$,tmp,1))+60,xscore,200) ;and display correct sprite 
xscore=xscore+30 ;move right to draw next character 
Next 
Return 

move_lady: 
For bug=1 To bugs ;for an explaination of how this all works 
lbx.l=lady(bug)\lpxpos ;check out Paul Gerfen's tutorial at 
lby.l=lady(bug)\lpypos ;www.openrpgs.com/articles/showarticle.php?article=2001/apr/pacman 
check.l=track(lbx,lby) 

If lady(bug)\lmove=0 
Select check 
Case 1:If lady(bug)\ldir=2:lady(bug)\ldir=3:Else:lady(bug)\ldir=4:EndIf 
Case 2:If lady(bug)\ldir=3:lady(bug)\ldir=4:Else:lady(bug)\ldir=1:EndIf 
Case 3:If lady(bug)\ldir=4:lady(bug)\ldir=1:Else:lady(bug)\ldir=2:EndIf 
Case 4:If lady(bug)\ldir=1:lady(bug)\ldir=2:Else:lady(bug)\ldir=3:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=5 
Select lady(bug)\ldir 
Case 3:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=4:EndIf 
Case 2:If cpxpos<lady(bug)\lpxpos:lady(bug)\ldir=1:Else:lady(bug)\ldir=2:EndIf 
Case 4:If cpypos>lady(bug)\lpypos:lady(bug)\ldir=4:Else:lady(bug)\ldir=1:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=6 
Select lady(bug)\ldir 
Case 4:If cpxpos<lady(bug)\lpxpos:lady(bug)\ldir=1:Else:lady(bug)\ldir=3:EndIf 
Case 3:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=3:EndIf 
Case 1:If cpxpos<lady(bug)\lpxpos:lady(bug)\ldir=1:Else:lady(bug)\ldir=2:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=7 
Select lady(bug)\ldir 
Case 4:If cpxpos>lady(bug)\lpxpos:lady(bug)\ldir=3:Else:lady(bug)\ldir=4:EndIf 
Case 1:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=4:EndIf 
Case 2:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=3:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=8 
Select lady(bug)\ldir 
Case 2:If cpxpos>lady(bug)\lpxpos:lady(bug)\ldir=3:Else:lady(bug)\ldir=1:EndIf 
Case 3:If cpypos>lady(bug)\lpypos:lady(bug)\ldir=4:Else:lady(bug)\ldir=3:EndIf 
Case 1:If cpypos>lady(bug)\lpypos:lady(bug)\ldir=4:Else:lady(bug)\ldir=1:EndIf 
EndSelect 
EndIf 

Select lady(bug)\ldir 
Case 1:lady(bug)\lx=-1:lady(bug)\ly=0 
Case 2:lady(bug)\lx=0:lady(bug)\ly=-1 
Case 3:lady(bug)\lx=1:lady(bug)\ly=0 
Case 4:lady(bug)\lx=0:lady(bug)\ly=1 
EndSelect 

If lady(bug)\lmove=0 
lady(bug)\lpxpos=lady(bug)\lpxpos+lady(bug)\lx 
lady(bug)\lpypos=lady(bug)\lpypos+lady(bug)\ly 
lady(bug)\lmove=32 
EndIf 

If lady(bug)\lmove<>0 
lady(bug)\lpx=lady(bug)\lpx+lady(bug)\lx 
lady(bug)\lpy=lady(bug)\lpy+lady(bug)\ly 
lady(bug)\lmove=lady(bug)\lmove-1 
EndIf 
If cpxpos=lady(bug)\lpxpos And cpypos=lady(bug)\lpypos:quit=2:EndIf 
Next 
Return 

draw_board: 
DisplaySprite(4,0,0) ;draw background to clear the screen 
For y=1 To 13 
For x=1 To 12 
bl=maze(x,y) 
DisplaySprite(bl,x*32,y*32) ;display the maze tiles on the screen 
Next 
Next 
Return 

draw_bugs: ;draw Lady bug depending on the direction she's moving 
For bug=1 To bugs 
If lady(bug)\lx=-1:DisplayTransparentSprite(6,lady(bug)\lpx,lady(bug)\lpy):EndIf 
If lady(bug)\lx=1:DisplayTransparentSprite(7,lady(bug)\lpx,lady(bug)\lpy):EndIf 
If lady(bug)\ly=-1:DisplayTransparentSprite(8,lady(bug)\lpx,lady(bug)\lpy):EndIf 
If lady(bug)\ly=1:DisplayTransparentSprite(9,lady(bug)\lpx,lady(bug)\lpy):EndIf 
Next 
frmbee=frmbee+1 ;draw Bee depending on the direction he's moving 
If frmbee>9:frmbee=0:EndIf 
If mm=1:DisplayTransparentSprite(frmbee+30,cpx,cpy):EndIf 
If mm=2:DisplayTransparentSprite(frmbee+40,cpx,cpy):EndIf 
If mm=3:DisplayTransparentSprite(frmbee+50,cpx,cpy):EndIf 
If mm=4 Or mm=0:DisplayTransparentSprite(frmbee+20,cpx,cpy):EndIf 
Return 

draw_diz: ;draw dizzy bee looping through all 3 frames 
diz=diz+1 
If diz>3:diz=1:EndIf 
DisplayTransparentSprite(11+diz,cpx-16,cpy-16) 
Return 

draw_credits: ;draw final credits on the screen 
For tmp=0 To 480 ;have bee fly from top to bottom 
Gosub Handle_Menu 
DisplaySprite(4,0,0) 
text(40,45,"PROGRAMMER") 
text(40,70,"PAUL LEISCHOW") 
text(40,120,"GRAPHICS") 
text(40,145,"PAUL LEISCHOW") 
text(40,195,"AUDIO") 
text(40,220,"PETE ZILINSKI") 
text(40,270,"THANKS TO") 
text(40,295,"PAUL GERFEN") 
text(40,320,"FRED LABOUREUR") 
text(40,370,"COPYRIGHT") 
text(40,395,"REEL MEDIA PRODUCTIONS") 
frmbee=frmbee+1 
If frmbee>9:frmbee=0:EndIf ;loop through the 9 frames while he flys 
DisplayTransparentSprite(frmbee+20,15,tmp) ;(looks like he's flapping) 
FlipBuffers() ;flip screen buffer into view so we can see it 
Next 
Return 



Handle_Menu: 

Event=WindowEvent() 
If Event=#PB_Event_Menu 
If EventMenuID()=1 
MessageRequester("Lady's Garden","New game") 
EndIf 
If EventMenuID()=2 
MessageRequester("Lady's Garden","Load Game") 
EndIf 
If EventMenuID()=3 
MessageRequester("Lady's Garden","Save Game") 
EndIf 
If EventMenuID()=4 
MessageRequester("Lady's Garden","PureBASIC Example by Paul Leischow. Adapted to Windowed mode + a sample menu by: Kaiser") 
EndIf 
If EventMenuID()=5 ; Quit 
If quit<>2 : PlaySound(4) : EndIf 
Gosub draw_credits:End 
EndIf 
EndIf 

Return 






DataSection ;maze data and movement data for Lady 
level1: ;each level has 2 sets of maze data 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 1,3,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,2,5,1,1,5,2,2,5,1 ;1 = bush1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 ;2 = bush2 
Data.l 1,5,2,5,2,2,2,2,5,2,5,1 ;3 = no flower (space) 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 ;5 = flower 
Data.l 1,5,1,1,5,1,1,5,1,1,1,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,5,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 
Data.l 1,5,2,2,5,1,1,5,2,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 74 ;number of flowers to collect 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,0,8,0,0,8,0,0,2,0 ;movement data for Lady 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;0 = no movement decision to be made 
Data.l 0,0,0,1,6,0,0,6,2,0,0,0 ;1 = lady can move down or right 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;2 = lady can move down or left 
Data.l 0,7,0,6,8,0,0,8,6,0,3,0 ;3 = lady can move up or left 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;4 = lady can move up or right 
Data.l 0,7,0,8,6,0,0,6,8,0,2,0 ;5 = lady can move left or up or down 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;6 = lady can move up or left or right 
Data.l 0,0,0,4,8,0,0,8,3,0,0,0 ;7 = lady can move right or up or down 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;8 = lady can move down or left or right 
Data.l 0,4,0,0,6,0,0,6,0,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

;level 2 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 1,3,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 
Data.l 1,5,2,2,2,2,2,2,5,2,5,1 
Data.l 1,5,5,5,5,5,5,2,5,5,5,1 
Data.l 1,1,1,5,2,5,5,2,5,1,1,1 
Data.l 1,5,5,5,2,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,2,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 71 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,8,0,0,0,0,8,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,4,0,0,0,0,5,0,0,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,8,0,8,2,0,7,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,5,0,4,6,0,6,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,7,0,0,0,0,2,0,0,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,6,0,0,0,0,6,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

;level 3 
Data.l 1,1,1,1,1,3,3,1,1,1,1,1 
Data.l 1,3,5,5,1,3,3,1,5,5,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,2,2,2,5,1,1,1,1,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,2,5,2,2,2,5,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,5,2,2,2,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,5,5,1,3,3,1,5,5,5,1 
Data.l 1,1,1,1,1,3,3,1,1,1,1,1 
Data.l 67 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,2,0,0,0,0,1,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,7,0,6,0,0,8,0,6,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,7,0,0,8,0,6,0,8,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,0,6,8,0,0,6,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,8,0,6,0,0,8,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,3,0,0,0,0,4,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

;level 4 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 1,3,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,2,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,1,5,1,1,5,2,5,1 
Data.l 1,5,2,5,1,5,5,1,5,5,5,1 
Data.l 1,5,5,5,1,1,5,5,5,2,5,1 
Data.l 1,5,2,5,1,5,5,1,5,5,5,1 
Data.l 1,5,2,5,1,5,1,1,5,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,2,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 74 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,8,0,0,0,0,0,0,2,0 

Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,7,0,8,0,0,8,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,0,0,4,2,0,7,0,5,0 
Data.l 0,7,0,5,0,0,7,0,5,0,0,0 
Data.l 0,0,0,0,0,1,3,0,7,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,7,0,6,0,0,6,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,6,0,0,0,0,0,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

EndDataSection
That is 3.94 code. The only difference I do from the above is I check/handle buttons after checking/handling the menu and I use a delay of (16) in the main loop. I get very low CPU usage and no animation problems, jerks, tearing, etc. My testers haven't reported any issues either. (I should note I have done little testing on Vista as I don't plan to "officially" support it.)
I saw in another thread that you're using a custom 2D Engine? Maybe your custom engine is why windowed graphics work for you while the examples that come with PB distribution don't even work...
I wasn't referring to those games. I wouldn't compare a DX based game to a game that doesn't use DX :wink:
Is it available somewhere?
I doubt there is really a demand for it :cry: Because of that, for now, I am keeping it for my own use.
mp303

Post by mp303 »

it won't compile under the v4.0 demo that I have here at work - I'll check it out tonight at home, thanks! :)

tried the executable though - it might be smooth, it's hard to tell since nothing moves vertically over the screen without animating in this game.

I'm on a dual-core, and it's maxing out the one processor... we'll see how it runs on my single-core at home...
Brice Manuel

Post by Brice Manuel »

it might be smooth, it's hard to tell since nothing moves vertically over the screen without animating in this game.
The ladybug isn't animated, only the bee is.
I'm on a dual-core, and it's maxing out the one processor...
I converted it to 4.0 and pasted it below. On my dual core system, I get about 1 or 2 under CPU usage. You may need to adjust the framerate setting to your own needs or remove it.

Hint with this game, if you want to test usage and such, if you immediately move the bee to the upper-right hand corner, it should put the ladybug in a looped movement, so you can check CPU usage and such and not have to worry about the ladybug killing you.

Code: Select all

;============================================== 
;= LADY'S GARDEN ©2001 Reel Media Productions = 
;= programmed by Paul Leischow Sept.15 /2001 = 
;============================================== 
;= MODIFIED BY KAISER TO SHOW A MENU EXAMPLE = 
;= = 
;= I've added the Handle_Menu sub-routine to = 
;= show how can you handle window events in = 
;= the way you would do with any window. = 
;= = 
;= I added the sub-routine in every loop that = 
;= needed a FlipBuffers(), because here were = 
;= so many, but it can be used at the main = 
;= loop so you won't have problems. = 
;= = 
;= Converted to PB 4.0 by Brice Manuel
;============================================== 


;If InitSprite(99) = 0 Or InitKeyboard() = 0 | Removed due that it has no parameters now. 
If InitSprite() = 0 Or InitKeyboard() = 0 
MessageRequester("Error", "Can't open DirectX 7 or later", 0) 
End 
EndIf 
;If InitSound(10) = 0 | Removed due that it has no parameters now. 
If InitSound() = 0 
MessageRequester("Error", "Can't open DirectX 7 Or Sound Card is not present", 0) 
End 
EndIf 
;========SYSTEM SPECS ARE OK 


Procedure text(txtx.l,txty.l,txt.s) ;x/y screen coordinates are send along with a text string 
For tmp=1 To Len(txt) ;loop for the length of the string 
txtasc=Asc(Mid(txt,tmp,1)) ;get the ASCII value of each character in the string 
If txtasc<>32 ;if its not a space, display the sprite on the screen 
DisplayTransparentSprite(txtasc+5,txtx,txty) 
EndIf 
txtx=txtx+16 ;move the width of the sprite so we can display the next one 
Next 
txty=txty+25 ;move down to the next line 
EndProcedure 

Structure ladybug ;create a structure to hold all Lady's info 
lpx.w ;x position of Lady 
lpy.w ;y position of Lady 
lpxpos.w ;x position in the lookup table 
lpypos.w ;y position in the lookup table 
ldir.w ;direction Lady is moving 
lmove.w ;counter for movement to next tile 
lx.w ;x speed of Lady 
ly.w ;y speed of Lady 
EndStructure 

;ADDED BY KAISER 
;=========================================== 
Global DoQuit 
;=========================================== 

Global txtx.l ;x position of text 
Global txty.l ;y position of text 
Global txt.s ;string that hold text 
#mazewidth=12 ;width of maze (12 tiles) 
#mazeheight=13 ;hight of maze (13 tiles) 
level=1 ;current game level 
bugs=1 ;number of Lady bugs in the maze 
frmbee=0 ;what frame of Bee to display 
score.l=0 ;current score 

Global Dim lady.ladybug(4) ;set up 4 Lady bugs 
Global Dim maze(#mazewidth,#mazeheight) ;set up an array to hold maze tiles 
Global Dim track(#mazewidth,#mazeheight) ;set up an array to hold Lady movement data 

OpenWindow(100,0,0,640,480,"Lady's Garden",#PB_Window_ScreenCentered | #PB_Window_SystemMenu) 

If OpenWindowedScreen(WindowID(100),0,0,640,480,0,0,0) 
;If OpenScreen(640,480,16,"Lady's Garden") ;open a 640x480 graphic window | We don't need this, it's gonna be windowed. 

;============================= 
;Add menus (By Kaiser) 
;============================= 
CreateMenu(1,WindowID(100)) 
MenuTitle("Game") 
MenuItem(1,"New Game") 
MenuItem(2,"Load Game") 
MenuItem(3,"Save Game") 
MenuItem(4,"About") 
MenuBar() 
MenuItem(5,"Exit") 
;============================= 
;============================= 

LoadSprite(1,"data\bush1.bmp",0) ;load all the game sprites 
LoadSprite(2,"data\bush2.bmp",0) 
LoadSprite(3,"data\black.bmp",0) 
LoadSprite(4,"data\clear.bmp",0) 
LoadSprite(5,"data\flower.bmp",0) 
LoadSprite(6,"data\ladyl.bmp",0) 
LoadSprite(7,"data\ladyr.bmp",0) 
LoadSprite(8,"data\ladyu.bmp",0) 
LoadSprite(9,"data\ladyd.bmp",0) 
LoadSprite(10,"data\level.bmp",0) 
LoadSprite(11,"data\over.bmp",0) 
LoadSprite(12,"data\diz1.bmp",0) 
LoadSprite(13,"data\diz2.bmp",0) 
LoadSprite(14,"data\diz3.bmp",0) 
For tmp=20 To 59 
LoadSprite(tmp,"data\bee"+Str(tmp)+".bmp",0) ;load all the Bee sprites 
Next 
For tmp=60 To 69 
LoadSprite(tmp,"data\num"+Str(tmp)+".bmp",0) ;load all the number sprites for score 
Next 
For tmp=70 To 95 
LoadSprite(tmp,"data\a"+Str(tmp)+".bmp",0) ;load all the alphabet sprites for text 
Next 
LoadSound(1,"data\blip.wav") ;load all the sound effects 
LoadSound(2,"data\catch.wav") 
LoadSound(3,"data\level.wav") 
LoadSound(4,"data\intro.wav") 


;===========================MAINLOOP 
mainloop: 

Gosub init_data ;initialize game data / all starting positions 
Gosub load_maze ;load the first maze 
Gosub load_data ;load the first movement table 

If level=1 And bugs=1 ;if we're on level 1 and there is 1 Lady bug 
hold=0 
While hold=0 ;display instructions until space is pressed 
Gosub Handle_Menu 
DisplaySprite(4,0,0) 
text(80,90,"GUIDE BUMBLE THROUGH") 
text(80,115,"THE HEDGE MAZE AND") 
text(80,140,"PICK ALL THE FLOWERS") 
text(80,215,"IF LADY CATCHES YOU") 
text(80,240,"ITS GAME OVER") 
text(130,350,"PRESS SPACEBAR") 
frmbee=frmbee+1 
If frmbee>9:frmbee=0:EndIf ;cycle through all 9 frames of Bee flying 
DisplayTransparentSprite(frmbee+50,30,90) ;display Bee sprite 
DisplayTransparentSprite(8,30,220) ;display Lady sprite 
FlipBuffers() ;Flip screen buffer into view 
ExamineKeyboard() 
If KeyboardPushed(#PB_Key_Space) Or KeyboardPushed(#PB_Key_Escape):hold=1:EndIf 
Wend 
EndIf 
;PlaySound(4) ;play starting tune 
SetFrameRate(60) ; Change this or rem it out
While quit=0 
Gosub Handle_Menu 
If flower=0:quit=1:EndIf ;loop until all flowers have been collected 
ExamineKeyboard() 
If KeyboardPushed(#PB_Key_Escape):Gosub draw_credits:End:EndIf ;if ESC is pressed show credits and end 
If KeyboardPushed(#PB_Key_Left):mm=1:EndIf ;check for left/right/up/down arrows keys 
If KeyboardPushed(#PB_Key_Right):mm=2:EndIf 
If KeyboardPushed(#PB_Key_Up):mm=3:EndIf 
If KeyboardPushed(#PB_Key_Down):mm=4:EndIf 
Select mm 
Case 1 
If mve=0 And maze(cpxpos-1,cpypos)>2 ;move Bee according to the direction you've selected 
cx=-2:cy=0:cpdir=1:cpxpos=cpxpos-1:mve=32 
Gosub check_flower ;check if you've plucked any flowers along the way 
EndIf 
Case 2 
If mve=0 And maze(cpxpos+1,cpypos)>2 
cx=2:cy=0:cpdir=3:cpxpos=cpxpos+1:mve=32 
Gosub check_flower 
EndIf 
Case 3 
If mve=0 And maze(cpxpos,cpypos-1)>2 
cx=0:cy=-2:cpdir=2:cpypos=cpypos-1:mve=32 
Gosub check_flower 
EndIf 
Case 4 
If mve=0 And maze(cpxpos,cpypos+1)>2 
cx=0:cy=2:cpdir=4:cpypos=cpypos+1:mve=32 
Gosub check_flower 
EndIf 
EndSelect 
If mve<>0:cpx=cpx+cx:cpy=cpy+cy:mve=mve-2:EndIf 

Gosub move_lady ;Ladybug movement routine and AI 
Gosub draw_board ;draw the maze on the screen 
Gosub draw_bugs ;draw the Lady bugs on the screen 
Gosub set_score ;draw the score on the screen 

If quit>0 
If quit=1 ;if quit=1 then we've finished the level 
tmpy=480 ;place the 'level' sign at the bottom of screen 
;PlaySound(3) 
For nextlevel=0 To 190 
Gosub Handle_Menu 
Gosub draw_board ;draw the maze on the screen 
Gosub set_score ;draw the score on the screen 
DisplaySprite(10,134,tmpy) ;draw the 'level complete' sign 

FlipBuffers() ;flip screen buffer into view 
tmpy=tmpy-3 ;move the sign up 3 pixels 
Next 
EndIf 
If quit=2:PlaySound(2):EndIf ;if quit=2 then Lady gottcha / play gottcha sound 
EndIf 
; WaitWindowEvent()
Delay(16) ; 16 gives the best results
FlipBuffers() ;flip screen buffer into view 
Wend 
Else 
MessageRequester("Error","Could Not Initialize 640x480x16 Display",0) 
End 
EndIf 

If quit=2 ;Lady gottcha 
diz=0 ;current frame of dizzy bee 
Restore level1 ;reset the maze data to load level 1 
For hold=1 To 400 ;hold this screen till we count to 400 
Gosub Handle_Menu 
Gosub draw_board ;draw the maze on the screen 
Gosub set_score ;draw the score on the screen 
Gosub draw_diz ;draw the dizzy bee on the screen 
DisplaySprite(11,134,110) ;draw the game over sign 
Delay(50) ;small delay so bee doesn't flap to fast 
ExamineKeyboard() 
If KeyboardPushed(#PB_Key_Space):hold=400:Delay(500):EndIf ;press space to start again 
If KeyboardPushed(#PB_Key_Escape):Gosub draw_credits:End:EndIf ;press ESC to display credits and end 
FlipBuffers() ;flip screen buffer into view 
Next 
level=0 ;reset all data 
bugs=0 
score=0 
EndIf 
level=level+1 ;advance level 
bugs=bugs+1 ;add another Lady bug to screen 
If bugs>4:bugs=4:EndIf ;if we have 4 Lady bugs, then that's enough 
If level>4:level=1:Restore level1:EndIf ;if we've finished level 4 then start over again at level 1 
Goto mainloop 


;=============SPECIAL ROUTINES 
init_data: 
cpx=32*2 ;position Bee on the screen 
cpy=32*2 ;tiles are 32x32 so we need to multiply maze data by 32 
cpxpos=2 ;position Bee in the maze array 
cpypos=2 
cpdir=1 
cpmve=0 
cx=0 
cy=0 
quit=0 
mve=0 
mm=0 
For tmp=1 To 4 ;reset data for all 4 Lady bugs 
lady(tmp)\ldir=4 
lady(tmp)\lmove=0 
lady(tmp)\lx=0 
lady(tmp)\ly=0 
Next 
lady(1)\lpx=32*11 ;place all 4 Lady bugs in their starting positions 
lady(1)\lpy=32*12 
lady(1)\lpxpos=11 
lady(1)\lpypos=12 

lady(2)\lpx=32*11 
lady(2)\lpy=32*6 
lady(2)\lpxpos=11 
lady(2)\lpypos=6 

lady(3)\lpx=32*11 
lady(3)\lpy=32*8 
lady(3)\lpxpos=11 
lady(3)\lpypos=8 

lady(4)\lpx=32*11 
lady(4)\lpy=32*4 
lady(4)\lpxpos=11 
lady(4)\lpypos=4 
Return 

load_maze: 
For y=1 To #mazeheight ;load the maze tile data into an array 
For x=1 To #mazewidth 
Read maze(x,y) 
Next 
Next 
Read flower ;see how many flowers we need to pluck 
Return 
load_data: 
For y=1 To #mazeheight ;load Lady's movement lookup table into an array 
For x=1 To #mazewidth 
Read track(x,y) 
Next 
Next 
Return 

check_flower: 
If maze(cpxpos,cpypos)=5 ;if we've reached a flower (5) 
maze(cpxpos,cpypos)=3 ;then change it to a blank (3) 
flower=flower-1 ;decrement flower counter by 1 
score=score+5 ;increment score by 5 points 
;PlaySound(1) ;play the flower plucking sound 
EndIf 
Return 

set_score: 
tempscore$=Str(score) 
If Len(tempscore$)=1:newscore$="0000"+tempscore$:EndIf ;place leading zeros in the score 
If Len(tempscore$)=2:newscore$="000"+tempscore$:EndIf 
If Len(tempscore$)=3:newscore$="00"+tempscore$:EndIf 
If Len(tempscore$)=4:newscore$="0"+tempscore$:EndIf 
If Len(tempscore$)=5:newscore$=tempscore$:EndIf 
xscore=448 ;x position to start drawing score 
For tmp=1 To Len(newscore$) ;break apart score 1 character at a time 
DisplayTransparentSprite(Val(Mid(newscore$,tmp,1))+60,xscore,200) ;and display correct sprite 
xscore=xscore+30 ;move right to draw next character 
Next 
Return 

move_lady: 
For bug=1 To bugs ;for an explaination of how this all works 
lbx.l=lady(bug)\lpxpos ;check out Paul Gerfen's tutorial at 
lby.l=lady(bug)\lpypos ;www.openrpgs.com/articles/showarticle.php?article=2001/apr/pacman 
check.l=track(lbx,lby) 

If lady(bug)\lmove=0 
Select check 
Case 1:If lady(bug)\ldir=2:lady(bug)\ldir=3:Else:lady(bug)\ldir=4:EndIf 
Case 2:If lady(bug)\ldir=3:lady(bug)\ldir=4:Else:lady(bug)\ldir=1:EndIf 
Case 3:If lady(bug)\ldir=4:lady(bug)\ldir=1:Else:lady(bug)\ldir=2:EndIf 
Case 4:If lady(bug)\ldir=1:lady(bug)\ldir=2:Else:lady(bug)\ldir=3:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=5 
Select lady(bug)\ldir 
Case 3:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=4:EndIf 
Case 2:If cpxpos<lady(bug)\lpxpos:lady(bug)\ldir=1:Else:lady(bug)\ldir=2:EndIf 
Case 4:If cpypos>lady(bug)\lpypos:lady(bug)\ldir=4:Else:lady(bug)\ldir=1:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=6 
Select lady(bug)\ldir 
Case 4:If cpxpos<lady(bug)\lpxpos:lady(bug)\ldir=1:Else:lady(bug)\ldir=3:EndIf 
Case 3:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=3:EndIf 
Case 1:If cpxpos<lady(bug)\lpxpos:lady(bug)\ldir=1:Else:lady(bug)\ldir=2:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=7 
Select lady(bug)\ldir 
Case 4:If cpxpos>lady(bug)\lpxpos:lady(bug)\ldir=3:Else:lady(bug)\ldir=4:EndIf 
Case 1:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=4:EndIf 
Case 2:If cpypos<lady(bug)\lpypos:lady(bug)\ldir=2:Else:lady(bug)\ldir=3:EndIf 
EndSelect 
EndIf 

If lady(bug)\lmove=0 And check=8 
Select lady(bug)\ldir 
Case 2:If cpxpos>lady(bug)\lpxpos:lady(bug)\ldir=3:Else:lady(bug)\ldir=1:EndIf 
Case 3:If cpypos>lady(bug)\lpypos:lady(bug)\ldir=4:Else:lady(bug)\ldir=3:EndIf 
Case 1:If cpypos>lady(bug)\lpypos:lady(bug)\ldir=4:Else:lady(bug)\ldir=1:EndIf 
EndSelect 
EndIf 

Select lady(bug)\ldir 
Case 1:lady(bug)\lx=-1:lady(bug)\ly=0 
Case 2:lady(bug)\lx=0:lady(bug)\ly=-1 
Case 3:lady(bug)\lx=1:lady(bug)\ly=0 
Case 4:lady(bug)\lx=0:lady(bug)\ly=1 
EndSelect 

If lady(bug)\lmove=0 
lady(bug)\lpxpos=lady(bug)\lpxpos+lady(bug)\lx 
lady(bug)\lpypos=lady(bug)\lpypos+lady(bug)\ly 
lady(bug)\lmove=32 
EndIf 

If lady(bug)\lmove<>0 
lady(bug)\lpx=lady(bug)\lpx+lady(bug)\lx 
lady(bug)\lpy=lady(bug)\lpy+lady(bug)\ly 
lady(bug)\lmove=lady(bug)\lmove-1 
EndIf 
If cpxpos=lady(bug)\lpxpos And cpypos=lady(bug)\lpypos:quit=2:EndIf 
Next 
Return 

draw_board: 
DisplaySprite(4,0,0) ;draw background to clear the screen 
For y=1 To 13 
For x=1 To 12 
bl=maze(x,y) 
DisplaySprite(bl,x*32,y*32) ;display the maze tiles on the screen 
Next 
Next 
Return 

draw_bugs: ;draw Lady bug depending on the direction she's moving 
For bug=1 To bugs 
If lady(bug)\lx=-1:DisplayTransparentSprite(6,lady(bug)\lpx,lady(bug)\lpy):EndIf 
If lady(bug)\lx=1:DisplayTransparentSprite(7,lady(bug)\lpx,lady(bug)\lpy):EndIf 
If lady(bug)\ly=-1:DisplayTransparentSprite(8,lady(bug)\lpx,lady(bug)\lpy):EndIf 
If lady(bug)\ly=1:DisplayTransparentSprite(9,lady(bug)\lpx,lady(bug)\lpy):EndIf 
Next 
frmbee=frmbee+1 ;draw Bee depending on the direction he's moving 
If frmbee>9:frmbee=0:EndIf 
If mm=1:DisplayTransparentSprite(frmbee+30,cpx,cpy):EndIf 
If mm=2:DisplayTransparentSprite(frmbee+40,cpx,cpy):EndIf 
If mm=3:DisplayTransparentSprite(frmbee+50,cpx,cpy):EndIf 
If mm=4 Or mm=0:DisplayTransparentSprite(frmbee+20,cpx,cpy):EndIf 
Return 

draw_diz: ;draw dizzy bee looping through all 3 frames 
diz=diz+1 
If diz>3:diz=1:EndIf 
DisplayTransparentSprite(11+diz,cpx-16,cpy-16) 
Return 

draw_credits: ;draw final credits on the screen 
For tmp=0 To 480 ;have bee fly from top to bottom 
Gosub Handle_Menu 
DisplaySprite(4,0,0) 
text(40,45,"PROGRAMMER") 
text(40,70,"PAUL LEISCHOW") 
text(40,120,"GRAPHICS") 
text(40,145,"PAUL LEISCHOW") 
text(40,195,"AUDIO") 
text(40,220,"PETE ZILINSKI") 
text(40,270,"THANKS TO") 
text(40,295,"PAUL GERFEN") 
text(40,320,"FRED LABOUREUR") 
text(40,370,"COPYRIGHT") 
text(40,395,"REEL MEDIA PRODUCTIONS") 
frmbee=frmbee+1 
If frmbee>9:frmbee=0:EndIf ;loop through the 9 frames while he flys 
DisplayTransparentSprite(frmbee+20,15,tmp) ;(looks like he's flapping) 
FlipBuffers() ;flip screen buffer into view so we can see it 
Next 
Return 



Handle_Menu: 

Event=WindowEvent() 
If Event=#PB_Event_Menu 
If EventMenu()=1 
MessageRequester("Lady's Garden","New game") 
EndIf 
If EventMenu()=2 
MessageRequester("Lady's Garden","Load Game") 
EndIf 
If EventMenu()=3 
MessageRequester("Lady's Garden","Save Game") 
EndIf 
If EventMenu()=4 
MessageRequester("Lady's Garden","PureBASIC Example by Paul Leischow. Adapted to Windowed mode + a sample menu by: Kaiser") 
EndIf 
If EventMenu()=5 ; Quit 
If quit<>2 : PlaySound(4) : EndIf 
Gosub draw_credits:End 
EndIf 
EndIf 

Return 






DataSection ;maze data and movement data for Lady 
level1: ;each level has 2 sets of maze data 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 1,3,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,2,5,1,1,5,2,2,5,1 ;1 = bush1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 ;2 = bush2 
Data.l 1,5,2,5,2,2,2,2,5,2,5,1 ;3 = no flower (space) 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 ;5 = flower 
Data.l 1,5,1,1,5,1,1,5,1,1,1,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,5,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 
Data.l 1,5,2,2,5,1,1,5,2,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 74 ;number of flowers to collect 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,0,8,0,0,8,0,0,2,0 ;movement data for Lady 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;0 = no movement decision to be made 
Data.l 0,0,0,1,6,0,0,6,2,0,0,0 ;1 = lady can move down or right 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;2 = lady can move down or left 
Data.l 0,7,0,6,8,0,0,8,6,0,3,0 ;3 = lady can move up or left 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;4 = lady can move up or right 
Data.l 0,7,0,8,6,0,0,6,8,0,2,0 ;5 = lady can move left or up or down 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;6 = lady can move up or left or right 
Data.l 0,0,0,4,8,0,0,8,3,0,0,0 ;7 = lady can move right or up or down 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 ;8 = lady can move down or left or right 
Data.l 0,4,0,0,6,0,0,6,0,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

;level 2 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 1,3,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 
Data.l 1,5,2,2,2,2,2,2,5,2,5,1 
Data.l 1,5,5,5,5,5,5,2,5,5,5,1 
Data.l 1,1,1,5,2,5,5,2,5,1,1,1 
Data.l 1,5,5,5,2,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,2,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,2,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 71 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,8,0,0,0,0,8,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,4,0,0,0,0,5,0,0,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,8,0,8,2,0,7,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,5,0,4,6,0,6,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,7,0,0,0,0,2,0,0,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,6,0,0,0,0,6,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

;level 3 
Data.l 1,1,1,1,1,3,3,1,1,1,1,1 
Data.l 1,3,5,5,1,3,3,1,5,5,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,2,2,2,5,1,1,1,1,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,2,5,2,2,2,5,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,5,2,2,2,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,1,1,1,1,5,2,5,1 
Data.l 1,5,5,5,1,3,3,1,5,5,5,1 
Data.l 1,1,1,1,1,3,3,1,1,1,1,1 
Data.l 67 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,2,0,0,0,0,1,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,7,0,6,0,0,8,0,6,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,7,0,0,8,0,6,0,8,0,2,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,0,6,8,0,0,6,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,8,0,6,0,0,8,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,3,0,0,0,0,4,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

;level 4 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 1,3,5,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,2,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,1,5,1,1,5,2,5,1 
Data.l 1,5,2,5,1,5,5,1,5,5,5,1 
Data.l 1,5,5,5,1,1,5,5,5,2,5,1 
Data.l 1,5,2,5,1,5,5,1,5,5,5,1 
Data.l 1,5,2,5,1,5,1,1,5,2,5,1 
Data.l 1,5,2,5,5,5,5,5,5,5,5,1 
Data.l 1,5,2,5,2,2,2,2,2,2,5,1 
Data.l 1,5,5,5,5,5,5,5,5,5,5,1 
Data.l 1,1,1,1,1,1,1,1,1,1,1,1 
Data.l 74 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,1,0,8,0,0,0,0,0,0,2,0 

Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,7,0,8,0,0,8,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,0,0,4,2,0,7,0,5,0 
Data.l 0,7,0,5,0,0,7,0,5,0,0,0 
Data.l 0,0,0,0,0,1,3,0,7,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,0,0,7,0,6,0,0,6,0,5,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 
Data.l 0,4,0,6,0,0,0,0,0,0,3,0 
Data.l 0,0,0,0,0,0,0,0,0,0,0,0 

EndDataSection
mp303

Post by mp303 »

well, what do you know.

I changed line 206 to Delay(11) - the same value used in the first smooth example with the Win32 API workarounds, and it's smooth now! without the API stuff, well done! :)

one question though ... the Delay command gives the CPU back to the system (and other applications) for a while, right? ... what happens when your game/app needs more CPU? If it's calling Delay, you might be giving back CPU time that your application actually needs, and you may not be able to achieve full framerate or full use of the available CPU time...?
Brice Manuel

Post by Brice Manuel »

what happens when your game/app needs more CPU?
In the last example above, delay is called after the game's logic is processed and drawing is done, and before the flip command, therefore the game gets all the cpu time it needs before the delay is called.
mp303

Post by mp303 »

Brice Manuel wrote:
what happens when your game/app needs more CPU?
In the last example above, delay is called after the game's logic is processed and drawing is done, and before the flip command, therefore the game gets all the cpu time it needs before the delay is called.
but that's assuming your app doesn't need any CPU power during Delay() - what if the time before Delay() is not enough to finish? The Delay() command will then be "over due" for the next flip, and you'll end up waiting over one frame.

for example, if this is a graph of the time:

Code: Select all

C: Calculate (and draw on the backbuffer, etc.)
f: Flip command issued
F: Actual Flip
W: Wait (Delay)

+: Vertical refresh

here's the graph when CPU usage is relatively low:

+---------------+---------------+---------------+---------------+
 CCCCWWWWf......FCCCCWWWWf......FCCCCWWWWf......FCCCCWWWWf......F

But you Delay() for a fixed period of time, therefore, if the Delay()
is longer than the remaining period of time after calculation and
before next vertical refresh, here's what happens:

+---------------+---------------+---------------+---------------+
 CCCCCCCCCCCCCWWWWf.............FCCCCCCCCCCCCCWWWWf.............F

you see what I mean? there was actually time enough left over to complete the calculations and paint the result, but instead, we end up waiting past the next vertical refresh, and we then have to wait for the next one.

... or do I have that all wrong for some reason?[/code]
Brice Manuel

Post by Brice Manuel »

you see what I mean?
No, as you are showing things in a different order in that example, than in the code I posted.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

you see what I mean? there was actually time enough left over to complete the calculations and paint the result, but instead, we end up waiting past the next vertical refresh, and we then have to wait for the next one.
that's correct, and that is a known problem.

if generally the amound of calculations per frame is the same,
you can pre-test the time needed and variate the argument for the Delay() according to that.

you could also request the time needed every frame,
but this will of course take two additional calles of the timer function:

Code: Select all

loop
  call Timer, memorize value
  do calculations and display
  call Timer, compare value
  Delay( Framelength - TimerDifference - Gap )
  FlipBuffers
loopend
the additional Gap is needed, because the timercalls and the flip itself will also take time.
oh... and have a nice day.
mp303

Post by mp303 »

interesting solution, but it's still a workaround ... your timing adjustments will be delayed by one frame, so if you're using those time measurements in a game where the load spikes or changes suddenly, you'll get choppy or lagged motion by compensating too much/too little.

here's another (bad) solution I came up with:

Code: Select all

ExamineDesktops()
framerate = DesktopFrequency(0) * 2
             
maxx.l = 482
maxy.l = 258

If InitSprite() = 0 Or InitKeyboard() = 0
  MessageRequester("Error", "Can't open screen & sprite enviroment!", 0)
  End
EndIf

If OpenWindow(0, 0, 0, 512, 288, "A screen in a window...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If Not OpenWindowedScreen(WindowID(0), 0, 0, 512, 288, 0, 0, 0)
    MessageRequester("Error", "Can't open windowed screen!", 0)
    End
  Else
    SetFrameRate(framerate) ; *** change  *** // Set framerate up
  EndIf
EndIf

CreateSprite(0, 30, 30)
If StartDrawing(SpriteOutput(0))
  Box(0, 0, 30, 30, RGB(255, 0, 0))
  Box(5, 5, 20, 20, RGB(0, 255, 0))
  Box(10, 10, 10, 10, RGB(0, 0, 255))
  StopDrawing()
EndIf

dx = 2 : dy = 1


Repeat

  FlipBuffers(1)
  FlipBuffers(1) ; yup, twice
 
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Escape) : End : EndIf
 
  ClearScreen(RGB(0,0,0))

  x = x + dx
  y = y + dy
 
  If x > maxx : x = maxx : dx = -dx : EndIf
  If x < 0 : x = 0 : dx = -dx : EndIf
 
  If y > maxy : y = maxy : dy = -dy : EndIf
  If y < 0 : y = 0 : dy = -dy : EndIf

  DisplaySprite(0, x, y)
 
ForEver
doubling the framerate and flipping twice.

the extra flip will cost some clockcycles of course, but what's left to spend should be reliably stable.

it's not pretty, I know. and it still maxes out the CPU.

really the best solution would be a high-res timer, as demonstrated in the article I posted a link to earlier... it looks to me as if this is the only really reliable solution to this problem under windoze...?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

your timing adjustments will be delayed by one frame
nope.
the two timer calls, one before and one after calc/disp,
measure the actual duration of the operations.
then you calculate the difference of that actual timeneed and the desired frametime (e.g. 33ms),
that will be the amound of time it will take until the next vsync.
then you Delay for the calculated time, flip, and start over.
oh... and have a nice day.
mp303

Post by mp303 »

it still doesn't work for me.

maybe I should just give up and go full-screen to ensure this works properly...

but is there any way to open full-screen on the second display on a dual-head setup?

the Desktop commands will let me identify the second display - but OpenScreen doesn't accept any desktop argument.

is there a way to configure which screen is used "for games" in the graphics card driver config or something?
Thalius
Enthusiast
Enthusiast
Posts: 711
Joined: Thu Jul 17, 2003 4:15 pm
Contact:

Post by Thalius »

Yes there is...

if you want to do it the RIGHT way:
http://www.code5.ch/tools/winAPI32.zip

Thalius
"In 3D there is never enough Time to do Things right,
but there's always enough Time to make them *look* right."
"psssst! i steal signatures... don't tell anyone! ;)"
mp303

Post by mp303 »

heh, yeah - but then I might as well use the API's native language C++ then, and save myself the hassle of trying to interpret the API through a different language.

C++ is a bitch - all the pointer-juggling drives me to drink! ;)
Post Reply