using UnityEngine;
public class Flock : MonoBehaviour
{
public GameObject c_prefebFish; //하위 프리팹
public GameObject p_prefebFish; //상위 프리팹
public int m_Fish = 30; // 생성할 물고기
public int Boundary = 7; //물고기가 자유롭게 움직일수 있는 경계
public GameObject[] Fishes;
public Vector3 TargetPosition = Vector3.zero;
public Vector3 centerPosition; //기준이 되는 좌표
void Start()
{
Fishes = new GameObject[m_Fish];
TargetPosition = centerPosition;
for (int i = 0; i < m_Fish; i++)
{
Vector3 position = centerPosition + new Vector3(
Random.Range(-Boundary, Boundary),
Random.Range(-Boundary, Boundary),
Random.Range(-Boundary, Boundary)
);
GameObject fish = (GameObject)Instantiate(c_prefebFish, position, Quaternion.identity);
fish.transform.parent = p_prefebFish.transform; //자식 오브젝트로 엮음
Fishes[i] = fish;
}
}
void Update()
{
GetTargetPosition();
}
void GetTargetPosition()
{
if (Random.Range(1, 10000) < 50)
{
TargetPosition = new Vector3(
Random.Range(TargetPosition.x -Boundary, TargetPosition.x + Boundary),
Random.Range(3, 13),
Random.Range(TargetPosition.z - Boundary, TargetPosition.z + Boundary)
);
}
}
}
물고기의 생성과 전체 물고기의 타겟 관리를 하는 스크립트
using UnityEngine;
public class FishController : MonoBehaviour
{
public float MaxSpeed = 2.0f; //최고 스피드
public float MaxTurnSpeed = 0.5f; //회전력
public float Speed; //초기속도
public float NeighborDistance = 3.0f; //주변 물고기와의 거리
private bool IsTurning = false;
private Flock flock;
void Start()
{
Speed = Random.Range(0.5f, MaxSpeed); //물고기 초기 속도 설정
flock = GetComponentInParent<Flock>(); //부모 스크립트
}
void Update()
{
GetIsTurning();
if (IsTurning) //물고기가 영역안에 들어가 있을때
{
Vector3 direction = Vector3.zero - transform.position;
transform.rotation = Quaternion.Slerp(transform.rotation,
Quaternion.LookRotation(direction),
TurnSpeed() * Time.deltaTime);
Speed = Random.Range(0.5f, MaxSpeed);
}
else
{
if (Random.Range(0, 5) < 1)
SetRotation();
}
transform.Translate(0, 0, Time.deltaTime * Speed);
}
//물고기가 경계에 다다르면 회전 상태를 설정
void GetIsTurning()
{
//물고기가 영역안에 들어있을때임
if (Vector3.Distance(transform.position, Vector3.zero) >= flock.Boundary)
{
IsTurning = true;
}
else
{
IsTurning = false;
}
}
//물고기의 회전을 설정
//주변 물고기들의 위치와 속도를 고려하여 그룹의 중심으로 이동
void SetRotation()
{
GameObject[] fishes;
fishes = flock.Fishes;
Vector3 center = Vector3.zero; //그룹의 중심
Vector3 avoid = Vector3.zero; //회피를 위한 백터
float speed = 0.1f; //그룹의 평균 속도
Vector3 targetPosition = flock.TargetPosition;
float distance;
int groupSize = 0;
for (int i = 0; i < fishes.Length; i++)
{
if (fishes[i] != gameObject) //자신외 물고기들 검사
{
// 주변 물고기 사이 거리 계산
distance = Vector3.Distance(fishes[i].transform.position, transform.position);
//주변 물고기가 일정 범위내 있을경우
if (distance <= NeighborDistance)
{
center += fishes[i].transform.position; //그룹의 중심을 업데이트
groupSize++;
//주변 물고기가 너무 가까운 경우
if (distance < 0.75f)
{
//회피 벡터를 업데이트
avoid += (transform.position - fishes[i].transform.position);
}
//주변 물고기의 평균 속도를 업데이트
FishController anotherFish = fishes[i].GetComponent<FishController>();
speed += anotherFish.Speed;
}
}
}
//주변에 물고기가 있을 경우:
if (groupSize > 0)
{
//그룹의 중심을 계산하고 이동 목표 지점으로 향하도록
center = center / groupSize + (targetPosition - transform.position);
Speed = speed / groupSize; //물고기의 평균 속도를 업데이트
Vector3 direction = (center + avoid) - transform.position; //이동방향을 구함
if (direction != Vector3.zero) //이동 방향이 존재한다면 아래의 코드를 실행
{
//Quaternion.Slerp는 현재 회전에서 목표 회전까지의 회전을 부드럽게 보간
transform.rotation = Quaternion.Slerp(transform.rotation,
Quaternion.LookRotation(direction),
TurnSpeed() * Time.deltaTime);
}
}
}
//회전속도 랜덤으로 반환
float TurnSpeed()
{
return Random.Range(0.2f, MaxTurnSpeed);
}
}
주변 물고기의 거리에 따라 회전과 스피드가 달라지는 구조 회전은 센터를 중점으로 바라보면서 주변 물고기의 거리에 따라 회전이 조금씩 달라짐.
using UnityEngine;
public class AvoidLayer : MonoBehaviour
{
public LayerMask obstacleLayer;
public float avoidanceRadius = 5f;
public float avoidanceForce = 10f;
public float maxSpeed = 5f;
private void FixedUpdate()
{
Vector3 avoidanceDirection = Vector3.zero;
// 레이캐스트를 이용하여 피해야 할 레이어의 장애물 감지
RaycastHit[] hits = Physics.SphereCastAll(transform.position, avoidanceRadius, transform.forward, 0f, obstacleLayer);
foreach (RaycastHit hit in hits)
{
// 피해야 할 레이어의 장애물이 감지된 경우, 피하는 방향 계산
Vector3 obstacleDirection = transform.position - hit.transform.position;
avoidanceDirection += obstacleDirection.normalized * (avoidanceRadius - obstacleDirection.magnitude);
}
// 피하는 방향을 현재 위치에 반영하여 이동
transform.position += avoidanceDirection.normalized * maxSpeed * Time.deltaTime;
}
}
특정 레이어와 일정 거리 가까워지면 - 힘으로 밀어내는 스크립트