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 :P
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

Code: Select all

Dim Link( 3, 7 )
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
Did you read this? Not sure if it helps you...

http://www.xs4all.nl/~bluez/datatalk/pu ... ng_sprites

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.