Can't get boomerang to return to player

I am trying to implement a simple boomerang into my game. Simply, I want the player to throw it, and once it exceeds the throwDistance, I want it to return to the player.

Right now, it throws, then remains spinning in one spot without returning to the player. And if the player approaches, it pushes it further away.

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

public class PlayerBoomerang : MonoBehaviour
{
    public static PlayerBoomerang instance;

    public float speed = 7.5f;
    public Rigidbody2D theRB;
   
    public float throwDistance = 1;

    public int impactSound;

    // Start is called before the first frame update
    void Start()
    {

        theRB.velocity = transform.right * speed;
    }

    // Update is called once per frame
    void Update()
    {
        if(Vector2.Distance(PlayerController.instance.boomerangFirePoint.position, transform.position) > throwDistance)
        {
            transform.position = Vector2.MoveTowards(transform.position, PlayerController.instance.transform.position, speed * Time.deltaTime);
        }
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            Destroy(gameObject);
            PlayerController.instance.isBoomeranging = false;
        }

        if (other.tag == "Enemy")
        {
            //insert knockback script here
            AudioManager.instance.PlaySFX(impactSound);
        }

        if (other.tag == "Boss")
        {
            //insert knockback script here
            AudioManager.instance.PlaySFX(impactSound);
        }

    }


}

Any help is appreciated!

You are re-checking the distance every update. Even if your code detects the boomerang is at the proper range, it will only detect that for one frame.

I think the easiest solution would be to create a “isComingBack” bool that starts false. Once the distance is reached, set the bool to true. Only test the distance if the bool is false, otherwise run the logic to bring it back.

Hope that helps!

Aight I think the reason why your boomerang isnt destroyed when you bump into it is because your collider is not set to trigger, if you select your collider there should be a check box for setTrigger

This definitely did something!

Still having an issue with the boomerang getting stuck in mid-air. Here’s a gif:
https://imgur.com/a/3UU7k0w

The script:

    public static PlayerBoomerang instance;

    public float speed = 7.5f;
    public Rigidbody2D theRB;
   
    public float throwDistance = 1f;

    public bool isReturning;

    public int impactSound;

    // Start is called before the first frame update
    void Start()
    {
        isReturning = false;
        theRB.velocity = transform.right * speed;
    }

    // Update is called once per frame
    void Update()
    {
        if(Vector2.Distance(PlayerController.instance.boomerangFirePoint.position, transform.position) > throwDistance)
        {
            isReturning = true;
        }


        if (isReturning)
        {
            //throwDistance = throwDistance + 1f;

            transform.position = Vector2.MoveTowards(transform.position, PlayerController.instance.transform.position, speed * Time.deltaTime);
       
        }

    }

You need to add code that destroys the boomerang. I recommend you check the distance inside the if check for “isReturning” and destroy the boomerang when it’s close. Another option is to use a collider as @PuppyPolice suggested and destroy the boomerang when it touches you.

Ah but if you take a look at the gif I’m already able to destroy the boomerang - that isn’t my issue. The issue I’m encountering is that the boomerang appears to get stuck mid-air in front of the player and never returns. It’s very strange!

The rigidbody still has forward velocity from the Start function. You’re setting the transform position, and the rigidbody is also setting the transform position. So either use transform.position for everything, velocity for everything, or set velocity to 0 on the return.

Something like this might work (i didnt test this):

private Vector2 throwTarget;

private void Start()
{
    throwTarget = transform.position + transform.right * throwDistance;
}

private void Update()
{
    if (isReturning)
    {
        MoveTowards(PlayerController.instance.transform.position);
    }
    else {
        MoveTowards(throwTarget);

        float distanceToTarget = Vector2.Distance(transform.position, throwTarget);
        if(distanceToTarget <= 0.001f)
        {
            isReturning = true;
        }
    }
}

private void MoveTowards(Vector2 target)
{
    transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);
}

Ah ok, this is a little foreign to me. Can you elaborate a little?

Should I just include:
theRB.velocity = transform.right * -speed; ?

The easiest thing would be to set “theRB.velocity = Vector3.zero” when you set “isReturning” to true.

If you wanted to do the whole thing with velocity, you will need to update the velocity to point toward your player each fame as they move, unless you want the boomerang to fly to where they were instead of where they are.

updated my previous post with a quick code example not using rigidbody. @MSplitz-PsychoK 's solution is easiest, and would work but I think it’s a little weird to use physics for the throw but not the return.

A more specific answer: Rigidbody is used to control the transform using physics calculations. Generally when you use the Rigidbody, you never set the transform.position manually, you let the Rigidbody do it. In your code, you set the Rigidbody’s velocity, so every frame the Rigidbody moves the transform.position accordingly. That won’t end until you change the velocity somehow, or it changes due to other physics forces. So when you start to set transform.position manually in the reverse direction, both your code and the Rigidbody are applying movement. Since the velocity is set to “speed”, and you’re also moving it at “speed” in the other direction, the movement will just about cancel out.

Dude THANK YOU. I tried out what you suggested and that seemed to do it!

Unfortunately now I’m having an issue where the throwDistance isn’t being taken into consideration it seems. When I change the value the boomerang still only travels a short distance. Any thoughts?

Nevermind! Not sure why, but I had to declare the float under Start(). Not sure why, haven’t had to do that before.

So I do have it working properly, but can you comment on this issue?

Not sure what you mean by that, can you share what you have? How are you changing the value?

Yes so under Start() I am having to use:

        throwDistance = 5f;

Even though I’m setting the value when I declare the float (at the top of the document):

    public float throwDistance = 5f;

When you declare a variable as public in a MonoBehaviour, it will be displayed in the inspector for editing. The value in the inspector will overwrite any default value you have assigned in code.

So
public float throwDistance = 5f; is declaring a new variable, and assigning it a default value. Any new components of this type will start with 5 in the inspector. If you edit the inspector value however, the inspector value takes priority.

Ya I am familiar with this, which is why it’s so strange! I’ve never had this issue before. Very odd.

I hate when I’m stupid. I guess at some point I did change the value. So this makes me stupid, but successful.

I hate how these always seem to go hand in hand (facepalm)

Everyone makes mistakes, and that is a very common mistake. Don’t beat yourself up about it.

Seriously thanks for the help. You can see what I made with your help on Instagram: @joneslearnsunity