# Help with creating smooth 2D movement

**URL:** <https://discourse.processing.org/t/help-with-creating-smooth-2d-movement/7272>\
**Category:** Coding Questions\
**Created:** [January 7, 2019, 2:54pm UTC](https://discourse.processing.org/t/help-with-creating-smooth-2d-movement/7272 "2019-01-07T14:54:45Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mono](https://avatars.discourse-cdn.com/v4/letter/m/9d8465/32.png) [@mono](https://discourse.processing.org/u/mono)\
**Post date:** [January 7, 2019, 2:54pm UTC](https://discourse.processing.org/t/help-with-creating-smooth-2d-movement/7272/1 "2019-01-07T14:54:46Z")

</div>

I have been attempting to implement some “smooth feeling” movement for a top-down action type game. The goal is to have the player slow down when changing direction and when stopping. The problem I have is the movement feels very inconsistent. Sometimes the “slow down” period feels very long and other times is feels just right, even though I have tried to code it to be consistent. Frankly it is so subtle it is hard to explain. I have compressed the project and uploaded it here:

> **[santa.zip](https://www.dropbox.com/s/dma8c4k0yotcj61/santa.zip?dl=0)**
>
> Shared with Dropbox

  
If you could open it yourself and try moving the player around you can maybe see what I mean. Any feedback or advice is appreciated.  
I believe all the relevant code should be in this section within the Player class:

```auto
  //move Player
  void movePlayer() {
    //selecting next Tile
    //if player is within a certain distance of the currentTilePos input is being given
    if (moving) {
      if (pos.dist(currentTilePos) < currentBoard.tileSize/2) {
        //pick possible next tile if there is certain input
        //also change directio variable
        int c = currentCol; //possible col
        int r = currentRow; //possible row
        switch(imd) {
        case 'w':
          c = currentCol;
          r = currentRow -1;
          md = imd;
          break;

        case 'd':
          c = currentCol +1;
          r = currentRow;
          md = imd;
          break;

        case 's':
          c = currentCol;
          r = currentRow +1;
          md = imd;
          break;

        case 'a':
          c = currentCol -1;
          r = currentRow;
          md = imd;
          break;
        }
        //if possible next tile is not out of bounds and not a wall make nextTile 
        if (c < currentBoard.cols && r < currentBoard.rows) {
          Boolean isWall = false;
          int i = 0;
          while (i < currentBoard.walls.size() && isWall == false) {
            Wall wall = currentBoard.walls.get(i);
            if (wall.col == c && wall.row == r) {
              isWall = true;
            }
            i++;
          }
          if (isWall == false) {
            currentCol = c;
            currentRow = r;
            currentTilePos = currentBoard.floor[c][r].pos.copy();
          }
        }
      }
    }

//detect if direction has just changed
    if (md != prevmd) {
      directionChange=true;
    }

//if changing direction
    if (directionChange) {
      //if magnitude of movement vector is less than 1
      if (moveVector.mag() < 1) {
        //direction change process is over, set speed to min for heading in new direction
        directionChange = false;
        speed = minSpeed;
      } else {
        //otherwise apply a slowdown to last frame's move vector and move player
        moveVector.mult(slowRate);
        pos.add(moveVector);
      }
    }

//if player is no longer changing direction
    if (!directionChange) {
      //if player is on the target tile (roughly lol)
      if (PVector.dist(pos, currentTilePos) < currentBoard.tileSize/2) {
        //apply slowing
        speed = speed*slowRate;
        //if speed is under the minimum
        if (speed < minSpeed) {
          //if player is very close to target speed may slow all the way down to zero once it is low enough
          //this prevents weird shaking on the spot h
          if (PVector.dist(pos, currentTilePos) < 2) {
            if (speed < 0.01) {
              speed = 0;
            }
          } else {
            //otherwise stop slowing at min speed until player gets closer to target
            speed = minSpeed;
          }
        }
        //if player has not reached the target tile
      } else {
        //apply acceleration
        speed = speed+accRate;
        //cap at top speed
        if (speed > topSpeed) {
          speed = topSpeed;
        }
      }

//target is center pixel of current tile
      PVector movementTarget = currentTilePos.copy();
      //produce vector from pos to target
      moveVector = PVector.sub(movementTarget, pos);
      //apply current speed
      moveVector.setMag(speed);
      //move player
      pos.add(moveVector);
      //record current input for detecting possible direction change next cycle
      prevmd = md;
    }
  }

```

However this might not make much sense outside the context of the full project so that is why I have linked it. Thanks for reading!

edit: after further investigation it seems the “moving” variable is false at times even when I am holding a key, causing the player to move to a tile and stop completely before moving to the next when direction is changing. Not very sure how to begin debugging something like this.

---

<div class="post-metadata">

**Author:** ![BennyHacker](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/bennyhacker/32/2969_2.png) [@BennyHacker](https://discourse.processing.org/u/BennyHacker)\
**Post date:** [January 7, 2019, 4:19pm UTC](https://discourse.processing.org/t/help-with-creating-smooth-2d-movement/7272/2 "2019-01-07T16:19:42Z")

</div>

The first thing you should try to fix is the method in which you move the player with keys. A well excepted way of doing this is using a boolean[] array in the player class and coding it like this:

```auto
void keyPressed() { 

  //player movement input
  //set direction to key pressed
  switch(key) {

    //WASD
  case 'w':
  case 'W':
    santa.moves[0]=true;
    break;

  case 'd':
  case 'D':
    santa.moves[1]=true;
    break;

  case 's':
  case 'S':
    santa.moves[2]=true;
    break;

  case'a':
  case'A':
    santa.moves[3]=true;
    break;
  }
}

```

All you have to do is add a velocity depending on which moves[] are true, and make sure to do the same in keyReleased()

It would also be a good idea to control all the other key functions this way

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 7, 2019, 4:24pm UTC](https://discourse.processing.org/t/help-with-creating-smooth-2d-movement/7272/3 "2019-01-07T16:24:45Z")

</div>

> [@BennyHacker](#):
>
> ```auto
> switch(key) {
> 
> //WASD
> case 'w':
> case 'W':
> 
> ```

```auto
  switch(keyCode) {

    //WASD
  case 'W':

```

---

<div class="post-metadata">

**Author:** ![BennyHacker](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/bennyhacker/32/2969_2.png) [@BennyHacker](https://discourse.processing.org/u/BennyHacker)\
**Post date:** [January 7, 2019, 4:33pm UTC](https://discourse.processing.org/t/help-with-creating-smooth-2d-movement/7272/4 "2019-01-07T16:33:19Z")

</div>

Also I’m a little confused by the idea of columns and rows in your player code. Do you only wish to move your player in the x and y axis, but not both at the same time?

---

<div class="post-metadata">

**Author:** ![mono](https://avatars.discourse-cdn.com/v4/letter/m/9d8465/32.png) [@mono](https://discourse.processing.org/u/mono)\
**Post date:** [January 8, 2019, 12:45pm UTC](https://discourse.processing.org/t/help-with-creating-smooth-2d-movement/7272/5 "2019-01-08T12:45:25Z")

</div>

the player is on top of a board of floor tiles, when a movement key is pressed it will move towards the center of an adjacent tile. I think you are correct that the issue lies within my method of processing input.
