Keyboard sprite movement

Advanced game related topics
ignign0kt
User
User
Posts: 59
Joined: Thu Sep 21, 2006 9:09 pm

Keyboard sprite movement

Post 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.
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

There is NO delay when using DirectInput.

PS: Where is FlipBuffers()?
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
ignign0kt
User
User
Posts: 59
Joined: Thu Sep 21, 2006 9:09 pm

Post 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?
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

WindowEvent(), not WaitWindowEvent().
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
ignign0kt
User
User
Posts: 59
Joined: Thu Sep 21, 2006 9:09 pm

Post 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?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post 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
oh... and have a nice day.
ignign0kt
User
User
Posts: 59
Joined: Thu Sep 21, 2006 9:09 pm

Post 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
    
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post 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.
oh... and have a nice day.
ignign0kt
User
User
Posts: 59
Joined: Thu Sep 21, 2006 9:09 pm

Post 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 ;\
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post 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.
oh... and have a nice day.
ignign0kt
User
User
Posts: 59
Joined: Thu Sep 21, 2006 9:09 pm

Post by ignign0kt »

Yeah like I said I'm really new at this. What would you suggest doing?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post 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) 
oh... and have a nice day.
ignign0kt
User
User
Posts: 59
Joined: Thu Sep 21, 2006 9:09 pm

Post 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
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

Did you read this? Not sure if it helps you...

http://www.xs4all.nl/~bluez/datatalk/pu ... ng_sprites
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post 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.
oh... and have a nice day.
Post Reply