While moving right, gameobject reacts to left-button, but not the other way around.
This one is a bit hard to explain. I'm just learning to code and as such trying to write my own player controller for the experience.
Issue: While holding in right-button, player moves to the right (which is correct). When pressing left-button, while still moving right, the player starts moving left (which is also correct). But when moving left and pressing the right-button, the player never starts moving right.
Same thing goes for when starting with left-button.
Been rewriting this a couple of times trying to sort though my logic, but just can't seem to pinpoint why it won't work.
This is my current player controller:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController2 : MonoBehaviour {
public enum enumDirection { Right, Left, Up, Down, Idle};
public enumDirection currentDirection;
public bool wasWalkingRight = true;
void Start() {
}
void Update() {
if (Input.GetButton("Right"))
{
currentDirection = enumDirection.Right;
}
if (Input.GetButton("Left"))
{
currentDirection = enumDirection.Left;
}
if (Input.GetButton("Up"))
{
currentDirection = enumDirection.Up;
}
if (Input.GetButton("Down"))
{
currentDirection = enumDirection.Down;
}
if (!Input.GetButton("Right") && !Input.GetButton("Left") && !Input.GetButton("Up") && !Input.GetButton("Down"))
{
currentDirection = enumDirection.Idle;
}
switch (currentDirection)
{
case enumDirection.Right:
MoveRight();
break;
case enumDirection.Left:
MoveLeft();
break;
case enumDirection.Up:
MoveUp();
break;
case enumDirection.Down:
MoveDown();
break;
case enumDirection.Idle:
NotMoving();
break;
default:
NotMoving();
break;
}
}
void MoveRight() {
wasWalkingRight = true;
GetComponent<Animator>().SetTrigger("To_Walking");
GetComponent<Rigidbody2D>().velocity = new Vector3(3, 0, 0);
if (Input.GetButton("Up"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(3, 3, 0);
}
else if (Input.GetButton("Down"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(3, -3, 0);
}
}
void MoveLeft() {
wasWalkingRight = false;
GetComponent<Animator>().SetTrigger("To_Walking_Left");
GetComponent<Rigidbody2D>().velocity = new Vector3(-3, 0, 0);
if (Input.GetButton("Up"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(-3, 3, 0);
}
else if (Input.GetButton("Down"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(-3, -3, 0);
}
}
void MoveUp () {
GetComponent<Rigidbody2D>().velocity = new Vector3(0, 3, 0);
if (wasWalkingRight)
{
GetComponent<Animator>().SetTrigger("To_Walking");
}
else
{
GetComponent<Animator>().SetTrigger("To_Walking_Left");
}
if (Input.GetButton("Right"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(3, 3, 0);
}
else if (Input.GetButton("Left"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(-3, 3, 0);
}
}
void MoveDown() {
GetComponent<Rigidbody2D>().velocity = new Vector3(0, -3, 0);
if (wasWalkingRight)
{
GetComponent<Animator>().SetTrigger("To_Walking");
}
else
{
GetComponent<Animator>().SetTrigger("To_Walking_Left");
}
if (Input.GetButton("Right"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(3, -3, 0);
}
else if (Input.GetButton("Left"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(-3, -3, 0);
}
}
void NotMoving()
{
if (!wasWalkingRight)
{
GetComponent<Animator>().SetTrigger("To_Idle_Left");
GetComponent<Rigidbody2D>().velocity = new Vector3(0, 0, 0);
currentDirection = enumDirection.Idle;
}
else
{
GetComponent<Animator>().SetTrigger("To_Idle");
GetComponent<Rigidbody2D>().velocity = new Vector3(0, 0, 0);
currentDirection = enumDirection.Idle;
}
}
}
Answer by Dragate · Nov 18, 2017 at 07:07 PM
The problem is the order of the if statements in Update(). You check right and then left. So if you press left while holding right, left will override your decision from right (cause left is checked after right). If you press right while holding left, left will persist. Why? As said, it's being checked after right. Left is getting "the last say". If you reverse the order of these 2 if statements, you should also have the reverse behaviour.
I'd recommend using GetButtonDown() instead of GetButton(). GetButtonDown() will set your currentDirection ONLY on the frame the button is pressed (not when it's held down). This way your currentDirection is set by the last button pressed. At the (5th) if statement determining the idle state leave it as it is (GetButton()). Change only the first four.
EDIT: Actually, this suggestion won't work on the scenario that you press 2 buttons and release 1 of the 2, the currentDirection won't be set by the button left held down. I guess this could be solved by adding an extra if statement that checks any button releases (GetButtonUp()). In that if statement you could have the current logic you have (the 4 if statements with Getbutton()).
void Update() {
bool horizontalRelease = Input.GetButtonUp("Right") || Input.GetButtonUp("Left");
bool verticalRelease = Input.GetButtonUp("Up") || Input.GetButtonUp("Down");
if(horizontalRelease || verticalRelease) {
if (Input.GetButton("Right")) {
currentDirection = enumDirection.Right;
} else if(Input.GetButton("Left")) {
currentDirection = enumDirection.Left;
} else if(Input.GetButton("Up")) {
currentDirection = enumDirection.Up;
} else if(Input.GetButton("Down")) {
currentDirection = enumDirection.Down;
}
}
if (Input.GetButtonDown("Right")) {
currentDirection = enumDirection.Right;
} else if(Input.GetButtonDown("Left")) {
currentDirection = enumDirection.Left;
} else if(Input.GetButtonDown("Up")) {
currentDirection = enumDirection.Up;
} else if(Input.GetButtonDown("Down")) {
currentDirection = enumDirection.Down;
}
if (!Input.GetButton("Right") && !Input.GetButton("Left") && !Input.GetButton("Up") && !Input.GetButton("Down")) {
currentDirection = enumDirection.Idle;
}
//...rest of code
}
EDIT: Above code has an issue. Let's say user has left, up, down pressed. Let's also say that down was pressed last (so player goes down). If user releases up button, code will pick up on it and will re-decide where player should head. With the above structured code that would be left (cause it's pressed), but down is still pressed so that should not change player's direction. Will try a different approach. Maybe having a stack is better. Stack will remember order of buttons pressed. GetButtonUp() / GetButtonDown() will handle the stack. Last element of stack determines direction. If List has no elements it means that nothing is pressed, thus idle state.
List<enumDirection> buttonMemory = new List<enumDirection>();
void Update(){
if(Input.GetButtonDown("Right")) {
buttonMemory.Add(enumDirection.Right);
}
if(Input.GetButtonDown("Left")) {
buttonMemory.Add(enumDirection.Left);
}
if(Input.GetButtonDown("Up")) {
buttonMemory.Add(enumDirection.Up);
}
if(Input.GetButtonDown("Down")) {
buttonMemory.Add(enumDirection.Down);
}
if(Input.GetButtonUp("Right")) {
buttonMemory.Remove(enumDirection.Right);
}
if(Input.GetButtonUp("Left")) {
buttonMemory.Remove(enumDirection.Left);
}
if(Input.GetButtonUp("Up")) {
buttonMemory.Remove(enumDirection.Up);
}
if(Input.GetButtonUp("Down")) {
buttonMemory.Remove(enumDirection.Down);
}
if(buttonMemory.Count != 0) {
currentDirection = buttonMemory[buttonMemory.Count - 1];
} else {
currentDirection = enumDirection.Idle;
}
//...rest of code
}
Tell me if it works.
This works exactly as I wanted it to. Thank you!
Didn't think of trying lists in this instance. Also wasn't aware that the order of the statements was playing a factor in this. Learned a valuable lesson here!
Your answer
![](https://koobas.hobune.stream/wayback/20220612142956im_/https://answers.unity.com/themes/thub/images/avi.jpg)