- Home /
How to get smooth 4 directional movement in top down without diagonal movement?
I noticed that there are other questions that address disabling diagonal movement, however each one I have tried doesn't seem to work smoothly with what I want. I think there is something wrong with my logic. The following code is my player script. I'm trying to get the player to walk exclusively in the up, down, left, or right direction. Also, if the player walks up, while holding the W key, then presses the D key to walk to the right, the character will then walk to the right, if the user lifts up on the D key the player will then continue to walk in the W direction because their finger was never lifted off the D key.
How can I get my movement to be smooth like this? Right now with the code I have if you hold down the D key first and then press the W or S key, I get the movement I want which I explained above. However if I first press the W key and then the D key, the player doesn't move. I first have to let up off of the W key for the character to move right. The movement depending on the keys I press is inconsistent. I'm thinking maybe I need to do a switch case for movement? I'm not sure. Any pointers? TIA!
[SerializeField]
private float _speed = 3f; // Player move speed
[SerializeField]
private float _attackTime; // Attack Time
private float _attackTimeCounter; // Counting time between attacks
private Animator _animator; // Reference to animator
private bool _playerMoving; // Tells us if the player is currently moving or idle
private bool _playerAttacking; // Whether the player is currently attacking or not
private Vector2 _lastMove; // Used for proper idle direction
void Start () {
_animator = GetComponent<Animator>();
}
void Update() {
//Set _playerMoving to false
_playerMoving = false;
//Upward Movement
if (!_playerAttacking)
{
if (Input.GetKey(KeyCode.W))
{
transform.position += Vector3.up * _speed * Time.deltaTime;
//If Player is moving _playerMoving = true
_playerMoving = true;
//Set the lastMovement on the Y Axis
_lastMove = new Vector2(0f, Input.GetAxisRaw("Vertical"));
}
//Left Movement
else if (Input.GetKey(KeyCode.A))
{
transform.position += Vector3.left * _speed * Time.deltaTime;
//If Player is moving _playerMoving = true
_playerMoving = true;
//Set the lastMovement on the X Axis
_lastMove = new Vector2(Input.GetAxisRaw("Horizontal"), 0f);
}
//Downward Movement
else if (Input.GetKey(KeyCode.S))
{
transform.position += Vector3.down * _speed * Time.deltaTime;
//If Player is moving _playerMoving = true
_playerMoving = true;
//Set the lastMovement on the Y Axis
_lastMove = new Vector2(0f, Input.GetAxisRaw("Vertical"));
}
//Right Movement
else if (Input.GetKey(KeyCode.D))
{
transform.position += Vector3.right * _speed * Time.deltaTime;
//If Player is moving _playerMoving = true
_playerMoving = true;
//Set the lastMovement on the X Axis
_lastMove = new Vector2(Input.GetAxisRaw("Horizontal"), 0f);
}
if (Input.GetKeyDown(KeyCode.Space))
{
_attackTimeCounter = _attackTime;
_playerAttacking = true;
transform.position += Vector3.zero;
_animator.SetBool("PlayerAttacking", true);
}
}
if(_attackTimeCounter > 0)
{
_attackTimeCounter -= Time.deltaTime;
}
if(_attackTimeCounter <= 0)
{
_playerAttacking = false;
_animator.SetBool("PlayerAttacking", false);
}
//Setting the MoveX and MoveY for the animator to read X and Y axis to accurately change animation based on <0 or >0
_animator.SetFloat("MoveX", Input.GetAxisRaw("Horizontal"));
_animator.SetFloat("MoveY", Input.GetAxisRaw("Vertical"));
_animator.SetBool("PlayerMoving", _playerMoving);
_animator.SetFloat("LastMoveX", _lastMove.x);
_animator.SetFloat("LastMoveY", _lastMove.y);
}
}
Answer by GamitusLabs · Dec 09, 2018 at 05:01 PM
I agree with hectorux for the most part. stick to one or the other. Additionally, I would use one of the getaxis methods as they take in multiple inputs (keyboard, controller, etc) and funnels it down to the one easy to find axis (horizontal, vertical, etc), this is the beauty of an input manager.
Next, the reason your code doesn't transition to the next direction is the way the if statements process. It checks the keys in order of the ifs. So when the W is held down it will never even check the A, S or D. Using the Axis and changing up the logic just a bit will get you the movement you're looking for.
I tried using the getAxis method and use horizontal and vertical, however this gives diagonal movement. I've been experimenting trying to get the movement I want. Do you mean to do something specific with the getAxis input method?
Yes, so the logic would be something like this pseudo-code: (edit - fixed the logic and clarified a few points)
abs_horz = absolute_val(horizontal_axis)
abs_vert = absolute_val(vertical_axis)
last_dir = 0 // set in the movement
if (abs_vert == abs_horz && abs_vert > 0) // check the dual input first
{
switch (last_dir)
{
case 0: // if for whatever reason the player mashed two keys simultaniously...
case 1: // this will be the one it executes, so just decide and change the order of the following
// horz
case 2:
// vert
}
}
else if (abs_vert > abs_horz)
// do vertical
else if (abs_horz > abs_vert)
// do horizontal
else // should occur with no directional input
last_dir = 0
Answer by hectorux · Dec 09, 2018 at 04:19 PM
Why do you use getkey(keycode) if when you chek the last direction you use GetAxisRaw?, try just to use GetAxis instead of raw, this will give you a smoother value, also, if you set getAxis!=0 then it will be the asme as keycode.X if you set in setting the gravity to 1
I'm using getAxisRaw for the animation I'm using. _last$$anonymous$$ove helps me idle in the correct direction when I am not pressing any key.