8 directional Movement question

Hey there,

i have a question and maybe someone can lead me to a clean solution.
my game is top down and the player is always in the middle of the screen.

on mobile i use the joystick

Vector3 moveDirection = GetMoveDirection(InputManager.GetAxis("Horizontal", raw), InputManager.GetAxis("Vertical", raw));

with that i can simple let the character move like joystick direction. → changing Horizontal and Vertical Axis.
now i want to make same behaviour on computer. but there i dont have a joystick instead player should move with the mouse. so when right click on mouse he should start moving in the direction where the mouse is on the screen

like if mouse is above (norht) of player he should walk upwards, if mouse is right he should walk right.
like Horizontal/vertical value like in Joystick should change where the mouse is depends from the player

i attached a picture to show what i mean.

i dont know whats best solution to change vertical/horizontal value depends on mouse position.
actualy i need a vector 3 that change x and z value depends on mouse pos.


Noone a hint? :confused:

Steps to success:

when you click:

  • read the mouse, find where it means in world space (tons of tutorials on this)

  • subtract your player’s position from the world mouse position

  • normalize that vector

  • feed those into your normal input handling.

1 Like

Well, that’s rather trivial. There are generally several different approaches to this. The first one tries to find the sector the mouse is in by using several nested if statements to test the normalized x / z coordinates agains certain values to figure out which sector is the closest one. This would be one of the fastest solution but also one of the most complex one. Even though you can re-use certain insights thanks to reflection cases, the overall structure would get quite complex.

Another approach is to simply normalize the unclamped direction, round each component seperately and re-normalize the result. I’ve explained that approach over here. However this has some issues as the diagonal sectors are slightly larger than the lateral ones.

Finally and probably the most flexible approach is to simply convert the direction into an angle (with Atan2), discretise the value into 8 sections and convert it back to a vector using Sin and Cos. This is pretty straight forward:

Of course our incoming direction vector has to be centered at the center of the screen (or whatever your center should be). So for a given direction to the mouse position you can do

int dirCount = 8;
float angle = Mathf.Atan2(dir.z, dir.x);
float normalized = Mathf.Repeat(angle / (Mathf.PI*2f), 1f);
angle = Mathf.Round(normalized * dirCount)*Mathf.PI*2f / dirCount;
dir.x = Mathf.Cos(angle);
dir.z = Mathf.Sin(angle);

This assumes that “dir” is the relative mouse position to the center point in the x-z plane (since you said it’s a top down game. If you use the x-y plane, of course just replace z with y). First we calculate the angle our relative direction makes with the positive x axis in radians with Atan2. Next we bring our angle into an angle in the range between 0 and 1. Now we simply multiply by the number of sectors we want to clamp the direction to, in our case 8. When we round that value we get a whole number between 0 and 8 where each whole number represents one of the 8 directions. Of course 0 and 8 are the same direction (just like 0° and 360° are the same). After that we simply divide again by 8 to get back our normalized but now clamped “angle”. We also convert back to radians by multiplying by 2pi. Finally we can create a new direction vector based on the given clampled angle. This does work with any number of direction sectors. So using 4 as dirCount would clamp to just the 4 lateral directions.

3 Likes

thank you for the answer,

but i dont understand how i get the a vector3 with this script.
i mean the variable X and Z from ventor3 should change from 0-1 depends on mouse position around the player.

in your example above i mache Vector3 dir;
when i debug it i always got the same value.

i tried to make Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); to geht mouse pos in worldgrid

but i dont get the result i need

i made a short gif where u can see what i mean.

this is the vector3 i get when i walk with W A S D using Horizintal Vertical Axis.

i exactly need to get this value when i hover mouse around player like:

Screen capture - 9111b4486f0e447c3965307c1faf18e9 - Gyazo (in this video i still walked with WASD and hover mouse on that position where the player should walk, just to show what i mean)

As I said “dir” should be the direction vector from your center to your mouse pos. There’s not really a reason in a 2d top down game to do any fancy screen to world conversions. What you can do is simply:

var mousePos = Input.mousePosition;
dir = new Vector3(mousePos.x - Screen.width*0.5f, 0, mousePos.y- Screen.height*0.5f);

This should already give you a “smooth” direction vector from your screen center to your mouse position. Of course you probably want to normalize this vector in order to keep it the same length. However when you do the “snapping” code I posted above, there’s no need to normalize it first as we convert the vector into an angle and then back to a vector of length one anyways.

I haven’t really tested this code (Since I haven’t started Unity for long time ^^) though this code in Update should give you that direction vector you’re looking for:

var mousePos = Input.mousePosition - new Vector3(Screen.width, Screen.height)*0.5f;

int dirCount = 8;
float angle = Mathf.Atan2(mousePos.y, mousePos.x);
float normalized = Mathf.Repeat(angle / (Mathf.PI*2f), 1f);
angle = Mathf.Round(normalized * dirCount)*Mathf.PI*2f / dirCount;
dir = new Vector3(Mathf.Cos(angle), 0f, Mathf.Sin(angle));
1 Like

hy that works like charm :slight_smile: thank you very much for your help