Ways to limit player sprite movement.

Previous topic - Next topic

Lord_TNK

I really tried tweaking this one, but I need your help. I was trying to figure out a way to make the player's sprite move less as you held down the keys. Specifically it was to try to make the sprite move only a certain amount when you held down a key, but stop until you released it and pressed it again, instead of doing it continuously as you held down the key (this would be for stuff like moving a character like on a grid, the way some old school CRPGs did).

I couldn't find a way to make it work. This is the code so far, that didn't accidentally stop the sprite from moving at all, or in two directions only (at least I figured out that THEN limits results from an IF statement to one, so I need ENDIF for more).

Code (glbasic) Select
SETCURRENTDIR("Media") // go to media files

SETTRANSPARENCY RGB (244, 124, 0)

LIMITFPS 60

LOADSPRITE "whatever.bmp", 5 //any picture will do; the code here works with a 32x32 one
GLOBAL shield% = 5

GLOBAL spritex = 128
GLOBAL spritey = 128
GLOBAL spritespeed = 1
GLOBAL KeyHit = 0

WHILE KEY (01) = FALSE

MovePlayer()
DrawScreen()

WEND

FUNCTION MovePlayer:

LOCAL dirx, diry

IF KeyHit = 0
IF KEY (17)
diry = -1
KeyHit = 1
ENDIF
ELSE
diry = 0
KeyHit = 0
ENDIF

IF KeyHit = 0
IF KEY (30)
dirx = -1
KeyHit = 1
ENDIF
ELSE
dirx = 0
KeyHit = 0
ENDIF

IF KeyHit = 0
IF KEY (31)
diry = 1
KeyHit = 1
ENDIF
ELSE
diry = 0
KeyHit = 0
ENDIF

IF KeyHit = 0
IF KEY (32)
dirx = 1
KeyHit = 1
ENDIF
ELSE
dirx = 0
KeyHit = 0
ENDIF

spritex = spritex + (spritespeed * dirx)
spritey = spritey + (spritespeed * diry)

IF KEY (57) THEN spritespeed=3
IF NOT KEY (57) THEN spritespeed=1

IF spritex < 0 THEN spritex = 0
IF spritex > 608 THEN spritex = 608
IF spritey < 0 THEN spritey = 0
IF spritey > 448 THEN spritey = 448

ENDFUNCTION

FUNCTION DrawScreen:

DRAWSPRITE shield, spritex, spritey

SHOWSCREEN

ENDFUNCTION

r0ber7

#1
Here's my thoughts: (pseudocode)

Code (glbasic) Select


WHILE 1

IF KEY(up) = TRUE AND keypressed = 0
  keypressed = 1
ENDIF

IF keypressed = 1
move_sprite(x_amount)
keypressed = 2
ENDIF

IF keypressed = 2 AND KEY(up) = FALSE
  keypressed = 0
ENDIF

WEND


Of course now the sprite moves in one big move, but you could change that with a boolean and a function with a timer or something. :P

Lord_TNK

#2
Put up one for each direction, and adjusted the variables accordingly, but although it compiled and ran, it freezes each time I run it.

EDIT: And just to be sure, I reverted back to the code I posted, and it ran fine.

Slydog

#3
Summary: Your goal is when the player hits the 'move left' key (for example), you want the player object to move 'x' number of pixels to the left, depending on the grid size?  And, if the key is still down, don't repeat the command.  To repeat the move, the player must first release the key, and repress it?

For the movement requirement, I would implement an easing / tweening function to smoothly move your player from point a to point b over a set time period.  Check these two posts for two tweening libraries done for GLBasic:
http://www.glbasic.com/forum/index.php?topic=5643.msg44318#msg44318
http://www.glbasic.com/forum/index.php?topic=5892.msg46443#msg46443
Of course I recommend the first one.  :P

With a tweening library, you don't have to move an object at a linear speed, but can use an ease in and ease out style so it slowly starts moving, gets to max speed, the gradually slows to its final resting location.  Much more polished.

Here's a stab at your requirements. I use a lot of static variables, but shouldn't be a problem.
Ideally you want to add custom TYPES for a 2D vector, plus to handle tween calls automatically (or more automatic).
I have another TYPE library to handle my tweens if anybody wants to see it, it handles decrementing the timer for you, etc.

THIS HASN'T BEEN TESTED!  I just created this on the spot.

Code (glbasic) Select
CONSTANT GridSizeX% = 32
CONSTANT GridSizeY% = 32
CONSTANT Key_MoveLeft% = 30 // Or whatever
CONSTANT Key_MoveRight% = 31 // Or whatever
CONSTANT MoveSpeed% = 1000 // A Player movement animation lasts this number of ms
CONSTANT MoveTweenStyle% = TWEEN_TRANSITION_QUAD_INOUT
(or 'CONSTANT MoveTweenStyle% = 7' if GLBasic doesn't allow a constant set to another constant - this was an issue a year ago)

FUNCTION PlayerMove:
STATIC previousKey% = 0 // Remember previous key press between calls
STATIC isMoving% = FALSE // Is player currently in a move animation?
STATIC playerPos_DestX% = 0 // Player's destination 'x' location after the move
STATIC playerPos_DestY% = 0 // Player's destination 'y' location after the move
STATIC playerPos_StartX% = 0 // Player's starting 'x' location before the move
STATIC playerPos_StartY% = 0 // Player's starting 'y' location before the move
STATIC moveTimer# = 0 // Move animation timer (as a float for division calculations)

// Are we currenly in a move animation?  Then update position based on tween settings
IF isMoving
DEC moveTimer, GETTIMER() // Reduce the animation timer by how many ms have elapsed since last frame
IF moveTimer < 0
isMoving = FALSE
playerPositionX = playerPos_DestX
playerPositionY = playerPos_DestY
ELSE
playerPositionX = Tween_Get(MoveTweenStyle, playerPos_StartX, playerPos_DestX, (moveTimer / MoveSpeed))
playerPositionY = Tween_Get(MoveTweenStyle, playerPos_StartY, playerPos_DestY, (moveTimer / MoveSpeed))
ENDIF
ENDIF

// Check if 'Move Left' key is pressed
IF KEY(Key_MoveLeft%)
// User must NOT be already moving, and must lift key and repress to repeat a movement
IF (NOT isMoving) AND (previousKey <> Key_MoveLeft%)
playerPos_StartX = playerPositionX // Set to your current player's x position
playerPos_DestX = playerPositionX - GridSizeX // We want to move the player 'GridSizeX' pixels to the left
playerPos_StartY = playerPositionY // Not need for the move, but needed later in the 'isMoving' function
playerPos_DestY = playerPositionY // Since only moving in the 'x' direction, Y stays the same
isMoving = TRUE
moveTimer = MoveSpeed
ENDIF

previousKey = Key_MoveLeft%

// Check if 'Move Right' key is pressed
ELSEIF KEY(Key_MoveRight%)
... copy from above and adjust ...
previousKey = Key_MoveRight%

// No keys hit this frame
ELSE
previousKey = 0
ENDIF

ENDFUNCTION


[EDIT] Moved the 'isMoving' code to above the key checks.  I had it inside the checks - oops!  I had to then update both x and y locations in the global 'isMoving' check since we don't know which direction we're moving.  (We could have use two checks, 'isMovingX' and 'isMovingY' I suppose!)  I hate the code listing tabs defaulting to 8 spaces!  My text editor is set to 4 spaces!  Now my code looks sloppy! ha

[EDIT2] I'm not too confident the 'previousKey' logic is sound.  If you lift your finger during a move and rehit the same key again, the logic won't know you had released it.  I would remove the previous key logic completely maybe, and allow the user to hold the left key down, and move it one unit each second (as in the sample code).
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Lord_TNK

To your second edit, is there a way for GLBasic to know if a key is held down and then released? It would not only help this, but stuff like holding down the button to charge an attack (like the main laser in R-Type).

kanonet

No in GLBasic you can only check if a key is pressed at the moment. But you can easily write your own routine to know when it gets released.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Lord_TNK

Quote from: kanonet on 2012-Dec-04
No in GLBasic you can only check if a key is pressed at the moment. But you can easily write your own routine to know when it gets released.
Well I guess that will be an advanced thing for later, but would it involve linking another language?

kanonet

As i said, its really easy to do it on your own:

Code (glbasic) Select
// needs to get called often, lets say every loop...
LOCAL space_old%
IF KEY(57)
  space_old = 1
  // key is pressed atm
  // do what ever you want to do when space is pressed down
ELSE
  IF space_old
    space_old = 0
    // key just got released
    // just do here what ever you want, when space gets released
  ENDIF
ENDIF


You also find pressed/ down/ released events in my key def. 8)
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Lord_TNK

#8
Quote from: kanonet on 2012-Dec-05
As i said, its really easy to do it on your own:

Code (glbasic) Select
// needs to get called often, lets say every loop...
LOCAL space_old%
IF KEY(57)
  space_old = 1
  // key is pressed atm
  // do what ever you want to do when space is pressed down
ELSE
  IF space_old
    space_old = 0
    // key just got released
    // just do here what ever you want, when space gets released
  ENDIF
ENDIF


You also find pressed/ down/ released events in my key def. 8)
How would I incorporate that into the code in the first post? I tried doing it, just modifying the IF statements, but it didn't work.

Moru


Lord_TNK

Quote from: Moru on 2012-Dec-05
Can we see some code?
I wrote "in the first post". That means the first post on this thread.

Moru

I don't see any edits on that post. I want to see exactly what isn't working and what you tried to do. Preferably with full explanations of what you expect to happen and error messages and what happened instead. Doesn't have to be an essay, just a few lines with the code in code brackets (just like in your first post)

kanonet

I just noticed an interesting thing in your 1st post that needs to get addressed:

You did write KEY(01) to access the escape key. Please keep in mind, that you need to input a decimal number into the KEY() function and "01" is expression of an octal number. The compiler automatically translates it into a decimal number and since octal "01" = decimal "1" everything works as expected. But if you keep this behaviour you may run into trouble on later projects, lets say you want to access the key with the number 8: if you write KEY(8) everything works fine, but if you write KEY(08) you get a compiler error, since the leading "0" tells the compiler this is a octal numer, but there is no octal number that contains an "8" or "9" (octals only use the digests 0-7, in c and glb they always have a leading 0 so the compiler knows that you want to use octals). So do not add a leading 0 as long as you dont want to use octal numbers!
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Lord_TNK

#13
Quote from: Moru on 2012-Dec-05
I don't see any edits on that post.(1) I want to see exactly what isn't working and what you tried to do.(2) Preferably with full explanations of what you expect to happen(3) and error messages(4) and what happened instead. Doesn't have to be an essay, just a few lines with the code in code brackets (just like in your first post)
1. Why should there be edits in the first post? The code was there from the beginning.

2. Well I did give some of the problems in the first post, the other problem is the other methods don't seem to slow down the movement at all.

3. I did state what I expected to happen in the first paragraph on this thread. Even if it wasn't a format you were used to, that doesn't mean I didn't state the problem.

4. I already fixed the problems that caused errors.

Moru

Quote from: Lord_TNK on 2012-Dec-05
Quote from: kanonet on 2012-Dec-05
As i said, its really easy to do it on your own:

Code (glbasic) Select
// needs to get called often, lets say every loop...
LOCAL space_old%
IF KEY(57)
  space_old = 1
  // key is pressed atm
  // do what ever you want to do when space is pressed down
ELSE
  IF space_old
    space_old = 0
    // key just got released
    // just do here what ever you want, when space gets released
  ENDIF
ENDIF


You also find pressed/ down/ released events in my key def. 8)
How would I incorporate that into the code in the first post? I tried doing it, just modifying the IF statements, but it didn't work.
This part suggest you tried some change to the code and it didn't work. Ok. I'm not sure what code I'm supposed to look at. Is it still the top code even after all the suggestions in this thread? I'm confused after 10 minutes of staring at this but I guess it's because it's late.
If you want to slow down something, you need to change the speed of this object. For example if your objects speed is +1, you need to make it +(1*0.95) for each update until it gets close to 0. Then you stop adding anything at all to avoid rounding-errors in floating point numbers. This is something similar to what those tweening-libraries would do I imagine. Just easier to adjust the exact curve of the slowdown.