简体   繁体   中英

Unity 2D Top Down Shooter movement issue C#

I am trying to make a simple 2D Top-Down Shooter in Unity. I have the basic movement and following of the mouse, but there is an issue in the movement.

Whenever you press say Up and Right at the same time, it moves diagonally as you would expect, but when you let go of the Up key, it keeps going diagonally where I want it to move Right. My code for handling the movement is:

private void Update () 
{
    if (Input.GetKey(Up)) {
        Debug.Log("UP");
        Vector3 velUp = rigidbody2D.velocity;
        velUp.y = walkSpeed;
        rigidbody2D.velocity = velUp;
    }
    else if (Input.GetKey(Down)) {
        Vector3 velDown = rigidbody2D.velocity;
        velDown.y = walkSpeed*-1;
        rigidbody2D.velocity = velDown;
    }
    else if (Input.GetKey(Left)) {
        Vector3 velLeft = rigidbody2D.velocity;
        velLeft.x = walkSpeed*-1;
        rigidbody2D.velocity = velLeft;

    }
    else if (Input.GetKey(Right)) {
        Vector3 velRight = rigidbody2D.velocity;
        velRight.x = walkSpeed;
        rigidbody2D.velocity = velRight;
    }
    else {
        Vector3 velStop = rigidbody2D.velocity;
        velStop.x = 0;
        velStop.y = 0;
        rigidbody2D.velocity = velStop;
    }

    //rotation
    Vector3 mousePos = Input.mousePosition;

    Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
    mousePos.x = mousePos.x - objectPos.x;
    mousePos.y = mousePos.y - objectPos.y;

    float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
    transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}

How can I get the movement to behave as I mentioned? With it moving diagonally like this makes the movement seem off.

Any help is greatly appreciated. Thanks.

You start with a velocity of 0, then you add up all the movements directions you have. Then you normalize the vector and scale it to your movement speed. Otherwise the player moves faster, if walking diagonal.

I haven't checked the code, but something like this will do:

void Update () {
    Vector3 vel = new Vector3();

    if(Input.GetKey(Up)){
        Debug.Log("UP");
        Vector3 velUp = new Vector3();
        // just use 1 to set the direction.
        velUp.y = 1;
        vel += velUp;
    }
    else if(Input.GetKey(Down)){
        Vector3 velDown = new Vector3();
        velDown.y = -1;
        vel += velDown;
    }

    // no else here. Combinations of up/down and left/right are fine.
    if(Input.GetKey(Left)){
        Vector3 velLeft = new Vector3();
        velLeft.x = -1;
        vel += velLeft;
    }
    else if(Input.GetKey(Right)){
        Vector3 velRight = new Vector3();
        velRight.x = 1;
        vel += velRight;
    }

    // check if player wants to move at all. Don't check exactly for 0 to avoid rounding errors
    // (magnitude will be 0, 1 or sqrt(2) here)
    if (vel.magnitude > 0.001) {
      Vector3.Normalize(vel);
      vel *= walkSpeed;
      rigidbody2D.velocity = vel;
    }

    //rotation
    Vector3 mousePos = Input.mousePosition;

    Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
    mousePos.x = mousePos.x - objectPos.x;
    mousePos.y = mousePos.y - objectPos.y;

    float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
    transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}

Regarding Normalize have a look at this image.

向量加法

If you walk only upwards or right you would move with speed 1 (which we later multiply with your desired speed). But if you walk diagonal you walk with about 1.4 times the desired speed (green vector). Normalize keeps the direction of the vector intact, but gives you a length (also called "magnitude") of 1 (red vector).

In older shooters you may find a bug called "bunny hopping" . I'm not sure if this is the source of the problem, but I would guess it is.

Regarding vel.magnitude > 0.001 :

We actually want to know if vel.magnitude > 0 . But vel.magnitude is the result of a calculation and thus may contain rounding errors. If you work with floating-point values always keep that in mind. The check itself is done because the Normalize method needs to divide by the magnitude and division by zero is evil. Not sure if Normalize checks for this itself.

It seems the only time you force your velocity to nothing is when there isn't any key being pressed.

I might suggest adding some checks to see when Input.GetKeyUp is true , and set the rigidbody2D.velocity 's x or y values to 0 , maybe something like this:

void Update () {

    if (Input.GetKeyUp(Up) || Input.GetKeyUp(Down)) {
        rigidbody2D.velocity.y = 0;
    }

    if (Input.GetKeyUp(Left) || Input.GetKeyUp(Right)) {
        rigidbody2D.velocity.x = 0;
    }

    ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM