ClassExample instance = new ClassExample();
public class ClassExample : MonoBehaviour
{
public static ClassExample instance;
void Awake()
{
if (instance != null)
{
Destroy(gameObject); //이미 있는 경우 새로운 인스턴스는 파괴
return;
}
instance = this;
}
}
= 일반화 프로그래밍
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<T>();
if(instance == null)
{
instance = new GameObject(typeof(T).Name).AddComponent<T>();
DontDestroyOnLoad(instance.gameObject); // 필요에 따라 선택적으로 사용
}
}
return instance;
}
}
}
표준이 따로 없어서 자유롭게 만들어도 됨.
단, 파괴 대신 비활성화한다는 것은 필수사항.
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool : MonoBehaviour
{
[SerializeField] GameObject prefab;
[SerializeField] int initialSize = 10;
[SerializeField] int maxSize = 300;
List<GameObject> pool = new List<GameObject>();
void Awake()
{
/// 초기화
/// 초기에 필요한 갯수만큼 오브젝트를 생성
for (int i = 0; i < initialSize; i++)
{
CreateObject();
}
}
GameObject CreateObject()
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false); // 초기 생성 시 비활성화로 생성
pool.Add(obj); // 풀에 넣기
return obj;
}
public GameObject GetObject()
{
foreach (GameObject obj in pool)
{
if(!obj.activeInHierarchy)
{
obj.SetActive(true);
return obj;
}
}
// 사용 가능한 것이 없는 경우 - 새로 생성하기
GameObject newObject = CreateObject();
newObject.SetActive(true); // 바로 사용할 것이므로 활성화하기
if (pool.Count < maxSize) // 1. 만들어진 갯수가 최대 크기보다 작은 경우 - 새로 생성한 것을 pool에 추가
{
pool.Add(newObject);
}
else // 2. 만들어진 갯수가 최대 크기에 도달한 경우 - 임시 오브젝트를 생성하고 반납 시 파괴할 것
{
newObject.name = "Temp";
}
return newObject;
}
public void ReturnObject(GameObject obj)
{
if(obj.name.Equals("Temp")) // 반환 시, 임시 오브젝트라면 파괴
Destroy(obj);
else // 일반 오브젝트라면 비활성화
obj.SetActive(false);
}
}
2021 버전이후부터 제공.
간단하게 델리게이트를 넣어서 커스터마이징 가능한 클래스를 제공.
using UnityEngine;
using UnityEngine.Pool;
public class ObjectPool : MonoBehaviour
{
[SerializeField] GameObject prefab;
const int SIZE = 100;
bool collectionCheck = true;
ObjectPool<GameObject> pool;
void Start()
{
pool = new ObjectPool<GameObject>(
Create,
OnGet,
OnRelease,
OnPoolDestroy,
collectionCheck,
0,
SIZE
);
}
GameObject Create()
{
return Instantiate(prefab, transform);
}
// Pool에서 꺼낼 때 호출
void OnGet(GameObject obj)
{
// 꺼낼 때 활성화하기
obj.SetActive(true);
}
// Pool에 반납 시 호출
void OnRelease(GameObject obj)
{
// 반납 시 비활성화하기
obj.SetActive(false);
}
void OnPoolDestroy(GameObject obj)
{
Destroy(obj);
}
// 외부에서 호출할 메서드
public GameObject GetObject()
{
return pool.Get();
}
public void ReturnObject(GameObject obj)
{
pool.Release(obj);
}
}
전략 인터페이스를 정의.
전략 인터페이스에는 세부 동작을 구현.
using UnityEngine;
// 전략 인터페이스
public interface IRideStrategy
{
void Ride();
}
public class Bicycle : IRideStrategy
{
public void Ride()
{
Debug.Log("Ride Bicycle");
}
}
public class Car : IRideStrategy
{
public void Ride()
{
Debug.Log("Ride Car");
}
}
public class Helicopter : IRideStrategy
{
public void Ride()
{
Debug.Log("Ride Helicopter");
}
}
public class Person : MonoBehaviour
{
IRideStrategy ridableStrategy;
public void SetRideStrategy(IRideStrategy strategy)
{
ridableStrategy = strategy;
}
public void Ride()
{
ridableStrategy.Ride();
}
}
연출에 대한 구현을 UIView 클래스에서 직접하지 않고,
UI를 보여주거나 숨기는 방법을 각 전략 인터페이스에서 가능하도록 구현
public interface IState
{
// 상태들에 들어갈 때, 나올 때, 매 프레임이 중요
void Enter(); // 상태에 들어갈 때 == OnEnable()
void Excute(); // 매프레임 실행할 때 == Update()
void Exit(); // 상태에서 나올 때 == OnDisable()
}
public class IdleState : IState
{
public void Enter()
{
}
public void Excute()
{
}
public void Exit()
{
}
}
public class WanderState : IState
{
public void Enter()
{
}
public void Excute()
{
}
public void Exit()
{
}
}
public class AttackState : IState
{
public void Enter()
{
}
public void Excute()
{
}
public void Exit()
{
}
}
public class StateMachine
{
IState curState;
public void ChangeState(IState newState)
{
if(curState != null)
curState.Exit();
curState = newState;
curState.Enter();
}
// MonoBehaviour의 Update가 아님.
// 이 클래스 아무것도 상속받지 않고 있기에 별개의 메서드로 봐야 함.
public void Update()
{
if(curState != null)
curState.Excute();
}
}
public class Enemy : MonoBehaviour
{
StateMachine stateMachine;
Transform target;
void Start()
{
stateMachine = new StateMachine();
stateMachine.ChangeState(new IdleState());
// new로 원하는 상태를 만들어서 사용
// 이 상태 클래스에 선언된 변수가 없기 때문에 비용적으로 큰 부담은 없음
}
// Update is called once per frame
void Update()
{
DetectEnemy();
}
void DetectEnemy()
{
// 생략
stateMachine.ChangeState(new AttackState());
}
}
Idle / Jump / Walk / Run
Idle / Jump / Move(Walk, Run)으로 나누는 것