Unity Tutorial – How to make realistic metal chains using HingeJoint2D


Do you want to make a cool dungeon effect for your platformer? Or maybe you just want some décor to spice up your levels? Whatever type of platformer you are making, chains can make a great addition to it, whether it being simple decorations that the player can interact with, or a way to suspend platforms in the air to add an extra dimension to the game.

Making the chain

Click the button below to download the zip file for this tutorial.

Download “2D Metal Chains Unity Projects” 2D Metal Chains.zip – 25 MB

This file contains two Unity projects: a final one that includes all the types of chains that we will see in the tutorial, and an “empty” starting one that just contains all the assets we will need. Open the latter to start the tutorial.

To start making a chain, you will need an image of a simple chain link. I just created a simple stretched circle and a rounded rectangle on Photoshop and added a slight gradient. You can add as much detail or even use an image of a real chain link for a cool effect, but I found simple usually works well.

A simple chain link

You will find this image (and all the others) inside the project’s Sprites folder. Drag it into the scene twice to create two new 2D sprite game objects, and place one above the other to create a small chain like so:

Change both of the tags to something like Chain as this will come in useful later.

Make the bottom link a child of the top so that everything is connected.

Depending on what you are using the chain for, it can be useful to make it interactable, so that when the player walks into it, it moves in the direction of the players force. Therefore, we will need to add a Capsule Collider 2D and also a Rigidbody 2D component to the chain links. The rigidbody element lets it interact with forces such as gravity and the players force, and the collider detects collisions and essentially makes it a solid object rather than just a humble sprite.

For the top link, we will change the Body Type of its Rigidbody 2D to Kinematic and leave the other one as Dynamic. This is because we don’t want the top link to move anywhere so it acts as if it is hung up.

Now comes the main part; the linking of sausages… I mean chains. Luckily, Unity has an extremely useful tool for linking game objects together in the form of the Hinge Joint 2D component. Click on the bottom chain link and add a Hinge Joint 2D component.

Next, we need to click the top button of the hinge joint component called Edit joint angular limits and drag the pivot of this up to where the two links are joined. This allows the link to rotate around the point at which it joins the one above it. Then drag the top chain link from the hierarchy to the Connected Rigid Body property of the Hinge Joint 2D component.

Duplicate the bottom link and position it below the original, and change the connected rigid body to be the link above it. Repeating this gives you a chain of any length you desire!

Adding sound to the chain

To make the chain fit in the environment and feel even more interactable, we need to add sound when you move into them.

There is a very useful audio clip of chains rattling found at freesound.org. I cut each rattle from this clip using Audacity and imported them into the Unity project inside the Sounds folder.

Now go to the PlayerMovement.cs script and add a new Audiosource list variable and call it chainSounds. You will also need a private integer called chainSoundChoice.

public AudioSource[] chainSounds;
private int chainSoundChoice = 0;

In the OnCollisionEnter2D function, we add a check for hitting chains, that when triggered, will play a random chain sound. As you will run into a few chains at the same time, it sounds like the chains are clinking together.

private void OnCollisionEnter2D(Collision2D collision)
{
	if (collision.gameObject.CompareTag("Chain"))
	{
		chainSoundChoice = Random.Range(0, chainSounds.Length);
		chainSounds[chainSoundChoice].Play();
	}
}

Add multiple Audio Source components to your character, with each different chain sound, and then drag each one into the new chainSounds list you created. Make sure you uncheck the Play on Awake box so that they don’t play when the game is launched.

Now you have chains that interact with the character and add an extra dimension to your game! Drag this chain into your prefabs folder and you can place them wherever you like.

Suspended platforms

To make platforms that are suspended on chains is a little different.

Duplicate your chain prefab and remove all capsule colliders from the links. Drag the platform sprite into the scene and make it a child of the top chain. Add a Box Collider 2D so that the player can interact with it.

Next add a Rigidbody 2D component and increase its mass to 5 or something so that it is heavier than the player to give a more realistic swing. You also need to check the Freeze Rotation box under Constraints, so that the platform stays flat when the player lands on it.

Just like the other links, add a Hinge Joint 2D component to the platform, setting the Connected Rigidbody to be the link above, and changing the pivot to where it connects to the chain.

To add sound to these platforms, click on the first child link (the first link with a hinge joint) and just like what you did with the character, add multiple Audio Source components with each chain sound as the Audio Clip element, and the Play on Awake checkbox unticked.

Then create a new C# script called ChainSound and add the following code:

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

public class ChainSound : MonoBehaviour
{
	private HingeJoint2D hinge;
	public AudioSource[] chainSounds;
	private int chainSoundChoice;
	private bool stopSounds = false; //So the sounds don't constantly play

	public int strength = 300; //The force at which the sound will be played. 
	//This will be different depending on the mass and amount of chains.

	private bool letSound = true;

	private void Start()
	{
		hinge = GetComponent<HingeJoint2D>(); //Sets the hinge variable as the connected HingeJoint2D
	}

	void Update()
	{
		if (hinge.reactionForce.magnitude > strength && !stopSounds) //If the force pulling on the hinge is greater than the threshold
		{
			chainSoundChoice = Random.Range(0, chainSounds.Length); //Choosing a random sound so it's not always the same
			chainSounds[chainSoundChoice].Play();
			stopSounds = true; //stops the sounds playing constantly
		}

		else if(hinge.reactionForce.magnitude <= strength && stopSounds)
		{
			stopSounds = false; //resets the stopSounds bool so the sound can be played again 
		}
	}
}

Dragging the Audio Source components into the newly created list, and altering the strength depending on your chain, will make the chain rattle when the character lands on the platform.

You can edit these platforms in any way you want, as we’ll see in the next sections.

Making the chain break when the player lands on it

To do this, you simply need to add a break force to one of the chain links by changing the Break Force property to a number instead of Infinity.

Depending on the mass of the game objects, and the amount of chain links, the breaking force will be different so you will have to tweak it until it is just right. Putting the force too low will make the chain break before the player lands on it, and making it too high will stop it from breaking all together.

Putting a series of hanging platforms, with one that can break over a big gap, or pit of lava, can make the game more interesting as it keeps the player concentrating.

Making a swinging platform

Before we make the swinging platform, we need to add a bit of code to our player so that they move horizontally with the platform. Otherwise, the player will stay still horizontally, and the platform will move from under their feet.

Without code
With code

First, give the platform a tag, for example, Swing. Add this code to your characters script (The PlayerMovement script). I have explained it in the comments, but you will have to change bits depending on your character controller.

Add this to the Update function:

if (Input.GetButtonDown("Jump"))
{
	jump = true;
	jumpCheck = true;
	if (onSwing)
	{
		onSwing = false; //When jumping, you are not on the swing anymore
	}
}

and this to the OnCollisionEnter2D function:

if (collision.gameObject.CompareTag("Swing"))
{
	onSwing = true;
}

Finally add the OnCollisionStay2D and OnCollisionExit2D functions:

private void OnCollisionStay2D(Collision2D collision)
{
	if (collision.gameObject.CompareTag("Swing"))
	{
		//This just determines if the player is trying to move horizontally by pressing the arrow keys etc/
		//It may be different depending on your character controller
		if(Mathf.Abs(horizontalMove) > 1)
		{
			onSwing = false; //stops the process so that the character can move freely
			player.velocity = new Vector2(player.velocity.x, player.velocity.y);
		}
		else
		{
			//This makes the player move in the same direction as the platform and so doesn't fall off
			player.velocity = new Vector2(collision.rigidbody.velocity.x, player.velocity.x);
			onSwing = true;
		}
	}
}

private void OnCollisionExit2D(Collision2D collision)
{
	if (collision.gameObject.CompareTag("Swing"))
	{
		onSwing = false; //Because you are no longer on the swing
	}
}

Now you can make swinging platforms. The hinge joint component has a handy element called a Motor which adds a force to the component, pivoted at the hinge joint. Select the first child link (the first link with a Dynamic Rigidbody). This will be the link that provides the motion. By clicking the Use Motor and Use Limits checkbox, and changing the forces and limits to suit you, you can add some movement to the platform. I found that these numbers worked best for me:

Then to make the chain swing from side to side instead of going around in a circle, we need to create a new C# script and add it to the link with the motor. This simple code will just switch the direction of the force when the angle boundaries are reached.

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

public class SwingScript : MonoBehaviour
{
	private HingeJoint2D hinge;
	private JointMotor2D motorRef;
	private float speed;

	void Start()
	{
		hinge = GetComponent<HingeJoint2D>(); //Sets the variable to the hinge joint component attached to the object
		motorRef = hinge.motor; //We have to create a reference to the motor as we can not change it directly
		speed = Mathf.Abs(motorRef.motorSpeed);
	}

	void Update()
	{
		Debug.Log(hinge.jointAngle);
		if(hinge.jointAngle >= hinge.limits.max)
		{
			motorRef.motorSpeed = -speed; //Changes direction of swing once the limits are reached
			hinge.motor = motorRef; //Changes the force of the motor
		}    

		if(hinge.jointAngle <= hinge.limits.min)
		{
			motorRef.motorSpeed = speed;
			hinge.motor = motorRef;
		}
	}
}

With all this in place, you should have a platform that swings from side to side on a chain.

Swinging the platform manually

Alternatively, you could add a simple lever by just adding a small rectangle sprite in the middle of the platform like so, and making it a child of the platform.

Giving this a box collider, the player can use this to move the platform themselves by running into it. This can be used to add different elements to the game, for example, having to swing to a faraway ledge to advance further.

Conclusions

Now you have multiple different objects that all use a chain affect. You can change this to suit your game in any way. For example, changing them from chains to a jungle vine instead. This isn’t the only use for hinge joints. They have many different uses, from making spinning platforms using the motor function, to doors that open and close. However, don’t get tied up with that and just have fun experimenting with your new chains for now!





Source link

Leave a Reply

Your email address will not be published. Required fields are marked *