hi there thanks for taking the time to look at my question im currenty making a 2D side scroller/platformer and im currently facing a issue where my enemies are piling up on top of each other. through googling i see alot of Astar pathfinding solving this however i hesitant to jump into ai right now as i glanced over its internal scripts and they are outside my current knowledge and im still attempting to get a understanding of just using scripting to achieve what i want.
i currently have my enemies correctly chasing my player with a vector2.movetowards however eventually they all pile on each other.
through google i have found this is a typical outcome of movetowards and i found this solution Stop enemies from grouping up - Questions & Answers - Unity Discussions and i implemented its code
void avoidOthers()
{
var hits = Physics2D.OverlapCircleAll(enemy.transform.position, avoidenceRadius);//create a circle around each enemy and check to see if they are not colliding
foreach (var hit in hits)
{
if(hit.GetComponent<DartFish>() != null && hit.transform != transform)//check to see if it is a enemy
{
Debug.Log("enemy transform" + enemy.transform.position);
Debug.Log("hit transform" + hit.transform.position);
Vector2 difference = enemy.transform.position - hit.transform.position;//check how close we are to another enemy
difference = difference.normalized / Mathf.Abs(difference.magnitude);//calculate how long the vector is
sum += difference;//add together differences so we can calculate a average of the group
count++;
}
}
if(count > 0)// if we found enemys interfearing with each other
{
sum /= count;//average of the movement
sum = sum.normalized * avoidenceSpeed;//calculate movement speed
Debug.Log("sum = " + sum);
enemy.transform.position = Vector2.MoveTowards(enemy.transform.position, enemy.transform.position + (Vector3)sum, avoidenceSpeed * Time.deltaTime);
}
}
however i needed to add “enemy” to each transform.position or they would instantly snap from my spawn location to the player. after adding enemy they stopped snapping over a large distance except now they started piling again
all of my debug logs look like they are printing out the correct values
i was also reading through transform.translate as looking at my “sum” values this should be how much they are moving away from each other
so i changed the line
enemy.transform.position = Vector2.MoveTowards(enemy.transform.position, enemy.transform.position + (Vector3)sum, avoidenceSpeed * Time.deltaTime);
to
transform.Translate((Vector3)sum * avoidenceSpeed * Time.deltaTime, Space.World);
now it seems to only effect one fish and the others clump together still
from my understanding physics.overlapcircle all should be functioning as a list?
i also noticed that my one enemy that was using the avoidence method was still moving towards my player so i then added a bool to block my chaseme() method
if(count > 0)// if we found enemys interfearing with each other
{
sum /= count;//average of the movement
sum = sum.normalized * avoidenceSpeed;//calculate movement speed
Debug.Log("sum = " + sum);
if(sum != Vector2.zero)
{
weHitAnotherFish = true;
transform.Translate((Vector3)sum * avoidenceSpeed * Time.deltaTime, Space.World);
sum = Vector2.zero;//zero the sum in preperation for the next contact
}
else
{
weHitAnotherFish = false;
}
}
heres my entire code albeit long and possibly repetitive(small changes such as jus adding a -)(still relatively new to coding)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DartFish : MonoBehaviour
{
public Transform target;
public float movementSpeed;
private float initialMovementSpeed;
public float dashSpeed;
private float spawnSpeed = 1.5f;
public float chaseRadius;
private float initialChaseRadius;
public float dashRadius;
private Vector2 targetDirection;
private float directionX;
private float previousDirectionX;
private float directionY;
private float spriteAngle;
private float previousAngle;
private float currentSpriteAngle;
private float difference;
private SpriteRenderer mySpriteRenderer;
private Rigidbody2D myRigidbody;
private bool directionIsAboutToChange;
private bool directionHasChanged;
private Vector3 angleCompensation;
// avoid others variables
public float avoidenceSpeed;
public float avoidenceRadius;
public Transform enemy;
private Vector2 sum = Vector2.zero;
private float count;
public bool weHitAnotherFish;
// Start is called before the first frame update
void Start()
{
enemy = GameObject.FindWithTag("dartfish").transform;
target = GameObject.FindWithTag("Player").transform;
mySpriteRenderer = GetComponent<SpriteRenderer>();
myRigidbody = GetComponent<Rigidbody2D>();
initialMovementSpeed = movementSpeed;
initialChaseRadius = chaseRadius;
}
// Update is called once per frame
void Update()
{
targetDirection = target.position - transform.position;// where is the player?
directionX = targetDirection.x;//extract only x for "check direction"
directionY = targetDirection.y;
if(directionX < -initialChaseRadius + .5f)// is the player further then the chase radius?
{
myRigidbody.velocity = new Vector2(-1.5f, 0);
}
else
{
myRigidbody.velocity = Vector2.zero;
}
if(directionX > 0)//calculate tangent angle to the player in radians and then convert it to degrees
{
spriteAngle = Mathf.Atan2(targetDirection.y, targetDirection.x) * Mathf.Rad2Deg;
}
else if(directionX < 0)//if player is to the left flip opp/adj and add 100° to zero angle
{
spriteAngle = Mathf.Atan2(targetDirection.x, targetDirection.y) * Mathf.Rad2Deg +100f;
}
currentSpriteAngle = spriteAngle;
difference = spriteAngle - previousAngle;
difference = Mathf.Abs(difference);
if(directionX < 1 && directionX > -1)//are we about to change directions?
{
//Debug.Log("direction is about to change");
directionIsAboutToChange = true;
}
if(directionIsAboutToChange == true)//did we pass through trigger zone?
{
if(directionX > 1 || directionX < -1)
//Debug.Log("direction has changed");
directionHasChanged = true;
}
lookAtMe();
avoidOthers();
chaseMe();
/*
//debug logs with spam control
if(previousAngle != spriteAngle)
{
Debug.Log("angle = " + spriteAngle);
}
if(difference != 0)
{
Debug.Log("difference = " + difference);
}
if(previousDirectionX != directionX)
{
Debug.Log("directionX = " + directionX);
}
if(previousAngle != currentSpriteAngle)
{
Debug.Log("previous angle = " + previousAngle);
}
*/
previousAngle = currentSpriteAngle;
previousDirectionX = directionX;
}
void lookAtMe()
{
if(directionHasChanged == true)//angle compensation for sprite flip
{
if(directionY > 0)//is the player above or below us
{
angleCompensation = transform.localEulerAngles;//get current rotation
//flip it
if(directionX > 0)
{
transform.localEulerAngles = -angleCompensation;
}
if(directionX < 0)
{
transform.localEulerAngles = angleCompensation;
}
}
if(directionY < 0)
{
if(directionX > 0)
{
transform.localEulerAngles = angleCompensation;
}
if(directionX < 0)
{
transform.localEulerAngles = -angleCompensation;
}
}
directionHasChanged = false;
directionIsAboutToChange = false;
}
if(directionX < -1)
{
mySpriteRenderer.flipX = true;
//Debug.Log("entered void lookAtMe.directionX <");
if(spriteAngle > previousAngle && spriteAngle < 50f )
{
transform.Rotate(0f, 0f, -difference);
}
else if(spriteAngle < previousAngle && spriteAngle > -50f)
{
transform.Rotate(0f, 0f, difference);
}
}
else if(directionX > 1)
{
mySpriteRenderer.flipX = false;
//Debug.Log("entered void lookAtMe.directionX >");
if(spriteAngle > previousAngle && spriteAngle < 50f)
{
transform.Rotate(0f, 0f, difference);
}
else if(spriteAngle < previousAngle && spriteAngle > -50f)
{
transform.Rotate(0f, 0f, -difference);
}
}
}
void avoidOthers()
{
var hits = Physics2D.OverlapCircleAll(enemy.transform.position, avoidenceRadius);//create a circle around each enemy and check to see if they are not colliding
foreach (var hit in hits)
{
if(hit.GetComponent<DartFish>() != null && hit.transform != transform )//check to see if it is a enemy
{
Debug.Log("enemy transform" + enemy.transform.position);
Debug.Log("hit transform" + hit.transform.position);
Vector2 difference = enemy.transform.position - hit.transform.position;//check how close we are to another enemy
difference = difference.normalized / Mathf.Abs(difference.magnitude);//calculate how long the vector is
sum += difference;//add together differences so we can calculate a average of the group
count++;
}
}
if(count > 0)// if we found enemys interfearing with each other
{
sum /= count;//average of the movement
sum = sum.normalized * avoidenceSpeed;//calculate movement speed
Debug.Log("sum = " + sum);
if(sum != Vector2.zero)
{
weHitAnotherFish = true;
transform.Translate((Vector3)sum * avoidenceSpeed * Time.deltaTime, Space.World);
sum = Vector2.zero;//zero the sum in preperation for the next contact
}
else
{
weHitAnotherFish = false;
}
}
}
void chaseMe()
{
if(Vector3.Distance(target.position, transform.position) <= chaseRadius && Vector3.Distance(target.position, transform.position) > dashRadius && weHitAnotherFish != true)
{
transform.position = Vector3.MoveTowards(transform.position, target.position, movementSpeed * Time.deltaTime);
}
else if(Vector3.Distance(target.position, transform.position) <= dashRadius && weHitAnotherFish != true)
{
transform.position = Vector3.MoveTowards(transform.position, target.position, dashSpeed * Time.deltaTime);
}
}
}
,