How can I get the NPCs to animate
based on the horizontal movement that
is the effect of the physics of the
HingeJoint2D?
Just pass the horizontal speed (aka velocity) of the NPC’s rigidbody to the animator. The player control script already gives us some hints on how we might do this:
float move = Input.GetAxis("Horizontal");
anim.SetFloat("Speed", Mathf.Abs(move));
anim.SetFloat("vSpeed", GetComponent<Rigidbody2D>().velocity.y);
We can simply change the part of the code above that sets the animator “Speed” float to the rigidbody’s absolute (Mathf.Abs) x velocity, rather than the horizontal input, like this:
anim.SetFloat("Speed", Mathf.Abs(GetComponent<Rigidbody2D>().velocity.x));
anim.SetFloat("vSpeed", GetComponent<Rigidbody2D>().velocity.y);
However, GetComponent is slow, so calling it every update is a bad idea. It’s much better to do any GetComponent calls on Start or Awake, and cache the reference for later use instead.
I would also recommend separating your logic for the NPC collecting behavior into another script. Ideally, each script should only be responsible for one task. This will make your code much more module and maintainable.
First off, delete all the NPC collecting logic from your player control script. Then create a new script to handle just this task using the code below.
For this example I’m just calling these NPC things “things”
I’m also assuming you don’t actually need three separate unique references to the NPCs? If you do, you can always add that logic back, but you shouldn’t need any joint references since they’re being created on-the-fly for you here.
using UnityEngine;
using System.Collections.Generic;
public class CollectThings : MonoBehaviour
{
// Tag for things we want to collect.
public string thingTag = "NPC";
// Maximum amount of things we can collect.
public int maxThings = 3;
// Connected joint damping amount.
public float followDamping = 5;
// Fixed follow distance. 0.5 seems good.
public float followDistance = 0;
// List to hold all collected things.
private List<GameObject> collected;
// List to hold all joints.
private List<SpringJoint2D> joints;
void Start()
{
// Initialize lists. Makes sure they're not null and empty.
collected = new List<GameObject>();
joints = new List<SpringJoint2D>();
}
void Update()
{
// Testing
if (Input.GetKeyDown(KeyCode.E))
{
RemoveAll();
}
}
void OnTriggerEnter2D(Collider2D other)
{
// Is this something we want to collect?
if (other.gameObject.CompareTag(thingTag))
{
// If already at maximum limit, abort.
if (collected.Count >= maxThings)
return;
AddThing(other.gameObject);
}
}
void AddThing(GameObject obj)
{
// Add a joint to this object.
var j = gameObject.AddComponent<SpringJoint2D>();
// Connect thing to the joint and set joint settings.
j.autoConfigureConnectedAnchor = false;
j.dampingRatio = followDamping;
j.connectedBody = obj.GetComponent<Rigidbody2D>();
// Use fixed follow distance if set.
if (followDistance > 0)
{
j.autoConfigureDistance = false;
j.distance = followDistance;
}
// Add new joint to the joints list.
joints.Add(j);
// Add new collected thing to collection list.
collected.Add(obj);
}
// Free all collected things by destroying their joints.
void RemoveAll()
{
// Destroy all joints.
foreach (var joint in joints)
{
Destroy(joint);
}
// Remove all collected things from the list.
collected.Clear();
}
}
I used Spring joints here because hinge joints don’t allow the NPCs to follow at varying distances, but you can change that if you want. To prevent the spring joints from bouncing all over the place you just need to increase the NPC’s rigid-body linear damping value to something like 1. You should also probably decrease their mass or increase the player’s mass, to prevent them from pulling the player around. However, this is all stuff you’ll need to tweak how you like it.
Oh, and you probably don’t need to disable colliders on the collected NPCs because collisions between jointed objects are disabled automatically.