Queue
- '선입선출' (First In First Out, FIFO) 원칙을 따르는 선형 자료구조. 가장 먼저 들어온 데이터가 가장 먼저 나가는 구조이다.
public class Node<T>
{
public T data{get; private set;}
public Node<T> next{get; set;}
public Node(T data)
{
this.data = data;
next = null;
}
}
public class QueueEx<T>
{
private Node<T> front;
private Node<T> rear;
private int size;
public QueueEx()
{
front = null;
rear = null;
size = 0;
}
public void Enqueue(T data)
{
Node<T> newNode = new Node<T>(data);
if (IsEmpty())
{
front = newNode;
rear = newNode;
}
else
{
rear.next = newNode;
rear = newNode;
}
size++;
}
public T Dequeue()
{
if (IsEmpty())
{
throw new InvalidOperationException("Queue is empty");
}
T data = front.data;
front = front.next;
size--;
if (IsEmpty())
{
rear = null;
}
return data;
}
public T Peek()
{
if (IsEmpty())
{
throw new InvalidOperationException("큐가 비어있습니다.");
}
return front.data;
}
public bool IsEmpty()
{
return size == 0;
}
public int Size()
{
return size;
}
}
Priority Queue
- 큐의 각 요소가 우선순위를 가지고 있어 우선순위가 높은 요소가 먼저 처리되며 Heap을 이용해 구현한다.
Heap
- 완전이진트리 형태의 자료구조. 여러 개의 값 중 최댓값 또는 최솟값을 찾아내는 연산이 빠르다.
- 완전이진트리 형태로 이루어져 있고, 부모노드와 서브트리간 대소 관계가 성립된다. (반정렬 상태)
- MaxHeap : 부모 노드의 값이 자식 노드의 값 보다 크거나 같음
- MinHeap : 부모 노드의 값이 자식 노드의 값 보다 작거나 같음
public class PriorityQueue<T> where T : IComparable<T>
{
private List<T> heap = new List<T>();
public void Enqueue(T item)
{
heap.Add(item);
int currentIndex = heap.Count - 1;
HeapifyUp(currentIndex);
}
public T Dequeue()
{
if (heap.Count == 0)
{
throw new InvalidOperationException("Queue is empty");
}
T root = heap[0];
int lastIndex = heap.Count - 1;
heap[0] = heap[lastIndex];
heap.RemoveAt(lastIndex);
if(heap.Count > 0)
HeapifyDown(0);
return root;
}
private void HeapifyUp(int index)
{
while (index > 0)
{
int parentIndex = (index - 1) / 2;
if (heap[index].CompareTo(heap[parentIndex]) >= 0)
break;
Swap(index, parentIndex);
index = parentIndex;
}
}
private void HeapifyDown(int index)
{
int lastIndex = heap.Count - 1;
while (true)
{
int smallest = index;
int leftChild = index * 2 + 1;
int rightChild = index * 2 + 2;
if(leftChild <= lastIndex && heap[leftChild].CompareTo(heap[smallest]) < 0)
smallest = leftChild;
if(rightChild <= lastIndex && heap[rightChild].CompareTo(heap[smallest]) < 0)
smallest = rightChild;
if(smallest == index)
break;
Swap(index, smallest);
index = smallest;
}
}
private void Swap(int i, int j)
{
T temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
public int Count => heap.Count;
public bool IsEmpty => heap.Count == 0;
}
Max Heap을 이용한 오브젝트 풀링
- 유니티에서 오브젝트를 생성하기 위해서는 Instantiate를, 삭제할 때는 Destroy를 사용한다.
- Instantiate(오브젝트 생성)은 메모리를 새로 할당하고 리소스를 로드하는 등의 초기화 과정이 필요하고, Destroy(오브젝트 파괴)는 파괴 이후에 발생하는 가비지 컬렉팅으로 인한 프레임 드랍이 발생할 수 있어서 총알과 같이 자주 생성되고 삭제되는 오브젝트들이 있을 경우 치명적일 수 있다.
- 오브젝트 풀링은 자주 사용하는 오브젝트를 미리 생성해 놓고 이걸 사용할 때마다 새로 생성 삭제 하는 것 이 아닌 사용할 때는 오브젝트풀한테 빌려서 사용하고 삭제할 때는 오브젝트풀한테 돌려줌으로써 단순하게 오브젝트를 활성화 비활성화 만 하도록 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Collections.Generic;
public class ObjectPool : MonoBehaviour
{
public GameObject prefab;
public int poolSize = 10;
public int createCount;
private Queue<GameObject> objectPool = new Queue<GameObject>();
public List<GameObject> objects = new List<GameObject>();
void Start()
{
for (int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
}
public GameObject GetPooledObject()
{
if (objectPool.Count > 0)
{
GameObject obj = objectPool.Dequeue();
obj.SetActive(true);
return obj;
}
else
{
for (int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
return objectPool.Dequeue();
}
return null;
}
public void ReturnToPool(GameObject obj)
{
obj.SetActive(false);
objectPool.Enqueue(obj);
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
for (int i = 0; i < createCount; i++)
{
float x = Random.Range(-100, 100);
float y = Random.Range(-100, 100);
float z = Random.Range(-100, 100);
var go = GetPooledObject();
go.transform.position = new Vector3(x, y, z);
objects.Add(go);
}
}
else if (Input.GetKeyDown(KeyCode.D))
{
for (var i = 0; i < objects.Count; i++)
{
ReturnToPool(objects[i]);
}
objects.Clear();
}
}
}
애니메이션 리타겟팅
- 동일한 애니메이션 세트를 다양한 캐릭터 모델에 비교적 편리하게 적용할 수 있게 해준다.
- 리타게팅은 모델의 골격 구조 사이에 연관성을 제공하기 때문에 아바타가 설정된 휴머노이드 모델에만 적용 가능하다.
(1) 리타켓팅 할 곳의 Rig > Animation Type을 Humanoid로 변경 후 적용
(2) AnimatorController 생성 후 적용할 애니메이션을 복제하여 넣기
(3) AnimatorController 연결
'TIL' 카테고리의 다른 글
[멋쟁이사자처럼 부트캠프 TIL 회고] 유니티 게임개발 3기 16일차 알고리즘(정렬) (0) | 2024.12.11 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL 회고] 유니티 게임개발 3기 15일차 자료구조(Tree) (0) | 2024.12.10 |
[멋쟁이사자처럼 부트캠프 TIL 회고] 유니티 게임개발 3기 13일차 LINQ (0) | 2024.12.05 |
[멋쟁이사자처럼 부트캠프 TIL 회고] 유니티 게임개발 3기 12일차 자료구조(Stack) (1) | 2024.12.04 |
[멋쟁이사자처럼 부트캠프 TIL 회고] 유니티 게임개발 3기 11일차 자료구조(Linked List) (0) | 2024.12.03 |