- Home /
Disabling diagonal movement in Unity 5 2D? (using C#)
Or rather I should say, "EFFECTIVELY disabling diagonal movement".
There are plenty of Q/As online about this, but I keep encountering the same problem: When moving horizontally (left, for example), I can override the current direction and start moving vertically (by pushing up), which is what I want. But it does not work the other way around! Vertical movement can not override horizontal movement.
void Update () {
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
ManageMovement(h, v);
}
void ManageMovement(float horizontal,float vertical) {
if (vertical != 0f) {
horizontal = 0f;
Vector3 movement = new Vector3 (horizontal, vertical, 0);
GetComponent<Rigidbody2D> ().velocity = movement * speed;
return;
}
if (horizontal != 0f) {
vertical = 0f;
Vector3 movement = new Vector3 (horizontal, vertical, 0);
GetComponent<Rigidbody2D> ().velocity = movement * speed;
return;
} else {
Vector3 noMovement = new Vector3 (0, 0, 0);
GetComponent<Rigidbody2D> ().velocity = noMovement;
}
}
If I reverse the order of these if() statements, it reverses the problem. So, that's a clue. But I'm not a great detective. I would love some help!
Whichever executes last will win.
Perhaps think about a 'last change' system which uses 1 variable to indicate the state and your logic populates that field.
Answer by Dave-Carlile · Jul 15, 2015 at 03:44 PM
Part of the problem is that you're looking for the direction component that's not zero. Assuming you're using a gamepad it's likely that both directions will be non-zero. The way you have the code structured, the last if
will always win. If you add an else
before if (horizontal...
then the first one that's non-zero will always win.
What will probably work better is for you to compare the direction components against each other, so the bigger one wins.
if (h > v)
{
// input is more horizontal than vertical so move horizontally
}
else if (v > h)
{
// input is more vertical than horizontal so move vertically
}
else
{
// don't move
}
Yeah comparing to 0 is asking for trouble. Need Dead-Zone.
I'm trying this solution currently, and it's yielding really weird results. $$anonymous$$ovement up and right work, although kind of un-reliably, and movement left and down don't work at all. The part of this solution I don't understand is.. the input is binary right? So either, "key is being pushed" or "key is not being pushed", so if both keys were being pushed, why would if (h > v) or (v > h) be useful? Because if both were being pushed, wouldn't they be equal?
You want $$anonymous$$athf.Abs(h) > $$anonymous$$athf.Abs(v)
to deal with the left and down movement.
As to your second question, it pretty much depends on the behavior you want. If both are being pushed then yes, movement would stop using my code when using the keyboard. What exactly do you want to happen? So far we only know that you don't want to move diagonally.
If the player is holding down the right key and then presses the up key while continuing to hold down the right key, what is the behavior you want? I assume it's whatever the most recent input was?
Using my previous assumption, you need to track the state changes for each direction - transitioning to horizontal or vertical, and transitioning out of horizontal or vertical...
I haven't tested this, but I think it should cover what you're looking for. The key is detecting the transitions, e.g. "If we have horizontal input this frame, but we didn't last frame, then zero out the vertical component and move horizontally".
If vertical and horizontal input are both added in the same frame, one of them has to win, and that will depend on the order in the code - the last one will win.
Vector2 direction; // this keeps track of our current movement direction
bool WasHorizontal { get { return $$anonymous$$athf.Abs(direction.x) != 0; } }
bool IsHorizontal { get { return $$anonymous$$athf.Abs(h) != 0; } }
bool WasVertical { get { return $$anonymous$$athf.Abs(direction.y) != 0; } }
bool IsVertical { get { return $$anonymous$$athf.Abs(v) != 0; } }
void Update()
{
// if horizontal movement was removed this frame then clear the horizontal component
if (!IsHorizontal and WasHorizontal)
{
direction.x = 0;
}
// if vertical movement was removed this frame then clear the vertical component
if (!IsVertical and WasVertical)
{
direction.y = 0;
}
// if horizontal movement was added this frame then switch to horizontal
if (IsHorizontal && !WasHorizontal)
{
direction = new Vector2(h, 0);
}
// if vertical movement was added this frame then switch to vertical
if (IsVertical && !WasVertical)
{
direction = new Vector2(0, v);
}
// TODO : apply the direction vector to the object position
}
Hey Dave! It looks like you put a lot of thought into this, thank you so much. I copied the code almost entirely, although there were a couple errors I got thrown. First 'v' and 'h' were out of scope for use in the bools, that was an easy fix, I just brought them up and declared them outside of update()
first. Then I got errors for if (!IsHorizontal and WasHorizontal)
and if (!IsVertical and WasVertical)
. It was not cool with the use of and
; (I changed it to &&) I assumed that was what you meant?
So, long story short. It runs, but unfortunately nothing has changed! When you're pressing right, the player moves right, you can then push up (while still holding right) and start moving up. Which is exactly the desired response, new keys should override old keys. But, vertical movement still can't be overridden by horizontal movement! I can't work it out. :/