Programming/algorithm

[Algorithm] Boids

devfactory 2024. 9. 28. 23:09

boids는 생물의 집단행동(새 무리의 이동 등)을 시뮬레이션 하는 알고리즘이다.

 

기본적으로 3개의 규칙을 따른다.

1. 응집(Cohesion): 주변 boid들과 평균위치를 향한다.

2. 분리(Separation): 주변 boid들과 충돌하지 않도록 방향을 돌린다.

3. 정렬(Alignment): 주변 boid들과 같은 방향을 향한다.

 

응집 - Cohesion

Boid는 주변의 Boid의 곁으로 가려는 성질이 있다.

주변 Boid의 위치의 평균을 구해 해당 방향으로 향한다.

Vector3 Cohesion(Transform[] _targets)
{
    Vector3[] targets = Change(_targets, (Transform target) => target.position);
    return Average(targets) - transform.position;
}

 

분리 - Separation

Boid는 다른 Boid와 너무 가까워 지지 않으려는 성질이 있다.

가까이 접근한 Boid들의 반대방향의 평균으로 향한다.

Boid의 거리에 비례해 가까이 있는 boid일수록 더 민감하게 반응하도록 하였다.

Vector3 Separation(Transform[] _targets)
{
    Vector3[] targets = Change(_targets, (Transform target) => transform.position - target.position);
    return Average(targets, (Vector3 vec) => vec.normalized * vec.magnitude / Boids.SeparationRadius);
}

 

정렬 - Alignment

Boid는 주변의 Boid와 같은 방향을 향하려는 성질이 있다.

주변의 Boid의 Vector의 평균방향을 향한다.

Vector3 Alignment(Transform[] _targets)
{
    Vector3[] targets = Change(_targets, (Transform target) => target.forward);
    return Average(targets);
}

 

위의 3가지 요소 외에도 장애물을 피하는 방향과 같이 다른 요소들을 추가 할 수 있다.

요소들의 값을 구하면 가중치를 곱한뒤 모든 요소의 합을 구해 해당방향을 바라보도록 천천히 회전시킨다.

void Update()
{
    Transform[] targets = Change(Physics.OverlapSphere(transform.position, Boids.SeparationRadius), (Collider coll) => coll.transform);
    
    if(targets.Length > Boids.maxNeighbourCount)
    {
        var t = new List<Transform>();
        int count = 0;

        for (int i = 0; i < targets.Length; i++)
        {
             t.Add(targets[i]);
        }
        targets = t.ToArray();
    }

    var SeparationVec = Separation(targets).normalized * Boids.SeparationWight;
    Debug.DrawRay(transform.position, Separation(targets).normalized, Color.red);
    
    targets = Change(Physics.OverlapSphere(transform.position, Boids.NeighbourRadius), (Collider coll) => coll.transform);


    var  AlignmentVec = Alignment(targets).normalized * Boids.AlignmentWight;
    Debug.DrawRay(transform.position, Alignment(targets).normalized, Color.blue);
    
    var   CohesionVec = Cohesion(targets).normalized * Boids.CohesionWight;
    Debug.DrawRay(transform.position, Cohesion(targets).normalized, Color.green);
    
    var boundsVec = Bounds() * Boids.BoundsWight;
    var obstacle = Obstacle().normalized * Boids.obstacleWight;

    var LookVec = SeparationVec + AlignmentVec + CohesionVec + boundsVec + obstacle + RandomVec ;

    if (!Boids.Space3D) LookVec.y = 0;

    LookVec = Vector3.Lerp(transform.forward, LookVec, Time.deltaTime * Boids.RotateSpeed);
    Quaternion targetQuaternion = Quaternion.LookRotation(LookVec);
    transform.rotation = targetQuaternion;
}

 

 

전체 코드: https://github.com/dheiejsbd/Boids

 

GitHub - dheiejsbd/Boids

Contribute to dheiejsbd/Boids development by creating an account on GitHub.

github.com

반응형