Search code examples
c#unity-game-enginegame-physics

Movement controls (2D scene)


I am having an issue with my movement code I am writing for a top down RPG in 2D. Forgive my lack of knowledge but I have only recently had to learn how to code and this is my first attempt at movement controls. The desired result is to have two input methods; the controller and keyboard. I want to have them separate so when you are using the controller you cannot use the keyboard and vice-versa. Here is the code.

using UnityEngine;
using System.Collections;

public class playerMovement : MonoBehaviour 
{   

    public float Speed = 1;
    private float deadZone = 0.25f;    

    // START - Use this for initialization
    void Start () {}

    // UPDATE is called once per frame - Using deadZone to compensate for faulty controllers etc.... Using options for controller true or false to switch between keyboard and controller input.
    void FixedUpdate () 
    {

        Vector2 stickInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));

        if ( Options.useController == true)
        {
            if( Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.A))
            {
                stickInput = Vector2.zero;
            }
            else if ( stickInput.magnitude < deadZone)
            {
                stickInput = Vector2.zero;
            }
            else
            {
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime;
            }

        }

        //Here is keyboard input - this is working great.
        else if ( Options.useController == false)
        {
            if ( Input.GetKey(KeyCode.A) && Input.GetKey (KeyCode.W))
            {
                stickInput = new Vector2(-1f,1f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime;  
            }
            else if ( Input.GetKey(KeyCode.W) && Input.GetKey (KeyCode.D))
            {
                stickInput = new Vector2(1f,1f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime; 
            }
            else if ( Input.GetKey(KeyCode.S) && Input.GetKey (KeyCode.D))
            {
                stickInput = new Vector2(1f,-1f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime; 
            }
            else if ( Input.GetKey(KeyCode.A) && Input.GetKey (KeyCode.S))
            {
                stickInput = new Vector2(-1f,-1f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime; 
            }
            else if ( Input.GetKey(KeyCode.W))
            {
                stickInput = new Vector2(0f,1f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime; 
            }
            else if ( Input.GetKey(KeyCode.D))
            {
                stickInput = new Vector2(1f,0f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime; 
            }
            else if ( Input.GetKey(KeyCode.S))
            {
                stickInput = new Vector2(0f,-1f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime; 
            }
            else if  ( Input.GetKey(KeyCode.A))
            {
                stickInput = new Vector2(-1f,0f);
                stickInput.Normalize();
                rigidbody2D.velocity = stickInput * Speed * Time.deltaTime; 
            }       
        }




    }
}

The issue arrives when the top loop is executing. I want movement from the keys to be null when useController is equal to true. It works great as long as the key is held down, but as soon as you release the key (A, D, S, W) it exits the if statement and the player is moved by the remaining GetAxis value.

I have to use GetAxis for the controller input in this loop and unfortunately Unity automatically grabs values from the keys. Is there a way I can not only limit the velocity to 0 but also make sure that when the key is released the GetAxis value also becomes 0.


Solution

  • You have to have a rigidbody2d attached to the object you want to move using rigidbody2d.velocity. But, it's not a good idea to do that every frame. Instead, you could use transform.translate, or if you want to keep the physics simulation by using the rigidbodies, use rigidbody2d.addforce.

    Also, in Edit > Project Settings > Input make sure you remove the WSAD keys from the axes.

    Your code should look more something like this

    void FixedUpdate () 
    {
    
        if (Options.useController)
        {
            // if the controller is enabled do this stuff
            Vector2 stickInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
        }
        else
        {
            // else if the controller is not enabled, do this stuff.
            stickinput = new Vector2(0, 0);
            if (Input.GetKey(KeyCode.W)
                stickinput += new Vector2(0, 1);
            if (Input.GetKey(KeyCode.S)
                stickinput += new Vector2(0, -1);
            if (Input.GetKey(KeyCode.A)
                stickinput += new Vector2(-1, 0);
            if (Input.GetKey(KeyCode.D)
                stickinput += new Vector2(1, 0);
            /* can have code like:
             * if (stickinput.x > 0)
             *     animator.crossfade("rightAnimation", 0f);
             * else if (stickinput.x < 0)
             *     animator.crossfade("leftanimation", 0f);
             * else
             *     animator.crossfade("standinganimation", 0f);
             */
        }
    
            transform.Translate(((stickinput.magnitude > 1) ? stickinput.normalized : stickinput) * speed * Time.fixedDeltaTime, Space.Self);
    
            // or use the one commented out below
            // rigidbody2D.AddForce(((stickinput.magnitude > 1) ? stickinput.normalized : stickinput) * speed * Time.fixedDeltaTime);
    
    
    }
    

    Notice I didn't use else if's. If someone holds W and S, it adds to 0 for the y component. I chose Space.Self for local translation, but you could use Space.World to move it in relation to the global axes.