How do I change character direction without messing up the controls?

So, I’ve got my Character Controls working, as well as the rotation.
However, they don’t seem to like each other, and if I go left, my Character faces left, but moves forward (like a crab, lol).
If I press down, the character seems to walk backwards.
This is what I have:

if (controller.isGrounded) {
	moveDirection = new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical"));
	moveDirection = transform.TransformDirection(moveDirection);
	moveDirection *= speed;
	if (Winp.GetButtonDown(WiiUGamePadButton.ButtonA) || Input.GetKeyDown(KeyCode.Space)) {
		moveDirection.y = jumpSpeed;
	}
	if (Input.GetAxis("Horizontal") < 0) {
		transform.eulerAngles = new Vector3(0,-90,0);
	}
	if (Input.GetAxis("Horizontal") > 0) {
		transform.eulerAngles = new Vector3(0,90,0);
	}
	if (Input.GetAxis("Vertical") < 0) {
		transform.eulerAngles = new Vector3(0,180,0);
	}
	if (Input.GetAxis("Vertical") > 0) {
		transform.eulerAngles = new Vector3(0,0,0);
	}
}

So my question is, if I want to go left, the Character needs to face left, and go left.
How can I accomplish this?

Update
I’ve Updated my Code to this:

if (controller.isGrounded) {
    transform.forward = Vector3.Normalize(new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical")));
    moveDirection = transform.forward;
    moveDirection *= speed;
    
    if (Winp.GetButtonDown(WiiUGamePadButton.ButtonA) || Input.GetKeyDown(KeyCode.Space)) {
        moveDirection.y = jumpSpeed;
    }
    Debug.Log(moveDirection);
}

At first, it looked like it worked, but since it’s “transformer.forward”, it will always go forward.

Update 2
I think I’m getting closer now, as I’ve managed to make Vertical Controls work perfectly.

if (controller.isGrounded) {
    transform.forward = Vector3.Normalize(new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical")));
    moveDirection = transform.forward;
    if (Input.GetAxis("Vertical") == 0) {
        moveDirection *= 0;
    }
    else {
        moveDirection *= speed;
    }
    
    if (Winp.GetButtonDown(WiiUGamePadButton.ButtonA) || Input.GetKeyDown(KeyCode.Space)) {
        moveDirection.y = jumpSpeed;
    }
    Debug.Log(moveDirection);
}

However, the Horizontal movement is now always 0, unless I use the Vertical Axis while using the Horizontal Axis.
So, any quick solution to this one?

3 Answers

3

Okay, it got resolved now.
Here’s the final Code, for other people struggling with this:

if (controller.isGrounded) {
		transform.forward = Vector3.Normalize(new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical")));
		moveDirection = transform.forward;
		if (Input.GetAxis("Vertical") == 0 && Input.GetAxis("Horizontal") == 0) {
			moveDirection *= 0;
		}
		else {
			moveDirection *= speed;
		}
		
		if (Winp.GetButtonDown(WiiUGamePadButton.ButtonA) || Input.GetKeyDown(KeyCode.Space)) {
			moveDirection.y = jumpSpeed;
		}
		Debug.Log(moveDirection);
	}

I can see why you are having problems, but it is hard to know the best way to fix it. The way your code is written now, ‘Vertical’ trumps. That is, if you are using a joystick, then giving it a lot of horizontal and just a bit of vertical will still result in looking in the ‘Vertical’ direction (which means it should move in the ‘Vertical’ direction). Here is a guess at what you want. You may still need to figure out if your rotation code works like you want in all situations:

if (controller.isGrounded) {
	var moveMag = new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical")).magnitude;
    moveMag *= speed;

    if (Input.GetAxis("Horizontal") < 0) {
       transform.eulerAngles = new Vector3(0,-90,0);
    }
    if (Input.GetAxis("Horizontal") > 0) {
       transform.eulerAngles = new Vector3(0,90,0);
    }
    if (Input.GetAxis("Vertical") < 0) {
       transform.eulerAngles = new Vector3(0,180,0);
    }
    if (Input.GetAxis("Vertical") > 0) {
       transform.eulerAngles = new Vector3(0,0,0);
    }

    moveDirection = transform.forward * moveMag;

    if (Winp.GetButtonDown(WiiUGamePadButton.ButtonA) || Input.GetKeyDown(KeyCode.Space)) {
       moveDirection.y = jumpSpeed;
    }
}

After changing "var" into "float", it looks like it works. I currently can only go into 4 directions because of this change, but the Character is meant to be controlled by an Analog Stick, making it very unconfty. Changing "transform.forward" into "transform.TransformDirection(moveMag)" gave me another error. In order to accomplish that, I have to change "float" into "Vector3", but Unity3D gives me yet another error for that.

You mentioned you don’t want to do a lot of changes, so you might end up not implementing my suggestion. But the best way, in my opinion, is to divide the possible analog stick movement space into four areas, each 45 degrees wide.

Imagine a big circle, let’s say it has a radius of one. Now imagine an X at the center which touches the circle at four points. Let’s call the newly created uppermost sector ‘up’, the one on the left, ‘left’ etc.

What you need to do is determine which sector the analog stick is currently in. Because Unity gives the analog input between 0 and 1 in both vertical and horizontal, our analog stick input can be considered a vector within our circle. This is exactly what you’re doing in line 2.

Instead of then comparing the length of the individual axes, you should be using a reference forward direction - in third person games it’s usually the camera’s forward - and computing the angle of the analog stick vector and our reference forward. Our reference direction is at angle 0 and pointing straight up.

  • If the angle is between 0 and +/- 45, look forward
  • if between +/- 45 and +/- 135 than look left or right, depending on sign
  • if between +/- 135 and +/- 180 look backwards.

Moving should of course be done in the direction and speed of the analog stick vector.

I can’t remember if it’s possible to get a (+/-1,+/-1) out of Unity’s input system. if it is, then instead of a circle, use a box.

EDIT: for some reason I had divided everything by two in my math. Fixed now.
13697-refcircle.png

EDIT: I cobbled together what I meant in code:

    		Vector2 inputVector = new Vector3(Input.GetAxis("Horizontal"),Input.GetAxis("Vertical"));
    		
    		moveDirection = transform.TransformDirection(new Vector3(inputVector.x,0f,inputVector.y));
    		
    		float angle = Mathf.Atan2(inputVector.x,inputVector.y)*Mathf.Rad2Deg;
    		
    		if(angle>=0){//the right side
    			if(angle<45f){
    				//rotate character facing forward
    			}
    			if(angle<135f){
    				//rotate character facing right
    			}if(angle<=180f){
    				//rotate character facing right
    			}
    		}else{
    			if(angle>-45f){
    				//rotate character facing forward
    			}
    			if(angle>-135f){
    				//rotate character facing right
    			}if(angle>=-180f){
    				//rotate character facing right
    			}			
    		}

@Jamora - your concept is a workable one, but you need to tweak it a bit. The angles meaning you will get back from the Atan2 will not match your comments, and your movement code will not cause the player to move in the direction he is facing. But this is a good approach for the OP to fix his axis issues. If "Horizontal" and "Vertical" are buttons or keys rather than a joystick, then her current code is probably fine.

It's mapped to Analog Sticks, as I said before (Wii U Analog Sticks, to be more specific). By the way, I don't know from which country you are, but here in the West, "Yamilla" is a girls name, and I'm a female (just in case you didn't know that). @Jamora, your Code didn't work out for me.