Questions about Isometric WASD Movement

Hi all!

I’m trying to implement an isometric WASD movement system. The problem is that I don’t know how to match the “Up” , “Right” , “Left” and “Down” orientation of the character to the ones that camera have. Here is an image describing the issue:

Blue is what I want.
Red is what I have (Using character controller and its Move() function).

Any help is appreciated, thanks in advance!

Your image doesn’t show up. I solved this problem before though. very simple solution.

I created blank game object, just the transform inside and had the camera transfer the y.rotation to the transform of this widget.

// Credit: AngryFoxGames
using UnityEngine;
using System.Collections;

public class CopyCamera : MonoBehaviour {
	public GameObject GameCamera;
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		gameObject.transform.position = GameCamera.transform.position;
		gameObject.transform.rotation = GameCamera.transform.rotation;
		transform.eulerAngles = new Vector3 (0,transform.eulerAngles.y,0);
	}
}

Then you can use the copycamera transform the find the forward direction. Z pos of the transform that has copy camera will be forward. And X pos will be right. So you can grab this transform by this pseudocode.

if (input == W)
{
     MyCharacterPos += CopyCamera.transform. forward * Time.deltatime;
}
if (input == D)
{
     MyCharacterPos += CopyCamera.transform.right * Time.deltatime;
}

This solved the issue nicely, an easy hack.

Thank you!

Indeed your solution worked! but now I’m having a problem with the speed of the diagonal movements (it is faster than the vertical and horizontal movements).

Here is my code:

	public void UpdatePlayerPosition(float xMagnitude, float zMagnitude)
	{
        /* My "CopyCamera" */
		GameObject movementCamera = playerStatusController.movementCamera;
		

		/* Direction calculations */
		Vector3 newMovement = new Vector3(movementCamera.transform.forward.x,0,movementCamera.transform.forward.z) * -zMagnitude +
							  new Vector3(movementCamera.transform.right.x,0,movementCamera.transform.right.z) * xMagnitude;
		
         /* Character controller movement (factored with time and the character speed) */
		charController.Move(newMovement * Time.deltaTime * playerStatusController.currentMovementSpeed);

	}

I’ll try clamping the value of the movement’s direction vector, but if any of you know an elegant solution for this I’ll use it!

Thanks in advance for your help!

Lol it worked just by changing

         /* Character controller movement (factored with time and the character spee) */
        charController.Move(newMovement * Time.deltaTime * playerStatusController.currentMovementSpeed);

for

         /* Character controller movement (factored with time and the character spee) */
        charController.Move(newMovement.normalized * Time.deltaTime * playerStatusController.currentMovementSpeed);

This solution is specially useful if you’re using smooth input like the one of a gamepad joystick

Thanks for the code update, when I created mine I didn’t normalize, I did not have that problem as much because mine was used for camera scrolling.

Hmm it seems that this solution have another problem: if you normalize the direction vector ( in my case newMovement) you’ll lose the magnitude of your input, in this case, causing that the player moves at the same speed no matter how higher or lower is the movement input’s value . This only happens if you use analog input which sadly is my case ::frowning:

I’ll start experimenting with solutions. Any help is appreciated!


UPDATE:

Here you have the fixed version. The magnitude clamp’s values were obtained by trial and error. I suspect that this have a trigonometric background and I really don’t like making code without knowing exactly why it works but until I find out it’ll suffice. Thank you all for your help! (still, any insight on this problem or a more elegant solution are welcome)

Player Controller

public void UpdateTargetDirection(float xMagnitude, float zMagnitude)
{
	// The new movement vector is calculated
	Vector3 newMovement = movementCamera.transform.forward * -zMagnitude +
						  movementCamera.transform.right * xMagnitude;

	// Magnitude fix
	newMovement = Vector3.ClampMagnitude(newMovement,1/Mathf.Sqrt(2)) * Mathf.Sqrt(2);
	
	// The player is moved according to his speed
	charController.Move(newMovement * Time.deltaTime * playerStatusController.currentMovementSpeed);
			
}

“Movement” Camera

public GameObject GameCamera;
void Update () {
	// Copy the rotation and position of the main camera
	gameObject.transform.position = GameCamera.transform.position;
	gameObject.transform.rotation = GameCamera.transform.rotation;
	
	// Zero the axis in which the player will move
	transform.eulerAngles = new Vector3 (0,transform.eulerAngles.y,0);
}
1 Like

I was using this as a camera controller, so what I did it it applied additional force when the button was pressed, the camera had a collider and rigid body, with a layer mask applied so it didn’t hit the objects around the camera. so of course it you have to adapt it.

I noticed you’re applying a transform to the character. Why don’t you use the physic’s engine, or the character controller? The character controller isn’t a rigid body and can handle movement and jumping.

If you want your keys to work like a gas peddle, so the longer or harder you press the more power it gives. Check out the race car demo at the asset store for its controls. The keypress gave off values between 0.0 and 1.0. What you can do is create a singleton which gets a value for each input button, add a time value for each frame is pressed down to a maximum of a second/half-second or whatever.

So:

Char.transform.position += DirectionMagnetude * Time.deltatime * speed * yourinput.keystrength

And we can do this quick example

using UnityEngine;
using System.Collections;

public class CharacterInput : MonoBehaviour {
	/// <summary>
	/// This will Make the Cube move into the distance based on a speed of how long the button is held down
	/// </summary>
	public GameObject ACube;
	public float keystrength = 0.0f;
	public float speed = 5;
	
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		if (Input.GetKey("space") == true)
		{
			//Detects how long the key is held down and creates a magnetude.
			if ((keystrength + (1.0f/60.0f)) <= 1.0f)
			{
				keystrength = keystrength + (1.0f/60.0f);
				print ("KeyStrength: " + keystrength);
			}
			else
			{
				//This is fixing the floating point error.
				keystrength = 1.0f;
			}
		}
		else
		{
			//Resets the key to zero.
			keystrength = 0;
		}
		ACube.transform.position += ACube.transform.up * keystrength * speed * Time.deltaTime;  
		
	}
}

Hi, new here. just a thought

	if (Input.GetKey("space") == true)

could be better written as

	if (Input.GetKey("space"))

just my 2 pence.

Thanks mate! It fixed my problem