Q1. fixedUpdate와 Update 차이
Q2. 유니티에서 쓰레딩 가능 여부
Q3. Time.deltaTime이란?
Q4. 왜 캐릭터 매니저를 사용하나요?
메모리 할당 최소화 : 오브젝트를 매번 생성하고 파괴하면 메모리 할당과 해제가 빈번하게 발생하여 성능이 저하 됨. 오브젝트 풀링은 이러한 문제를 해결하기 위해 미리 필요한 수의 오브젝트를 생성해둠
재사용(Reusing) : 한 번 생성된 오브젝트는 풀 안에서 재사용됨. 새 오브젝트를 만들지 않고, 사용이 끝난 오브젝트를 다시 활용하므로 성능을 크게 향상시킴
풀 관리 : 풀에서 오브젝트를 필요로 할 때는 사용 가능한 오브젝트를 꺼내 사용하고, 사용이 끝나면 다시 풀에 반환함. 이 과정을 통해 효율적인 메모리 관리를 유지할 수 있음
유니티의 오브젝트 풀링에서 사용하는 자료구조는 특정한 요구 사항에 맞춰 선택할 수 있으며, 특정 자료구조로 고정되어 있지는 않음
리스트(List) : 간단하고 직관적인 자료구조로, 오브젝트를 순차적으로 관리하기에 좋음. 삽입과 제거가 빠르지 않지만, 적은 수의 오브젝트를 관리할 때는 적합함
큐(Queue) : 선입선출(FIFO) 방식으로 오브젝트를 재사용할 때 유용함. 오브젝트가 필요할 때 앞에서 꺼내고, 사용이 끝난 오브젝트는 다시 뒤로 넣는 방식
스택(Stack) : 후입선출(LIFO) 방식으로 사용됨. 가장 최근에 사용한 오브젝트를 다시 사용하고 싶은 경우 적합
딕셔너리(Dictionary) or 해시맵(HashMap) : 특정 키를 기준으로 오브젝트에 접근해야 할 때 유용함. 오브젝트 풀링에서 오브젝트의 종류나 상태에 따라 구분해야 할 때 유용할 수 있음
Object Type (오브젝트 타입)
Initial Pool Size (초기 풀 크기)
Max Pool Size (최대 풀 크기)
Auto Expand (자동 확장)
Recycle Objects (오브젝트 재활용)
Factory Method (팩토리 메소드)
Unity에서 제공하는 오브젝트 풀링 인터페이스
오브젝트 풀을 관리하는 데 필요한 기본적인 기능들을 정의한 인터페이스
이를 통해 오브젝트 풀링 시스템을 구현하거나 커스터마이징할 수 있음
주요 기능은 풀의 오브젝트를 요청하고 반환하는 과정에 대한 규칙을 설정하는 것
IObjectPool 인터페이스는 풀링 시스템을 표준화하여 다양한 종류의 오브젝트 풀링에 동일한 방식으로 접근할 수 있게 해줌
Get()
Release(T element)
Clear()
CountInactive
public class InputRebinder : MonoBehaviour
{
public InputActionAsset actionAsset;
private InputAction spaceAction;
private InputAction escapeAction;
void Start()
{
// (완료) [구현사항 1] actionAsset에서 Space 액션을 찾고 활성화합니다.
spaceAction = actionAsset.FindAction("Space");
// Space 액션 활성화
spaceAction.Enable();
spaceAction.performed += OnSpacePressed;
}
// (완료) [구현사항 2] ContextMenu 어트리뷰트를 활용해서 인스펙터창에서 적용할 수 있도록 함
void OnEnable()
{
// Esc 키에 대한 액션 생성
escapeAction = new InputAction(binding: "<Keyboard>/escape");
// Esc 키 입력 이벤트 등록
escapeAction.performed += OnEscapePressed;
// 액션 활성화
escapeAction.Enable();
}
public void OnSpacePressed(InputAction.CallbackContext context)
{
if(context.performed)
{
Debug.Log("Check_Space");
}
}
private void OnEscapePressed(InputAction.CallbackContext context)
{
// Esc 키 눌렀을 때 실행
RebindSpaceToEscape();
}
public void RebindSpaceToEscape()
{
if (spaceAction == null)
return;
actionAsset.FindAction("Space").ApplyBindingOverride("<Keyboard>/escape");
Debug.Log("Done!");
}
void OnDestroy()
{
// 액션을 비활성화합니다.
spaceAction?.Disable();
escapeAction?.Disable();
}
}
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool_1 : MonoBehaviour
{
// [구현사항 1]
// 최소 50개의 오브젝트 수 보장,
// 부족할 경우 누적 300개까지 추가 생성,
// 300개가 넘어갈 경우 임시로 생성 후 반환 시 파괴
private List<GameObject> pool;
private const int minSize = 50;
private const int maxSize = 300;
[SerializeField] private GameObject bulletPrefab;
void Awake()
{
pool = new List<GameObject>();
for (int i = 0; i < minSize; i++)
{
pool.Add(CreateObject()); // 일단은 최소 50개 생성
}
}
// 오브젝트 생성 함수
private GameObject CreateObject()
{
GameObject newObject = Instantiate(bulletPrefab);
newObject.SetActive(false); // 초기에는 비활성화
return newObject;
}
// 오브젝트 가져오는 함수
public GameObject GetObject()
{
foreach (var obj in pool)
{// 풀 안에서
if (!obj.activeInHierarchy) // 비활성화된 객체를 찾는다
{
obj.SetActive(true); // 활성화
return obj; // 있으면 반환
}
}
// 비활성화 객체 탐색 실패
// 모든 객체가 활성화되어 있을 경우
if (pool.Count < maxSize)
{
// 풀 안에 오브젝트가 최대 300개가 되기전까지는 추가
GameObject newObject = CreateObject();
pool.Add(newObject);
newObject.SetActive(true);
return newObject;
}
// 최대 크기를 초과할 경우, 임시로 생성 후 반환
// 풀 안에는 추가하지 않음.
GameObject tempObject = CreateObject();
tempObject.SetActive(true);
return tempObject;
}
// 오브젝트 반환 함수
public void ReleaseObject(GameObject obj)
{
if (pool.Contains(obj))
{// 풀안에 포함된 오브젝트면
obj.SetActive(false); // 비활성화
}
else
{
// 풀 외의 것이면
Destroy(obj); // 파괴
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
public class ObjectPool_2 : MonoBehaviour
{
// [구현사항 2]
// 최소 50개의 오브젝트 수 보장,
// 부족할 경우 누적 300개까지 추가 생성,
// 300개가 넘어갈 경우 가장 오래전에 생성된 오브젝트를 반환 후 재사용
private List<GameObject> pool;
private const int minSize = 50;
private const int maxSize = 300;
private int recentNum = 0;
[SerializeField] private GameObject bulletPrefab;
void Awake()
{
pool = new List<GameObject>();
for (int i = 0; i < minSize; i++)
{
pool.Add(CreateObject());
}
}
private GameObject CreateObject()
{
GameObject newObject = Instantiate(bulletPrefab);
newObject.SetActive(false); // 초기에는 비활성화
return newObject;
}
public GameObject GetObject()
{
foreach (var obj in pool)
{
if (!obj.activeInHierarchy) // 비활성화된 객체를 찾는다
{
obj.SetActive(true); // 활성화
return obj;
}
}
// 모든 객체가 활성화되어 있을 경우
if (pool.Count < maxSize)
{
GameObject newObject = CreateObject();
pool.Add(newObject);
newObject.SetActive(true);
return newObject;
}
// 300개가 넘어갈 경우
// 가장 오래전에 생성된 오브젝트를 반환 후 재사용
if(recentNum == maxSize)
recentNum = 0;
ReleaseObject(pool[recentNum]);
pool[recentNum].SetActive(true);
return pool[recentNum++];
}
public void ReleaseObject(GameObject obj)
{
if (pool.Contains(obj))
{
obj.SetActive(false); // 비활성화
}
else
{
Destroy(obj); // 풀에 포함되지 않은 객체는 파괴
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
public class ObjectPool_3 : MonoBehaviour
{
// [구현사항 3]
// 오브젝트를 미리 생성하지 않고
// 부족할 경우 누적 100개까지 추가 생성,
// 100개가 넘어갈 경우 임시로 생성 후 반환 시 파괴
private List<GameObject> pool;
private const int maxSize = 100;
[SerializeField] private GameObject bulletPrefab;
void Awake()
{
pool = new List<GameObject>();
}
private GameObject CreateObject()
{
GameObject newObject = Instantiate(bulletPrefab);
newObject.SetActive(false); // 초기에는 비활성화
return newObject;
}
public GameObject GetObject()
{
foreach (var obj in pool)
{
if (!obj.activeInHierarchy) // 비활성화된 객체를 찾는다
{
obj.SetActive(true); // 활성화
return obj;
}
}
// 모든 객체가 활성화되어 있을 경우
if (pool.Count < maxSize)
{
GameObject newObject = CreateObject();
pool.Add(newObject);
newObject.SetActive(true);
return newObject;
}
GameObject tempObject = CreateObject();
tempObject.SetActive(true);
return tempObject;
}
public void ReleaseObject(GameObject obj)
{
if (pool.Contains(obj))
{
obj.SetActive(false); // 비활성화
}
else
{
Destroy(obj); // 풀에 포함되지 않은 객체는 파괴
}
}
}
#include <string>
#include <vector>
using namespace std;
int solution(string ineq, string eq, int n, int m)
{
if (eq == "=")
{
if (ineq == ">")
return n >= m ? 1 : 0;
else if (ineq == "<")
return n <= m ? 1 : 0;
}
else if (eq == "!")
{
if (ineq == ">")
return n > m ? 1 : 0;
else if (ineq == "<")
return n < m ? 1 : 0;
}
}
#include <string>
#include <vector>
using namespace std;
int solution(string ineq, string eq, int n, int m) {
string oper = ineq+eq;
if(oper=="<=")
{
return n<=m;
}
else if(oper==">=")
{
return n>=m;
}
else if(oper=="<!")
{
return n<m;
}
else if(oper==">!")
{
return n>m;
}
}
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string str;
cin >> str;
for(int i = 0; i < str.length(); i++)
cout << str[i] <<"\n";
return 0;
}
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string str;
int n;
cin >> str >> n;
for (int i = 0; i < n; i++)
cout << str;
return 0;
}
감사합니다