- Home /
Put an offset distance to gameobject that follows player
I have these multiple gameobjects that the player can pick-up and starts following him like its pets but what's happening is when the player picks up more than one of this game object is starts stacking/overlapping its position so it looks like there is only 1 following the player. How can I prevent this gameobjects from overlapping their position while following the player? I attached a sketch of to make it clear, also the code that I use to follow the player
public float radius; public float speed = 3; public float pickDistance = 1.5f;
void Update()
{
Collider2D[] colls = Physics2D.OverlapCircleAll(transform.position, radius);
foreach (Collider2D c in colls)
{
if (c.tag == "Player")
{
if (Vector2.Distance(transform.position, c.transform.position) > pickDistance)
{
transform.position = Vector2.MoveTowards(transform.position, c.transform.position, speed * Time.deltaTime);
}
}
}
}
Answer by highpockets · Jun 05, 2019 at 07:43 AM
As your player picks up these pets, put them in a list. Then iterate through the list and add the offset distance * (index + 1).
Make your list:
List<Transform> pets = new List<Transform>();
Add to your list:
pets.Add(transform);
When you want to set their offset, loop through them like so:
float xOffset = 1.5f;
for(int i = 0; i < pets.Count; i++)
{
pets[i].position = new Vector2(player.transform.position.x + (xOffset * (i + 1)), player.transform.position.y);
}
Untested, but that should do it. If you want an offset on the y axis, you can add an additional offset float for that.
Additionally, you can add the offset when you add a new pet to the list:
pets.Add();
pets[pets.Count - 1].position = new Vector2(player.transform.position.x + (xOffset * pets.Count), player.transform.position.y);
Then making the player transform a parent will keep them at the offset.
Cheers
Answer by DCordoba · Jun 05, 2019 at 07:54 AM
that seem to you're using a independent, modular, less-interconected pet AI, thats great to deploy on any scene, and they are able to reroute themselves, so, good approach.
the problem is, you need to make the AI detect each other, so... can be a problem because they need to know the position of the rest of the swarm on each update, to take decision to advance, so you need to have a way to each AI detect a pal, and make a following formation.
to a line pattern of persecution you can manage easy on several ways
you can do a pack-like way, when a object starts following, it send a "howl", as answer receive the number on the line to it have to align and it automatically calculates the offset, some like:
public static class PackSharedMind{
static int packsize = 0;
public static int Howl(){
packsize++;
return packsize - 1;
}
}
and inside the Update of each element
public float radius;
public float speed = 3;
public float pickDistance = 1.5f;
public float offset;
int packRank = 0;//ranks on the pack are inverse, 0 means first (leader of dogs, wolfs, etc xd) so go ahead
bool following = false;
void Update()
{
Collider2D[] colls = Physics2D.OverlapCircleAll(transform.position, radius);
foreach (Collider2D c in colls)
{
if (c.tag == "Player")
{
if (!following){
packRank = PackSharedMind.Howl();
following = true;
}
if (Vector2.Distance(transform.position, c.transform.position) > pickDistance + packRank*offset)
{
transform.position = Vector2.MoveTowards(transform.position, c.transform.position, speed * Time.deltaTime);
}
}
}
}
EDIT: I was writing while @highpockets write a answer, after read his answer I realized that the pet never get the the oportunity of leave, so, if stops following, you'll have holes on your formation, using his approach, I suggest make a most powerful PackSharedMind, able to give feedback and reorder the formation if someone is off the radius and leave
public static class PackSharedMind{
//I dont know the name of your AI scrip, replace "Pet" to the right name...
static List<Pet> pack = new List<Pet>();
/// <summary>
/// add one element to the followers.
/// </summary>
public static int Howl(Pet newMember){
pack.Add(newMember);
return pack.Count - 1;
}
public static void Leave(int rank){
pack.RemoveAt(rank);
for (int i = rank; i<pack.Count(); i++)
pack(i).Reroute(i);
}
}
and inside Pet
update
public float radius;
public float speed = 3;
public float pickDistance = 1.5f;
public float offset;
int packRank = 0;//ranks on the pack are inverse, 0 means first (leader of dogs, wolfs, etc xd) so go ahead
bool following = false;
//check if this instance should stop following
bool found = false;
void Update()
{
Collider2D[] colls = Physics2D.OverlapCircleAll(transform.position, radius);
found = false;
foreach (Collider2D c in colls)
{
if (c.tag == "Player")
{
if (!following){
packRank = PackSharedMind.Howl();
following = true;
}
if (Vector2.Distance(transform.position, c.transform.position) > pickDistance + packRank*offset)
{
transform.position = Vector2.MoveTowards(transform.position, c.transform.position, speed * Time.deltaTime);
}
found = true;
}
}
if(following && !found){
PackSharedMind.Leave(packRank);
following = false;
}
}
also inside "Pet" add method Reroute()
to receive a new position from the pack shared mind when someone else leaves:
public void Reroute(int newRank){
PackRank = newRank;
}