Page 1 of 1

Smooth movement (design question)

Posted: Tue Sep 02, 2014 10:25 pm
by rmcode
Heya,

recently I started implementing smooth movement between tiles in my game. I came up with a method that uses lerping to smoothly correct the player's position on one axis, while he is moving on the other. It works pretty well, but I have a pretty stupid question which is more a related to design rather than code (at least that's what I think).

The problem occurs at crossroads with two valid paths like this (red is the actual tile position, blue is the real position):
tile.png
tile.png (9.04 KiB) Viewed 3670 times
When the player presses two keys at the same time (in this case up and right) then the character gets stuck in between tiles like in the image above. I already tried a few things like discarding one of the input directions, but haven't found a solution that I like.

Any ideas?

Re: Smooth movement (design question)

Posted: Wed Sep 03, 2014 2:10 am
by G-Mang
I worked on a maze tag kind of game in college that dealt a lot with pacman/bomberman-style arena movement, so it might be relevant here. :P

These were the basic rules, in case your game wouldn't work the same way:
1. Players could only move straight north, south, easy, west (no diagonal, no height)
2. Levels were straight paths and intersections (like pacman), no "rooms"
3. Game was real-time (not turn-based like Pokemon)

Given that, we ended up with these design rules in the code:
1. Assume the player wants to move over standing still (standing still is OK, just make totally sure that's definitely what the player wants). Ambiguity means "find the best direction," not "stop moving."
2. At an intersection, if a player's intended direction is unclear, assume they want to change directions from their previous movement (which we tracked). For example, holding up-right should tend to zigzag you to the northeast of the level.
3. If direction still can't be decided... CONTROLLER: compare joystick axes; KEYBOARD: whichever direction was most recently pressed gets priority.
4. If direction even still can't be decided, choose arbitrarily (like "favors north and east, north if still need a tiebreaker"). Movement test never got this far.

Hope that's helpful! :awesome:


EDIT: Hm I think I mighta misread the OP and skipped a step. :0
You should be separating input attempt and actual movement. In between, you should run checks to see where to actually move the character, if at all. If the diagonal is illegal, it shouldn't permit the diagonal movement. You may also want it to check for alternative "close enough" directions to move, like the example I have above, and then move in that direction instead.

Re: Smooth movement (design question)

Posted: Wed Sep 03, 2014 5:34 am
by micha
rmcode wrote:When the player presses two keys at the same time (in this case up and right) then the character gets stuck in between tiles like in the image above. I already tried a few things like discarding one of the input directions, but haven't found a solution that I like.

Any ideas?
The trick is to separate movement in x- and y-direction. First process all the input and calculate the velocity of the player. Then move the player in x-direction only, detect and resolve collisions, then move in y-direction, detect and resolve collision. Here is a nice blog post about this topic (not only relevant for 2d-platformers).

Re: Smooth movement (design question)

Posted: Fri Sep 05, 2014 9:03 am
by rmcode
Thanks a lot to you both. I'm close to fixing the movement, which means that I'll finally have a version with all the major features in it!

I have a small follow up question though, so I can do it correctly for my next games. Both of you said I should separate input and actual movement.

I currently use an InputManager I wrote for my first game, which basically sets command flags to true or false based on which keys have been pressed. In my player class I check for these commands:

Code: Select all

    local function handleInput()
        if InputManager.hasCommand('UP') then
            self:move('n');
        elseif InputManager.hasCommand('DOWN') then
            self:move('s');
        elseif InputManager.hasCommand('RIGHT') then
            self:move('e');
        elseif InputManager.hasCommand('LEFT') then
            self:move('w');
        end
    end
So whenever one of the keys is pressed

Code: Select all

self:move(...)
is called from the entity class which the player inherits from. That move(...) function is the one doing all the calculations and the actual movement. Is that what you meant?