Make a 2D Grappling Hook Game in Unity – Part 2

How to make a 2D grappling hook in Unity – part 2. In this part you will learn how to unwrap your rope as you swing back past the pivot points. By Sean Duffy.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 2 of this article. Click here to view the first page.

Contents

Hide contents

Unwrapping

Take a look at this annotated screen capture where our friendly slug has anchored to a rock, then swung upward, wrapping the grappling hook rope around a rock edge on its way up.

You'll notice that at the apex of its swing, where the slug is a solid color, its current closest wrap point (where the white dot is) would be saved in the wrapPointsLookup dictionary with a value of 1.

On its way down, as playerAngle becomes less than hingeAngle (those two dotted green lines) as illustrated by the blue arrow, a check will be made, and if the wrap point's last (current) value was 1, then the point should be unwrapped.

You'll now code that logic in. But before you do that, create a placeholder for the method that will do the unwrapping first. Then the logic you're about to add won’t cause an error after you create it.

Add a new method UnwrapRopePosition(anchorIndex, hingeIndex) by adding the following lines:

private void UnwrapRopePosition(int anchorIndex, int hingeIndex)
{

}

After you've done that, return to HandleRopeUnwrap(). Just below the newly added variables, add the following logic which will handle the two cases, where playerAngle is less than hingeAngle, or playerAngle is greater than hingeAngle:

if (playerAngle < hingeAngle)
{
    // 1
    if (wrapPointsLookup[hingePosition] == 1)
    {
        UnwrapRopePosition(anchorIndex, hingeIndex);
        return;
    }

    // 2
    wrapPointsLookup[hingePosition] = -1;
}
else
{
    // 3
    if (wrapPointsLookup[hingePosition] == -1)
    {
        UnwrapRopePosition(anchorIndex, hingeIndex);
        return;
    }

    // 4
    wrapPointsLookup[hingePosition] = 1;
}

This code should align with the explanation of the logic above for the first case (where playerAngle < hingeAngle), but also handles the other case (where playerAngle > hingeAngle).

  1. If the current closest wrap point to the slug has a value of 1 at the point where playerAngle < hingeAngle then unwrap that point, and return so that the rest of the method is not handled.
  2. Otherwise, if the wrap point was not last marked with a value of 1, but playerAngle is less than the hingeAngle, the value is set to -1 instead.
  3. If the current closest wrap point to the slug has a value of -1 at the point where playerAngle > hingeAngle, unwrap the point and return.
  4. Otherwise, set the wrap point dictionary entry value at the hinge position to 1.

This code will now ensure that the wrapPointsLookup dictionary is always updated to ensure the current wrap point (closest to the slug) is always up to date with the slug's current angle relative to the wrap point.

Remember that -1 is when the slug's angle is less than the hinge angle (relative to the anchor position), and that 1 is when the slug's angle is greater than the hinge angle.

Now complete UnwrapRopePosition() in the RopeSystem script with the code that will actually do the unwrap by moving the anchored position and resetting the rope's DistanceJoint2D distance value to the new distance. Add the following lines to the placeholder you created earlier:

    // 1
    var newAnchorPosition = ropePositions[anchorIndex];
    wrapPointsLookup.Remove(ropePositions[hingeIndex]);
    ropePositions.RemoveAt(hingeIndex);

    // 2
    ropeHingeAnchorRb.transform.position = newAnchorPosition;
    distanceSet = false;

    // Set new rope distance joint distance for anchor position if not yet set.
    if (distanceSet)
    {
        return;
    }
    ropeJoint.distance = Vector2.Distance(transform.position, newAnchorPosition);
    distanceSet = true;
  1. The current anchor index (the second rope position away from the slug) becomes the new hinge position and the old hinge position is removed (the one that was previously closest to the slug that we are now 'unwrapping'). The newAnchorPosition variable is set to the anchorIndex value in the rope positions list. This will be used to position the updated anchor position next.
  2. The rope hinge RigidBody2D (which is what the rope's DistanceJoint2D is attached to) has its position changed here to the new anchor position. This allows the seamless continued movement of the slug on his rope as he is connected to the DistanceJoint2D, and this joint should allow him to continue swinging based off the new position he is anchored to — in other words, the next point down the rope from his position.
  3. Next, the distance joint's distance value needs to be updated to account for the sudden change in distance of the slug to the new anchor point. A quick check against the distanceSet flag ensures that this is done, if not already done, and the distance is set based on calculated the distance between the slug and the new anchor position.

Save your script and return to the editor. Run the game again, and marvel at the rope unwrapping from edges as the slug passes each wrap point threshold!

Although the logic is complete, add one small bit of housekeeping code to HandleRopeUnwrap() just before the check of playerAngle against hingeAngle (if (playerAngle < hingeAngle)).

if (!wrapPointsLookup.ContainsKey(hingePosition))
{
    Debug.LogError("We were not tracking hingePosition (" + hingePosition + ") in the look up dictionary.");
    return;
}

This shouldn't really ever happen, as you're already resetting and detaching the grappling hook if it wraps around an edge twice, but it doesn't hurt to bail out of this method if this does happen with a simple return statement and an error message to the console.

Plus it makes you feel rather dapper when you handle edge cases like this; and furthermore, you get a custom error message indicating you've done something you shouldn't have.

Where to Go From Here?

Here's a link to the completed project for this second and final part of the tutorial.

Congratulations on completing this tutorial series! Things got pretty complex with all the angle and position comparisons, but you persevered and now have great grappling hook and rope system that can wrap and unwrap objects in your game like nobody's business.

Did you know the Unity team has created a book? If not, check out Unity Games By Tutorials. The book will teach you to create four complete games from scratch:

  • A twin-stick shooter
  • A first-person shooter
  • A tower defense game (with VR support!)
  • A 2D platformer

By the end of this book, you’ll be ready to make your own games for Windows, macOS, iOS, and more!

This book is for complete beginners to Unity, as well as for those who’d like to bring their Unity skills to a professional level. The book assumes you have some prior programming experience (in any language).

If you have any questions or comments on this tutorial or tutorial series as a whole, please join the discussion below!

Sean Duffy

Contributors

Sean Duffy

Author

Gijs Bannenberg

Tech Editor

Chris Belanger

Editor

Eric Van de Kerckhove

Final Pass Editor and Team Lead

Over 300 content creators. Join our team.