2D Grapple Gun Quest: Eye on the Prize struggle

Hello! I was hoping to create the inverse of what was already solved up to this point. For example, when the RMB is pressed instead of the LMB, the object clicked on is pulled towards Mr. Slinky instead of Mr. Slinky being pulled towards the object. I’ve got it set up with a couple bools and a tag to distinguish between a “pullable” object or not, BUT I can’t seem to reverse the direction.

Am I thinking this is easier than it is?

public class GrapplingHook : MonoBehaviour
{
    DistanceJoint2D joint;
    Vector3 targetPos;
    RaycastHit2D hit;

    [SerializeField] LayerMask mask;
    [SerializeField] LineRenderer line;
    [SerializeField] GameObject playerHand;

    [SerializeField] float distance = 10f;
    [SerializeField] float grappleSpeed = 3f;
    [SerializeField] float pullObjectSpeed = 4f;

    [SerializeField] bool isBeingPulled = false;
    [SerializeField] bool isPulling = false;

    private void Start()
    {
        joint = GetComponent<DistanceJoint2D>();
        joint.enabled = false;
        line.enabled = false;
    }

    private void Update()
    {
        GrappleEnvironment();
        GrappleObject();
        ReleasePlayer();
    }

    private void PullPlayer()
    {
        joint.distance -= Time.deltaTime * grappleSpeed;
    }

    private void GrappleEnvironment()
    {
        if (!isPulling)
        {
            PullPlayer();

            if (Input.GetMouseButtonDown(0))
            {
                targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                targetPos.z = 0;

                hit = Physics2D.Raycast(playerHand.transform.position, targetPos - playerHand.transform.position, distance, mask);

                if (hit.collider != null && hit.collider.gameObject.GetComponent<Rigidbody2D>() != null && hit.collider.tag != "Pullable")
                {
                    joint.enabled = true;

                    joint.connectedBody = hit.rigidbody;

                    joint.connectedAnchor = hit.rigidbody.transform.InverseTransformPoint(hit.point);

                    joint.distance = Vector2.Distance(playerHand.transform.position, hit.point);

                    line.enabled = true;
                    line.SetPosition(0, playerHand.transform.position);
                    line.SetPosition(1, hit.point);
                }
            }

            if (Input.GetMouseButton(0) && hit.collider != null && hit.collider.tag != "Pullable")
            {
                print("pulling player");
                isBeingPulled = true;
                line.SetPosition(0, playerHand.transform.position);
            }

            if (Input.GetMouseButtonUp(0))
            {
                joint.enabled = false;
                line.enabled = false;
                isBeingPulled = false;
            }
        }
    }

    private void PullObject()
    {
        joint.distance -= Time.deltaTime * pullObjectSpeed;
    }

    private void GrappleObject()
    {
        if (!isBeingPulled)
        {
            PullObject();

            if (Input.GetMouseButtonDown(1))
            {
                targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                targetPos.z = 0;

                hit = Physics2D.Raycast(playerHand.transform.position, targetPos - playerHand.transform.position, distance, mask);

                if (hit.collider != null && hit.collider.gameObject.GetComponent<Rigidbody2D>() != null && hit.collider.tag == "Pullable")
                {
                    joint.enabled = true;

                    joint.connectedBody = hit.rigidbody;

                    joint.connectedAnchor = hit.rigidbody.transform.InverseTransformPoint(hit.point);

                    joint.distance = Vector2.Distance(playerHand.transform.position, hit.point);

                    line.enabled = true;
                    line.SetPosition(0, playerHand.transform.position);
                    line.SetPosition(1, hit.point);
                }
            }

            if (Input.GetMouseButton(1) && hit.collider != null && hit.collider.tag == "Pullable")
            {
                print("pulling object");
                isPulling = true;
                line.SetPosition(0, playerHand.transform.position);
            }

            if (Input.GetMouseButtonUp(1))
            {
                joint.enabled = false;
                line.enabled = false;
                isPulling = false;
            }
        }
    }

    private void ReleasePlayer()
    {
        if (Vector2.Distance(transform.position, hit.point) < 0.25f)
        {
            joint.enabled = false;
            line.enabled = false;
        }
    }
}

Thanks you in advance for any help!

After watching a few more videos, I found a similar component called the Spring Joint 2D. Trial and error led me to the following. Left click and holding on an appropriate “environment” object will pull the player towards the environment, while click and holding on a “pullable” object will pull it to the player. For the most part, I just replaced the distanceJoint with a springJoint reference, set the line renderer up to follow the hit.transform.position while holding the RMB and then made a ReleaseObject method that somewhat mirrors the ReleasePlayer() method from earlier.

public class GrapplingHook : MonoBehaviour
{
    DistanceJoint2D distanceJoint;
    SpringJoint2D springJoint;
    Vector3 targetPos;
    RaycastHit2D hit;

    [SerializeField] LayerMask mask;
    [SerializeField] LineRenderer line;
    [SerializeField] GameObject playerHand;

    [SerializeField] float distance = 10f;
    [SerializeField] float grappleSpeed = 3f;
    [SerializeField] float pullObjectSpeed = 4f;

    [SerializeField] bool isBeingPulled = false;
    [SerializeField] bool isPulling = false;

    private void Start()
    {
        distanceJoint = GetComponent<DistanceJoint2D>();
        springJoint = GetComponent<SpringJoint2D>();
        distanceJoint.enabled = false;
        springJoint.enabled = false;
        line.enabled = false;
    }

    private void Update()
    {
        GrappleEnvironment();
        GrappleObject();
        ReleasePlayer();
        ReleaseObject();
    }

    private void PullPlayer()
    {
        distanceJoint.distance -= Time.deltaTime * grappleSpeed;
    }

    private void GrappleEnvironment()
    {
        if (!isPulling)
        {
            PullPlayer();

            if (Input.GetMouseButtonDown(0))
            {
                targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                targetPos.z = 0;

                hit = Physics2D.Raycast(playerHand.transform.position, targetPos - playerHand.transform.position, distance, mask);

                if (hit.collider != null && hit.collider.gameObject.GetComponent<Rigidbody2D>() != null && hit.collider.tag != "Pullable")
                {
                    distanceJoint.enabled = true;

                    distanceJoint.connectedBody = hit.rigidbody;

                    distanceJoint.connectedAnchor = hit.rigidbody.transform.InverseTransformPoint(hit.point);

                    distanceJoint.distance = Vector2.Distance(playerHand.transform.position, hit.point);

                    line.enabled = true;
                    line.SetPosition(0, playerHand.transform.position);
                    line.SetPosition(1, hit.point);
                }
            }

            if (Input.GetMouseButton(0) && hit.collider != null && hit.collider.tag != "Pullable")
            {
                isBeingPulled = true;
                line.SetPosition(0, playerHand.transform.position);
            }

            if (Input.GetMouseButtonUp(0))
            {
                distanceJoint.enabled = false;
                line.enabled = false;
                isBeingPulled = false;
            }
        }
    }

    private void PullObject()
    {
        springJoint.distance -= Time.deltaTime * pullObjectSpeed;
    }

    private void GrappleObject()
    {
        if (!isBeingPulled)
        {
            PullObject();

            if (Input.GetMouseButtonDown(1))
            {
                targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                targetPos.z = 0;

                hit = Physics2D.Raycast(playerHand.transform.position, targetPos - playerHand.transform.position, distance, mask);

                if (hit.collider != null && hit.collider.gameObject.GetComponent<Rigidbody2D>() != null && hit.collider.tag == "Pullable")
                {
                    springJoint.enabled = true;
                 
                    springJoint.connectedBody = hit.rigidbody;

                    springJoint.connectedAnchor = hit.rigidbody.transform.InverseTransformPoint(hit.point);

                    springJoint.distance = Vector2.Distance(playerHand.transform.position, hit.point);

                    line.enabled = true;
                    line.SetPosition(0, playerHand.transform.position);
                    line.SetPosition(1, hit.point);
                }
            }

            if (Input.GetMouseButton(1) && hit.collider != null && hit.collider.tag == "Pullable")
            {
                isPulling = true;
                line.SetPosition(1, hit.transform.position);
            }

            if (Input.GetMouseButtonUp(1))
            {
                springJoint.enabled = false;
                line.enabled = false;
                isPulling = false;
            }
        }
    }

    private void ReleasePlayer()
    {
        if (isBeingPulled)
        {
            if (Vector2.Distance(transform.position, hit.point) < 0.25f)
            {
                distanceJoint.enabled = false;
                line.enabled = false;
                isBeingPulled = false;
            }
        }
    }

    private void ReleaseObject()
    {
        if (isPulling)
        {
            if (Vector2.Distance(transform.position, hit.transform.position) < 0.5f)
            {
                springJoint.enabled = false;
                line.enabled = false;
                isPulling = false;
            }
        }
    }
}

Thanks!

1 Like

Privacy & Terms