Boids 군집 알고리즘 소개
Boids는 인공 생명 알고리즘으로, 개체 간 상호 작용을 통해 동물의 군집 움직임을 표현하는데 사용한다.
Boids는 각 개체마다 다음 3개의 규칙을 가지고 움직인다.
separation: 무리와 충돌하지 않게 반대 방향으로 이동
alignment: 무리의 평균 방향으로 조향
cohesion: 무리의 평균 위치를 향해 이동
boids가 여러 방법이 있는데 그 중 아래 영상을 참고로 만들어볼것이다.
아래 영상은 군집의 타겟이 있으며 이를 중점으로 따라가는 형식이다.
https://www.youtube.com/watch?v=_CTzKiVTFPQ
Boids 구현
1. Boids 코드
public class Boids : MonoBehaviour
{
[SerializeField] float forwardSpeed;
[SerializeField] float searchRadius_cohesion_alignment;
[SerializeField] float searchRadius_separation;
[SerializeField] float rotateSpeed;
[SerializeField] float targetWeight;
[SerializeField] float alignmentWeight = 1.0f;
[SerializeField] float cohesionWeight = 1.0f;
[SerializeField] float separationWeight = 1.0f;
Transform Target;
List<Collider> list_colliders = new List<Collider>();
public void getTarget(Transform target)
{
Target = target;
}
// Update is called once per frame
void Update()
{
moveBoid();
}
void moveBoid()
{
// 범위내 콜라이더 확인
if (list_colliders.Count > 0)
{
list_colliders.Clear();
}
Collider[] colliders = Physics.OverlapSphere(transform.position, searchRadius_cohesion_alignment);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].CompareTag("Bird"))
{
list_colliders.Add(colliders[i]);
}
}
colliders = list_colliders.ToArray();
// cohesion, alignment, separation 저장할 변수 초기화
Vector3 totalCenter = Vector3.zero;
Vector3 totalDir = Vector3.zero;
Vector3 totalSeparation = Vector3.zero;
Vector3 BoidDir = Vector3.zero;
Vector3 cohesionDirection = Vector3.zero;
Vector3 Vec_toTarget = Vector3.zero;
int totalSeparationCount = 0;
foreach (Collider collider in colliders)
{
// alignment 무리 방향으로 조정
totalDir += collider.transform.forward;
// cohesion 무리 중심 위치로 이동
totalCenter += collider.bounds.center;
// separation 무리와 충돌하지 않게 반대 방향으로 이동
if (Vector3.Distance(transform.position, collider.transform.position) <= searchRadius_separation)
{
totalSeparation += transform.position - collider.transform.position;
}
totalSeparationCount++;
}
if(totalSeparationCount > 0)
{
totalDir /= colliders.Length;
totalCenter /= colliders.Length;
cohesionDirection = totalCenter - transform.position;
Vec_toTarget = Target.position - transform.position;
totalDir += targetWeight * Vec_toTarget.normalized;
BoidDir = alignmentWeight * totalDir + cohesionWeight * cohesionDirection + separationWeight * totalSeparation;
BoidDir.Normalize();
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(BoidDir), rotateSpeed * Time.deltaTime);
}
transform.position += transform.forward * forwardSpeed * Time.deltaTime;
}
}
2. Spawner 코드
public class Spawner_scr : MonoBehaviour
{
[SerializeField] Transform Target;
[SerializeField] GameObject prefabs_bird;
[SerializeField] int spawn_Count;
[SerializeField] int spawn_radius;
private void Awake()
{
for (int i = 0; i < spawn_Count; i++)
{
//Random.onUnitSphere 반지름 1을 가진 구의 공간에서의 랜덤한 위치
Vector3 pos_randOnSpherePos = Random.onUnitSphere * spawn_radius;
Vector3 rot_randOnSpherePos = Random.onUnitSphere * 100f;
GameObject obj = Instantiate(prefabs_bird, pos_randOnSpherePos, Quaternion.Euler(rot_randOnSpherePos));
obj.transform.GetComponent<Boids>().getTarget(Target);
}
}
}
결과
움직이는 목표와 지정된 목표지점으로 각자 잘 흩어져서 모이는걸 확인할 수 있다.
'Unity > 정보' 카테고리의 다른 글
[Unity] 구글 스프레드시트 연동 (0) | 2023.11.14 |
---|---|
[Unity] 스텐실 버퍼(Stencil Buffer) (0) | 2023.10.26 |
[Unity] 고급네비메쉬 (0) | 2023.09.23 |
[Unity] Poisson Disk Sampling (0) | 2023.09.16 |
[Unity] Path Creator - 설정한 경로대로 물체 움직이기 (0) | 2023.08.31 |