Search code examples
c#unity-game-enginedirection

Direction entity movment glitch in unity 2d


I am creating a game in Unity 2D. I have Dragons that I am adding to the scene. The dragons are only supposed to move in 1 of 4 directions, Up, Down, Left and Right. the dragons that move left and right move exactly as intended. However the dragons that move up and down have a problem in that they move at an angle. All dragons that move upwards move up and to the right at a 45 degree angle. All dragons that move downwards move down and to the left at a 45 degree angle. at first I thought it was a problem with the animator moving the dragon to a different location, but I removed the animator component from the prefab and the problem still persisted.

below is the code I am using to move the dragons.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DragonMovment : MonoBehaviour {
    public string Direction;    //needs to be set in the prefab

    public float DragonSpeed;   //speed of dragon

    Rigidbody2D rb; 

    public Transform Boundries;

    // Use this for initialization
    void Start ()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void FixedUpdate ()
    {
        float MoveRight = 1;
        float MoveLeft = -1;
        float MoveUp = 1;
        float MoveDown = -1;

        if (Direction== "R")
        {
            rb.velocity = new Vector3(DragonSpeed * MoveRight, rb.velocity.y);
        }
        if (Direction == "L")
        {
            rb.velocity = new Vector3(DragonSpeed * MoveLeft, rb.velocity.y);
        }
        if (Direction == "U")
        {
            rb.velocity = new Vector3(DragonSpeed * MoveUp, rb.velocity.x);
        }
        if (Direction == "D")
        {
            rb.velocity = new Vector3(DragonSpeed * MoveDown, rb.velocity.x);
        }


    }
}

Edit. So why does the following work.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControler : MonoBehaviour {
    // speed of movment 
    public float Speed;
    // rb
    Rigidbody2D rb;


    public Transform Boundries;

    // Use this for initialization
    void Start () {
        rb = GetComponent<Rigidbody2D>();
    }

    void FixedUpdate()
    {
        // get horizontal input
        float MoveSide = Input.GetAxis("Horizontal");
        //get vertical input
        float MoveVert = Input.GetAxis("Vertical");
        // move horizontal
        rb.velocity = new Vector3(Speed * MoveVert, rb.velocity.y);
        // move vertical 
        rb.velocity = new Vector3(Speed * MoveSide, rb.velocity.x);
    }
}

but the other code doesent?


Solution

  • You have got the velocity x in the y of the vector 3

    if (Direction == "U")
    {
        rb.velocity = new Vector3(rb.velocity.x, DragonSpeed * MoveUp);
    }
    if (Direction == "D")
    {
        rb.velocity = new Vector3(rb.velocity.x, DragonSpeed * MoveDown);
    }
    

    It works in your player script as you are overriding the values in the subsequent statement.

        float MoveSide = Input.GetAxis("Horizontal"); //eg 1
        float MoveVert = Input.GetAxis("Vertical"); // eg 1
    
        // setting your x velocity incorrectly to the y (vert) velocity speed and keeping y the same velocity as start of frame
        rb.velocity = new Vector3(Speed * MoveVert, rb.velocity.y);
        // Set the y to the x value of the statement above so it is now in the correct vector and set the x to the correct hoz velocity
        rb.velocity = new Vector3(Speed * MoveSide, rb.velocity.x);
    
    // effectively doing 
    rb.velocity = new Vector3(Speed * MoveSide, Speed * MoveVert);
    

    You should also be using MovePosition as it doesn't directly affect the physics engine (using velocity can have knock on effects to collisions and triggers and create unexpected physics). Your gameobjects will have to be marked as kinematic otherwise the below will cause them to teleport to the new position instantly.

    var movementDirection = new Vector3(Speed * MoveSide, Speed * MoveVert);
    rb.MovePosition(transform.position + movementDirection * Time.deltaTime);
    

    And the * Time.deltaTime ensures that movement is consistent for different framerates. If you run the game on a 30 fps machine the game objects will move slower than a 60fps. Time.deltaTime calculates the physical time passed since the previous frame and ensures the distance traveled is the same regardless of frame rate.

    e.g say the gameObject moves 1 per frame update. After a second on a 30 fps machine the object would have moved 30. After a second on a 60 fps machine the object would have moved 60.

    Time.deltaTime=.2s on 30 fps so 1 movement * .2 = move .2 per frame * 30 frames in the second = 60 moved
    Time.deltaTime=.1s on 60 fps so 1 movement * .1 = move .1 per frame * 60 frames in the second = 60 moved