简体   繁体   中英

Set rigidbody.velocity to direction of mouse in Unity2d: Updated Version

Yes I know this question was asked before by SuperSonyk: That post is here: Set rigidbody.velocity to direction of mouse in Unity2d

However- the link referenced in the answer to that post is now legacy material, and I can't bring myself to understand it in Unity's current version.

My Problem: In short, I want to make my player accelerate in the direction of my cursor. My game is currently a TOP-DOWN Space Shooter in 2D. My player already looks at my mouse correctly, using cam.ScreenToWorldPoint. But relentlessly trying to add force seems futile for me, since I am fairly new to coding.

If I have any other issues in my code, It would be great if anyone could point them out: Here's my code:

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

public class PlayerController : MonoBehaviour
{
    //================= MOVEMENT =====================
    private float thrust = 0.5f;
    private float maxSpeed = 10f;
    public Rigidbody2D rb;

    //================= AIMING =======================
    public Camera cam;
    Vector2 mousePos;

    // Update is called once per frame: Good for INPUTS
    void Update()
    {
        //aiming
        mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
    }
    // Called Set amount of times. Good for PHYSICS CALCULATIONS
    void FixedUpdate()
    {
        Move();
        speedLimiter();

        //aim
        Vector2 lookDirection = mousePos - rb.position;
        float angle = Mathf.Atan2(lookDirection.y, lookDirection.x) * Mathf.Rad2Deg - 90f;
        rb.rotation = angle;
    }
    //======= MY MOVE FUNCTION DOES NOT WORK. HELP? ======
    void Move()
    {
        if (Input.GetButtonDown("Accelerate"))
        {
            rb.velocity = new Vector3(0, thrust, 0) * Time.deltaTime;
        }
    }
    void speedLimiter()
    {
        if (rb.velocity.magnitude > maxSpeed)
        {
            rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
        }
    }
}

Please summarize the edits clearly, thank you!

In general since this is a 2D rigidbody also the velocity is a Vector2 and you should probably rather use Vector2.ClampMagnitude

and then in

rb.velocity = new Vector3(0, thrust, 0) * Time.deltaTime; 

do you only want to move in global Y direction? Also a velocity is already a "per second" value -> it makes no sense to multiply by Time.deltaTime if you reassign a new velocity. Since it says thrust I guess you rather wanted to add to the existing velocity.


What you would rather do is save your mouse direction you already have and do

public class PlayerController : MonoBehaviour
{
    ...

    void FixedUpdate()
    {
        // I would update the aim BEFORE moving
        // Use a NORMALIZED direction! Makes things easier later
        Vector2 moveDirection = (mousePos - rb.position).normalized;
        float angle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg - 90f;
        rb.rotation = angle;

        // OPTIONAL: Redirect the existing velocity into the new up direction 
        // without this after rotating you would still continue to move into the same global direction    
        rb.velocity = rb.velocity.magnitude * moveDirection;

        Move(moveDirection);
        speedLimiter();
    }
    
    void Move(Vector2 moveDirection)
    {
        if (Input.GetButtonDown("Accelerate"))
        {
            // Instead of re-assigning you would probably add to the existing velocity
            // otherwise remove the "+" again
            rb.velocity += moveDirection * thrust * Time.deltaTime;
        }
    }

    void speedLimiter()
    {
        if (rb.velocity.magnitude > maxSpeed)
        {
            // You are working with Vector2 so use the correct method right away
            rb.velocity = Vector2.ClampMagnitude(rb.velocity, maxSpeed);
        }
    }
}

You already have half of the work by having your player looking at the mouse. We will be using the vector lookDirection as the direction of the movement for the player, normalize it so its length is 1 and multiply it by thrust . This way, we have a vector in the direction of the mouse and of length thrust as intended.

void Move()
{
  if (Input.GetButtonDown("Accelerate"))
  {
    Vector2 lookDirection = (mousePos - rb.position);
    rb.AddForce(lookDirection.normalized  * thrust);
  }
}

Note that we work here with Vector2 since you are using a Rigidbody2D.

Also, I don't think that using Time.DeltaTime is relevant here. When you apply force to a physic object, you don't need to use it, by definition, the function FixedUpdate() has a fixed frequency. If you look at one of Unity's tutorial , you can see that they don't multiply it by Time.DeltaTime

Last tip: you may want to be playing around with the drag property of your Rigidbody2D to have your player slow down over time when not accelerating, otherwise, it will be sliding out of control and the player won't be able to stop it.

Don't hesitate to tell me if my answer is not clear for you or does not entirely satisfy you, it's my first answer here!

EDIT: I forgot to tell you but as derHugo mentioned, since you are using Rigidbody2D , you must use Vector2.ClampMagnitude to limit your speed in your speedLimiter function. Also, I don't think that you need your if since the function Vector2.ClampMagnitude will only change the value of the velocity if it exceeds the maximum.

Thanks to everyone who responded, With the help of Brackeys community: I managed to solve this by using this method:

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

public class PlayerController : MonoBehaviour
{
    //================= MOVEMENT =====================
    private float thrust = 10f;
    private float maxSpeed = 100f;
    public Rigidbody2D rb;

    //================= AIMING =======================
    public Camera cam;
    Vector2 mousePos;

    // Update is called once per frame: Good for INPUTS
    void Update()
    {
        //aiming
        mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
    }
    // Called Set amount of times. Good for PHYSICS CALCULATIONS
    void FixedUpdate()
    {
        Move();
        speedLimiter();

        //aim
        Vector2 lookDirection = mousePos - rb.position;
        float angle = Mathf.Atan2(lookDirection.y, lookDirection.x) * Mathf.Rad2Deg - 90f;
        rb.rotation = angle;
    }
    void Move()
    {
        if (Input.GetKey("up"))
        {
            rb.AddRelativeForce(Vector2.up*thrust);
        }
    }
    void speedLimiter()
    {
        if (rb.velocity.magnitude > maxSpeed)
        {
            rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
        }
    }
    //rb.AddForce(new Vector3(0, thrust, 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