Page 1 of 1
Keyboard sprite movement
Posted: Sun Mar 01, 2009 2:15 am
by ignign0kt
Normally, when moving a sprite with keyboard input:
Code: Select all
Repeat
DisplaySprite(#SpriteLink1,400,y)
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Down)
y+2
EndIf
Until whatever
Depending on Window's keyboard repeat settings, there will be a delay in the sprite's movement when pushing the down key. How can I stop this without changing Window's settings?
Just want a smooth animation from the moment the key is pressed.
Posted: Sun Mar 01, 2009 2:25 am
by Fluid Byte
There is NO delay when using DirectInput.
PS: Where is FlipBuffers()?
Posted: Sun Mar 01, 2009 2:29 am
by ignign0kt
Well, I'm using a WindowedScreen but that shouldn't matter should it?
There's a delay when you press and hold the Down key.
By the way I'm trying to learn some things through playing around, I'm not really making anything.
Code: Select all
Enumeration
#WinMain
#SpriteLink1
EndEnumeration
UsePNGImageDecoder()
InitSprite()
InitKeyboard()
OpenWindow(#WinMain,0,0,800,600,"Screen Test", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(#WinMain),0,0,800,600,1,0,0)
LoadSprite(#SpriteLink1, "C:\Users\horn\Desktop\link1.png", #PB_Sprite_AlphaBlending)
y=300
Repeat
evnt = WaitWindowEvent()
FlipBuffers()
ClearScreen(RGB(0,0,0))
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Down)
y+2
EndIf
DisplaySprite(#SpriteLink1,400,y)
Until evnt = #PB_Event_CloseWindow
Edit: I just tried the exmaple in the Keyboard exmaple file in the Help. I noticed it does pretty much the exact same thing as mine, but it uses a fullscreen Screen. So if that's the case.. how do I make mine with no delay using a window?
Posted: Sun Mar 01, 2009 2:35 am
by Fluid Byte
WindowEvent(), not WaitWindowEvent().
Posted: Sun Mar 01, 2009 2:40 am
by ignign0kt
Ugh, I figured it'd be a dumb mistake ;\\\
Thanks
But while we're on the subject. If instead of screens I was just using Image gadgets, would I have the problem I mentioned?
Posted: Sun Mar 01, 2009 3:29 am
by Kaeru Gaman
if you don't use a screen, you cannot use the DX-Keyboard.
then, if you use some keyboard-input via string inputs or via keyboard events,
you
will experience the problems you described.
but normally you should work via checks like GetAsyncKeystate_() API,
and then again your Keypresses are synchronous to your mainloop, no delay will occur.
(additionally, in that case you should take care to only check the key when your window has the focus)
... but in the end, using ImageGadgets would have other inconvenienties, so better stick to a screen.
I wrote a little Winscreen,Mouse&Focus Example some time ago, should be not too hard to add Keyboard processing...
http://www.purebasic.fr/english/viewtopic.php?t=25082
Posted: Mon Mar 02, 2009 2:56 am
by ignign0kt
Thanks for the replies. I have another question.
I have the sprite moving fine with they keyboard events...but I do not really know how to add stepping animations when the sprite moves.
For exmaple.. if I'm holding the right arrow, I would like see the sprite change images every 500 miliseconds for exmaple, between the images where the sprite is walking.
I'm just not really sure how to do this.
Right now I'm just testing it out with the Right Arrow Key event
Code: Select all
UsePNGImageDecoder()
InitSprite()
InitKeyboard()
Enumeration
#WinMain
#SpriteLinkDown
#SpriteLinkUp
#SpriteLinkRight
#SpriteLinkRightStep1
#SpriteLinkRightStep2
#SpriteLinkLeft
EndEnumeration
Structure SprAttrib
x.i ;x and y coordinates for Link sprite
y.i
EndStructure
LinkSpriteToUse = #SpriteLinkDown ;Used to change sprite direction on key events.. Set initial direction - Down
Link.SprAttrib
;set initial coordinates for Link
Link\y=300
Link\x=400
OpenWindow(#WinMain,0,0,800,600,"Screen Test", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(#WinMain),0,0,800,600,1,0,0)
CatchSprite(#SpriteLinkDown, ?LinkSpriteDown, #PB_Sprite_AlphaBlending)
CatchSprite(#SpriteLinkUp, ?LinkSpriteUp, #PB_Sprite_AlphaBlending)
CatchSprite(#SpriteLinkRight, ?LinkSpriteRight, #PB_Sprite_AlphaBlending)
CatchSprite(#SpriteLinkRightStep1, ?LinkSpriteRightStep1, #PB_Sprite_AlphaBlending)
CatchSprite(#SpriteLinkRightStep2, ?LinkSpriteRightStep2, #PB_Sprite_AlphaBlending)
CatchSprite(#SpriteLinkLeft, ?LinkSpriteLeft, #PB_Sprite_AlphaBlending)
;Main loop
Repeat
evnt = WindowEvent()
FlipBuffers()
ClearScreen(RGB(0,0,0))
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Down)
;Move down
Link\y+1
LinkSpriteToUse = #SpriteLinkDown
EndIf
If KeyboardPushed(#PB_Key_Up)
;Move up
Link\y-1
LinkSpriteToUse = #SpriteLinkUp
EndIf
If KeyboardPushed(#PB_Key_Right)
;Move Right
Link\x+1
LinkSpriteToUse = #SpriteLinkRightStep1
EndIf
If KeyboardPushed(#PB_Key_Left)
;Move left
Link\x-1
LinkSpriteToUse = #SpriteLinkLeft
EndIf
DisplaySprite(LinkSpriteToUse,Link\x,Link\y)
;less CPU usage
Delay(15)
Until evnt = #PB_Event_CloseWindow
DataSection
LinkSpriteDown:
IncludeBinary "C:\Users\horn\Desktop\linkdown.png"
LinkSpriteUp:
IncludeBinary "C:\Users\horn\Desktop\linkup.png"
LinkSpriteRight:
IncludeBinary "C:\Users\horn\Desktop\linkright.png"
LinkSpriteRightStep1:
IncludeBinary "C:\Users\horn\Desktop\linkrightstep1.png"
LinkSpriteRightStep2:
IncludeBinary "C:\Users\horn\Desktop\linkrightstep2.png"
LinkSpriteLeft:
IncludeBinary "C:\Users\horn\Desktop\linkleft.png"
EndDataSection
Posted: Mon Mar 02, 2009 5:12 am
by Kaeru Gaman
better sync your whole movement AND animation to some timer.
you would not only the animation of your sprite to take e.g. 20ms per frame,
but you would also want your sprite to move a certain amount of pixel the same time.
for the beginning, you can sync the whole loop.
a cheap example:
http://www.purebasic.fr/german/viewtopi ... 795#208795
ignore the german text, the example is sufficent. I stress it's only a cheap sample.
when you go for more accurancy, you may want to put your movement,
animations and calculations into a seperated thread that is timer based,
and your display in the event-handling loop that runs at maximum framerate.
for some minigames this is not necessary, just sync the complete mainloop and put all into it.
Posted: Mon Mar 02, 2009 5:22 am
by ignign0kt
The only way a timer makes sense to me is if I think of it like a VB timer.
I could enable the timer when a key is held, and the timer would switch the sprites. But I don't get how to do that in PB.
I really don't even see why I need a timer for this, I just can't think of any way to switch between the sprites at all... ;\
Edit:
Ok I found a messy way of changing sprites using boolean toggles...and now I see why I need a timer of some sort. Cause it switches wayyy too fast

That example you showed me is a little confusing though.. I'm new to this stuff ;\
Posted: Tue Mar 03, 2009 2:40 am
by Kaeru Gaman
the timer thingy I showed you is only an example for how to sync the mainloop.
you can use a counter within your Keycheck to make an animation frame last more than one screenframes.
Code: Select all
If KeyboardPushed(#PB_Key_Right)
x+1
Counter + 1
If Counter > 4
Counter = 0
AnimFrame + 1
If AnimFrame > LastFrame
AnimFrame = FirstFrame
EndIf
EndIf
EndIf
btw... you should alter your SpriteHandling.
using Constants for Spritenumbers is not the best idea.
Posted: Tue Mar 03, 2009 4:41 am
by ignign0kt
Yeah like I said I'm really new at this. What would you suggest doing?
Posted: Tue Mar 03, 2009 12:10 pm
by Kaeru Gaman
you got me a bit confused, because on the one hand you say you are new to programming, on the other hand you use a term like "boolean toggles"...
anyhow...
the best way to handle Spritenumbers is to load/create them dynamically and store the PB-IDs in an Array.
you can set up the arrays right the way it suits best for your own sprite organisation.
e.g. for your PlayerSprite, you could set up an Array
for four directions with 8 AnimationFrames each.
with descriptive filenames, the loader would look like this:
Code: Select all
Dim Link( 3, 7 )
Link( 0, 0 ) = LoadSprite( #PB_Any, "LinkUpStep1.png" )
Link( 0, 1 ) = LoadSprite( #PB_Any, "LinkUpStep2.png" )
Link( 0, 2 ) = LoadSprite( #PB_Any, "LinkUpStep3.png" )
Link( 0, 3 ) = LoadSprite( #PB_Any, "LinkUpStep4.png" )
Link( 0, 4 ) = LoadSprite( #PB_Any, "LinkUpStep5.png" )
Link( 0, 5 ) = LoadSprite( #PB_Any, "LinkUpStep6.png" )
Link( 0, 6 ) = LoadSprite( #PB_Any, "LinkUpStep7.png" )
Link( 0, 7 ) = LoadSprite( #PB_Any, "LinkUpStep8.png" )
Link( 1, 0 ) = LoadSprite( #PB_Any, "LinkDownStep1.png" )
Link( 1, 1 ) = LoadSprite( #PB_Any, "LinkDownStep2.png" )
Link( 1, 2 ) = LoadSprite( #PB_Any, "LinkDownStep3.png" )
...
Link( 2, 0 ) = LoadSprite( #PB_Any, "LinkLeftStep1.png" )
...
Link( 3, 0 ) = LoadSprite( #PB_Any, "LinkRightStep1.png" )
Loading/Catching/Creating a Sprite with #PB_Any will cause the function to return the PB-ID of the new Sprite.
you store this in an Array, and can use it in every Sprite Command just like you would use the Number.
Code: Select all
DisplaySprite( Link( Direction, AnimationFrame ), Link\x, Link\y)
Posted: Wed Mar 04, 2009 2:22 am
by ignign0kt
Awesome... Thanks man, seems to be working well, except I don't know how to return to the standing still frame (frame 0) when a key isn't pushed.
I don't really know how to code 'If key isn't being pressed and the last pressed was Left, then LinkSprite = Link(0,0)'
Code: Select all
Repeat
evnt = WindowEvent()
FlipBuffers()
ClearScreen(RGB(0,0,0))
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Left)
x-1
FrameCounter+1
If FrameCounter > 4
FrameCounter = 0
Frame +1
LinkSprite = Link(0,Frame)
If Frame = 8
Frame = 3
EndIf
EndIf
EndIf
DisplaySprite(LinkSprite,x,y)
Until evnt = #PB_Event_CloseWindow
Posted: Wed Mar 04, 2009 10:37 am
by blueznl
Posted: Wed Mar 04, 2009 11:46 am
by Kaeru Gaman
ignign0kt wrote:I don't really know how to code 'If key isn't being pressed and the last pressed was Left, then LinkSprite = Link(0,0)'
well, not at all...
this is a good Moment to devide into more sections.
you can use an Animation-Flag to control Animated or not.
Code: Select all
AnimationFlag = 0
If KeyboardPushed(#PB_Key_Left)
x-1
Direction = 0
AnimationFlag = 1
EndIf
If KeyboardPushed(#PB_Key_Right)
x+1
Direction = 2
AnimationFlag = 1
EndIf
If KeyboardPushed(#PB_Key_Up)
y-1
Direction = 1
AnimationFlag = 1
EndIf
If KeyboardPushed(#PB_Key_Down)
y+1
Direction = 3
AnimationFlag = 1
EndIf
If AnimationFlag = 1
FrameCounter+1
If FrameCounter > 4
FrameCounter = 0
Frame +1
If Frame > 4
Frame = 1
EndIf
EndIf
Else
FrameCounter = 0
Frame = 0
EndIf
LinkSprite = Link( Direction, Frame)
at the beginning of the Loop we clear the Flag.
now, if any of our controlkeys is pressed, we set the Direction and activate the AnimationFlag.
only if the Flag is set, we perform the Counting and the Frame changing.
if the flag is not set, we set the counter and the Frame to 0,
but the Direction stays from the last loop when a key was pressed.
I used Frame 0 for standing still and Frames 1-4 for movement here.
you used Frames 4-8, wich left Frames 1-3 unused...
.... we have another problem here:
when you press two keys, e.g. UP and RIGHT,
both Coordinates are altered,
but the Direction is set by the last check performed.
more than this, when we press UP, DOWN and RIGHT at the same time (and our Keyboard handles it correctly),
the sprite will look DOWN but move RIGHT...
we would have to devide functions again to avoid that.