0

I'm using libGDX trying to make a top-down 2D game with movement along the lines of Pokemon. However, I'm not sure how to implement this.

I want the player to be able to press a key (ie: arrow keys or WASD) in order to move, however, when the player releases the key, I don't want the character to stop moving until it's position falls along a grid of cells that consist of 32x32 pixel squares.

So how would I go about creating an 'invisible' grid of 32x32 pixel cells and making my character only stop moving whenever it's on top of one of those cells?

So far I've only done by-pixel movement. Which, I've contemplated I could just have a boolean stating whether the character was moving and just change that if the character landed on the right area, but I haven't thought of any way to implement that.

Here's the method that I'm using for my by-pixel movement (the libGDX covers key input and it draws the sprite based on where the player's bounding box is):

public void generalUpdate() {
    if(Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT)) {
        if (anim_current == Assets.anim_walkingLeft)
            if(player.collides(wall.bounds)) {
                player.bounds.x += 1;
            }
            else
                player.dx = -1;
        else
            anim_current = Assets.anim_walkingLeft;
        Assets.current_frame = anim_current.getKeyFrame(stateTime, true);
    }
    else if (Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT)) {
        if (anim_current == Assets.anim_walkingRight)
            if(player.collides(wall.bounds)) {
                player.bounds.x -= 1;
            }
            else
                player.dx = 1;
        else
            anim_current = Assets.anim_walkingRight;
        Assets.current_frame = anim_current.getKeyFrame(stateTime, true);
    }
    else if (Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP)) {
        if (anim_current == Assets.anim_walkingUp)
            if(player.collides(wall.bounds)) {
                player.bounds.y += 1;
            }
            else
                player.dy = -1;
        else
            anim_current = Assets.anim_walkingUp;
        Assets.current_frame = anim_current.getKeyFrame(stateTime, true);
    }
    else if (Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN)) {
        if (anim_current == Assets.anim_walkingDown)
            if(player.collides(wall.bounds)) {
                player.bounds.y -= 1;
            }
            else
                player.dy = 1;
        else
            anim_current = Assets.anim_walkingDown;
        Assets.current_frame = anim_current.getKeyFrame(stateTime, true);
    }
    else {
        Assets.current_frame = anim_current.getKeyFrames()[0];
        player.dx = player.dy = 0;
    }

    player.bounds.x += player.dx;
    player.bounds.y += player.dy;
}
Daniel
  • 10,641
  • 12
  • 47
  • 85
StormSurge95
  • 55
  • 1
  • 5
  • What have you tried so far? Most people would be glad to help you, if you show an inkling of effort. – Anubian Noob May 06 '14 at 02:49
  • @Anubian Noob Well I'm a slow thinker, I haven't tried anything involving grid-based movement because I haven't thought of anything that might work. – StormSurge95 May 06 '14 at 02:56
  • Include your (relavent) code for pixel-by-pixel movement. – Anubian Noob May 06 '14 at 02:57
  • @Anubian Noob Edited question to include code. – StormSurge95 May 06 '14 at 03:00
  • Thanks, I'll try to help as best I can... That's some scary code there... – Anubian Noob May 06 '14 at 03:03
  • whenever you move your character you should set a destination cell in your grid, if they continue to hold the button after the cell has been reached then move into the next cell etc – Matthew Pigram May 06 '14 at 03:03
  • @Anubian Noob Ah I know. I planned on finding some way to condense it after I figured out grid movement. – StormSurge95 May 06 '14 at 03:05
  • I'm just going to answer with design suggestions, not code. If you implement it and need more help I can help you more. – Anubian Noob May 06 '14 at 03:08
  • @MatthewPigram That would work, plus I could just have it draw the image tiles for the world in each cell. But would just creating a large 2D array of cells suffice for my game? Or would that take too much processing power? (Admittedly...it's simple enough to not need a lot, but I still don't want it to be gluttonous) – StormSurge95 May 06 '14 at 03:10
  • @Anubian Noob That would be fine. Thank you. – StormSurge95 May 06 '14 at 03:10
  • @StormSurge95 either would be fine, however a single large graphic would be better if performance was an issue. The cells do not need to be visible for the grid, they just need to map to your game world in some way (though making a debug flag to toggle drawing them can help you to visualise and debug) – Matthew Pigram May 06 '14 at 03:28

1 Answers1

1

Your code is a huge mess, and I don't want to try to fix it, but here's generally how you can approach your problem:

Have a boolean to represent if you are moving. Let's call it isMoving. Also have a method to store direction (maybe as an integer between 0 and 3?). Let's call it dir.


When you press a key, set isMoving to true. If you are aligned with the grid, update dir to the direction of the key you press as well.

If you aren't holding keys, set isMoving to false.

When you get to moving your character, if isMoving is true and they are not aligned with the grid, then move is the direction represented by dir. If they are aligned with the grid, then set isMoving to false and don't move.


// Only including one key, process is same for others.
if (rightKey) {
    isMoving = true;
    if (aligned)
        dir = 0;
} /* chain other keys in here */ else {
    isMoving = false;
}

if (isMoving) {
    if (!aligned) {
        move(dir);
        render(dir);
    } else {
    }
}

I just realized nearing the end that it might not work in it's current state :/. I hope this at least gives you an idea of what to do. I'll try to revise it some more...

Anubian Noob
  • 13,426
  • 6
  • 53
  • 75
  • this idea is on the right track, first though you would need to split up your world into a grid so that it maps evenly (e.g each cell might be 32x32 pixels in knowing this if your character is at cell 1, 5 you know they are at pixel coordinates 1x32, 5x32 = 32, 160), moving down one cell the character needs to move to 1x32, 6x32 = 1, 192 – Matthew Pigram May 06 '14 at 03:32
  • 1
    an even better solution would be move your character along an axis by say 1 pixel each update cycle, then once the button is released "snap" the character to the appropriate tile (applying the example about of `32x32` grid you get the players current pixel position `32, 155` for example and divide by grid size so grid `32/1, 155/32 = 1, ~4.8` we round this up to the next grid always if its a decimal so they should snap to grid `1, 5 = 32, 160` in pixels. – Matthew Pigram May 06 '14 at 03:39
  • Testing the position alone almost works...except that whenever I call my method to test if my character is aligned, it always says that it's false. I'm returning whether `(0 == ((int) bounds.y) % 32);` is true or false. Unless my understanding of float-to-int conversion is wrong, it should test and return whether the current pixel is evenly divisible by 32. – StormSurge95 May 06 '14 at 04:39
  • I'm only having my character move 1 pixel each update. And it's also testing the alignment during each update. So it should do something along the lines of `if (isMoving) { move 1 pixel; if (!aligned) move 1 pixel; else set isMoving to false;}` – StormSurge95 May 06 '14 at 04:42
  • Never mind. I figured it out. Thanks for all the help! – StormSurge95 May 06 '14 at 05:53