Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Minimal Platformer Movement Controls (Direction and Flipping Problems)  (Read 3565 times)

0 Members and 3 Guests are viewing this topic.

Rabees

  • Newbie
  • *
  • Posts: 25
    • View Profile
I'm struggling with something painfully basic here, so please bear with me.  :(

I'm going to try some simple platforming mechanics, and of course the first order of business is walking back and forth on the screen. There's no collision detection or velocity or anything yet, I've just got keys changing X position. Anyway, that's all well and good, but my placeholder Megaman sprite should be facing the direction he is moving.

What I've done right now is made an "isXFlipped" boolean, which is initialized as false. Then, with event polling, I check if the "right" key is pressed and if "isXFlipped" is false, and if it is I make "isXFlipped" true (as left is the sprite's default direction), and call sprite.Scale(-1.f, 1.f) (to X flip with SFML 2.0). Then, if the "left" key is pressed and "isXFlipped" is true, I make "isXFlipped" false and call sprite.Scale(-1.f, 1.f).

bool Engine::Init()
{
    ...

    isXFlipped = false;

    ...
}

void Engine::processInput()
{
    ...

    while(mainWindow.PollEvent(Event))
    {
        ...

        if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Keyboard::Right) && isXFlipped == false)
        {
            isXFlipped = true;
            playerSprite.Scale(-1.f, 1.f);
        }

        if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Keyboard::Left) && isXFlipped == true)
        {
            isXFlipped = false;
            playerSprite.Scale(-1.f, 1.f);
        }
    }

    float deltaTime = frameClock.GetElapsedTime().AsSeconds();

    if(sf::Keyboard::IsKeyPressed(sf::Keyboard::Left))
    {
        playerSprite.Move(-1150 * deltaTime, 0);
    }

    if(sf::Keyboard::IsKeyPressed(sf::Keyboard::Right))
    {
        playerSprite.Move(1150 * deltaTime, 0);
    }

...

This works alright, Megman flips left (if he is not already) when I press left and right (if he is not already) when I press right. He also moves those directions. The problem comes when I try pressing BOTH keys.

For example, when I am pressing right, the sprite is facing right and is walking right, but if, while I am still pressing right, I press left, the sprite stops moving altogether and faces left. This is a bit of a problem, as I would like for the new direction to take precedence over the old one (so pressing right then left would make you move left, and letting go of left if you were still holding right makes you go right). But, even worse, if I let go of left, but I am still holding right, the sprite moves right but continues to face left. This is probably horribly confusing in words, so here is a diagram: http://i.imgur.com/8V5jB8Q.png

(I'm honestly not sure if that makes more sense or not)

Anyway, thanks for reading my stupid thread!

eigenbom

  • Full Member
  • ***
  • Posts: 228
    • View Profile
Re: Minimal Platformer Movement Controls (Direction and Flipping Problems)
« Reply #1 on: January 27, 2013, 01:10:50 am »
I think you answered your own question, you just need to code in that preference. Instead of having just a xflipped flag, you'll also need a "isLeftPressed" and a "isRightPressed" flag. Then you poll the input each frame and update the two flags, along with the xflipped/facing_dir flag. e.g.,

Code: [Select]
// assume is_left=true and is_right=false
if this frame player pressed right:
  set is_right=true
  but as is_left is also true then don't change walking direction

if this frame player DIDN't press left:
  set is_left=false
  as is_right=true then update the walking direction to face right

Rabees

  • Newbie
  • *
  • Posts: 25
    • View Profile
Re: Minimal Platformer Movement Controls (Direction and Flipping Problems)
« Reply #2 on: January 27, 2013, 02:06:30 am »
Thanks! There is no longer any moonwalking (I think). Here is the altered code, for reference:

bool Engine::Init()
{
    ...

    isXFlipped = false;
    isRightPressed = false;
    isLeftPressed = false;

    ...
}

void Engine::processInput()
{
    ...

    while(mainWindow.PollEvent(Event))
    {
        ... (there is actually nothing related in here anymore)
    }

    float deltaTime = frameClock.GetElapsedTime().AsSeconds();

    if(sf::Keyboard::IsKeyPressed(sf::Keyboard::Left))
    {
        playerSprite.Move(-1150 * deltaTime, 0);
        isLeftPressed = true;
    }

    if(!sf::Keyboard::IsKeyPressed(sf::Keyboard::Left))
        isLeftPressed = false;

    if(sf::Keyboard::IsKeyPressed(sf::Keyboard::Right))
    {
        playerSprite.Move(1150 * deltaTime, 0);
        isRightPressed = true;
    }

    if(!sf::Keyboard::IsKeyPressed((sf::Keyboard::Right)))
        isRightPressed = false;

    if(isRightPressed == true && isXFlipped == false)
    {
        playerSprite.Scale(-1.f, 1.f);
        isXFlipped = true;
    }

    if(isLeftPressed == true && isXFlipped == true)
    {
        playerSprite.Scale(-1.f, 1.f);
        isXFlipped = false;
    }

...

The only issue now is that if both keys are pressed simultaneously, it either flips to face the direction of the new key or does not flip depending on which key it was. I think I can live with this though. However, if anybody wants to help out with that too, I wouldn't be against it.  :P

eigenbom

  • Full Member
  • ***
  • Posts: 228
    • View Profile
Re: Minimal Platformer Movement Controls (Direction and Flipping Problems)
« Reply #3 on: January 27, 2013, 03:10:45 am »
The only issue now is that if both keys are pressed simultaneously, it either flips to face the direction of the new key or does not flip depending on which key it was. I think I can live with this though. However, if anybody wants to help out with that too, I wouldn't be against it.  :P

Isn't this solved by adding this extra condition? (and the same for the isLeftPressed logic)

Code: [Select]
...
if(isRightPressed == true && isLeftPressed==false &&  isXFlipped == false)
    {
        playerSprite.Scale(-1.f, 1.f);
        isXFlipped = true;
    }
...

Also, btw, if you are using sf::Keyboard::IsKeyPressed(sf::Keyboard::Left) then you don't need those extra boolean variables. I assumed you were using the Pressed/Released events.

Rabees

  • Newbie
  • *
  • Posts: 25
    • View Profile
Re: Minimal Platformer Movement Controls (Direction and Flipping Problems)
« Reply #4 on: January 27, 2013, 03:40:43 am »
Isn't this solved by adding this extra condition?

The problem is that if I hold right and then press left while still holding right, the sprite flips left, but if I hold left and then press right while still holding left, the sprite does not flip right until I let go of left (also holding both keys just stops movement altogether still, but I am ok with this for now).

Also, btw, if you are using sf::Keyboard::IsKeyPressed(sf::Keyboard::Left) then you don't need those extra boolean variables. I assumed you were using the Pressed/Released events.

I sort of realized this while I was changing the code, but the booleans feel a little easier to keep track of. I'll probably get rid of them eventually though.

eigenbom

  • Full Member
  • ***
  • Posts: 228
    • View Profile
Re: Minimal Platformer Movement Controls (Direction and Flipping Problems)
« Reply #5 on: January 27, 2013, 03:59:12 am »
So, let me get this correct. You're holding the right key and the state is..

Code: [Select]
isXFlipped = true
isRightPressed  = true
isLeftPressed = false

Then you press the left key while still holding the right key. This code should avoid the sprite being flipped immediately, until you let go of one key.

Code: [Select]
// ... code for reading keystate

// now the state is
// isRightPressed=true
// isXFlipped=true
// isLeftPressed = true

if (isRightPressed && !isXFlipped && !isLeftPressed){
  playerSprite.Scale(-1.f, 1.f);
  isXFlipped = true;
}

if (isLeftPressed && isXFlipped && !isRightPressed){
  playerSprite.Scale(1.f, 1.f);
  isXFlipped = false;
}

The movement issue can be solved simply: move the guy in the direction given by isXFlipped, but only if isLeftPressed or isRightPressed or both are pressed.

Rabees

  • Newbie
  • *
  • Posts: 25
    • View Profile
Re: Minimal Platformer Movement Controls (Direction and Flipping Problems)
« Reply #6 on: January 27, 2013, 04:33:33 am »
Ah! There we go. My code was that, but I did not check if the opposite key was false. I didn't realize that was messing it up. Also,

if (isLeftPressed && isXFlipped && !isRightPressed){
  playerSprite.Scale(1.f, 1.f);
  isXFlipped = false;
}

should be

if (isLeftPressed && isXFlipped && !isRightPressed){
  playerSprite.Scale(-1.f, 1.f);
  isXFlipped = false;
}

Now it works flawlessly!

Quote
The movement issue can be solved simply: move the guy in the direction given by isXFlipped, but only if isLeftPressed or isRightPressed or both are pressed.

I have tried this just now too:

if(isXFlipped == false)
    {
        if(isRightPressed == true || isLeftPressed == true)
        {
            playerSprite.Move(-1150 * deltaTime, 0);
        }
    }

    if(isXFlipped == true)
    {
        if(isRightPressed == true || isLeftPressed == true)
        {
            playerSprite.Move(1150 * deltaTime, 0);
        }
    }

This works in that the player does not change direction until the old key was released, but how would I go about doing the opposite, so that the new key changes the direction and the old key is forgotten (e.g., pressing right then presses left while still pressing right, changes to move left instead of continuing right)?

eigenbom

  • Full Member
  • ***
  • Posts: 228
    • View Profile
Re: Minimal Platformer Movement Controls (Direction and Flipping Problems)
« Reply #7 on: January 27, 2013, 05:25:19 am »
... but how would I go about doing the opposite, so that the new key changes the direction and the old key is forgotten (e.g., pressing right then presses left while still pressing right, changes to move left instead of continuing right)?

I think you'd need to remember what has changed in the keyboard state this frame in order to do that. For example..

Code: [Select]
bool wasLeftPressed = isLeftPressed;
bool wasRightPressed = isRightPressed;

isLeftPressed = sf::Keyboard::IsKeyPressed(sf::Keyboard::Left);
isRightPressed = sf::Keyboard::IsKeyPressed(sf::Keyboard::Right);

if (isLeftPressed && !wasLeftPressed){
  // face left
  playerSprite.setScale(1,1);
  isXFlipped = false;
}
else if (wasLeftPressed && !isLeftPressed && isRightPressed){
  // face right again
  playerSprite.setScale(-1,1);
  isXFlipped = false;
}

if (isRightPressed && !isRightPressed){
  // face right
  ..
}
else if (wasRightPressed && !isRightPressed && isLeftPressed){
  // face left again
 ..
}