
오늘 학습 키워드
유니티 숙련 팀 프로젝트
오늘 학습 한 내용을 나만의 언어로 정리하기
몬스터 만들기
- 일단 기존에 강의를 듣고 만들었던 것과 동일하게 시도.
스탠다드 반 강의 (주제 : 디자인 패턴)
- GoF : 디자인패턴 처음에 23가지 만드신 분들
싱글톤
- 중복 개체가 생기지 않도록 꼭 만들어줘야됨
- 너도 나도 다 싱글톤 변수 쓰면 안됨…
- 제네릭으로 만드는게 편하다!
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
// T 안에 뭐든 들어갈 수 있다
// 다만 T는 MonoBehaviour 를 상속받아야 한다.
// 그리고 Singleton도 MonoBehvaiour를 상속한다.오브젝트 풀
- 자주 생기는 오브젝트가 많으면 쓰기 좋음
public class ObjectPool : MonoBehaviour
{
public GameObject prefab;
public int poolSize = 10;
private Queue<GameObject> poolQueue = new();
void Start()
{
for(int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
poolQueue.Enqueue(obj);
}
}
public GameObject GetObject()
{
if(poolQueue.Count > 0)
{
GameObject obj = poolQueue.Dequeue();
obj.SetActive(true);
return obj;
}
else
{
GameObject obj = Instantiate(prefab);
return obj;
}
}
public void ReturnObject(GameObject obj)
{
obj.SetActive(false);
poolQueue.Enqueue(obj);
}
}- 근데 2021? 버전부터 이걸 제공함 ⇒ ObjectPool!
public class BulletPoolManager : MonoBehvaiour
{
public Bullet bulletPrefab;
public ObjectPool<Bullet> bulletPool;
void Awake()
{
bulletPool = new ObjectPool<Bullet>(
createFunc: () =>
{
// 풀에 객체가 없어서 새로 만들어야 할 때 호출
return Instantiate(bulletPrefab);
},
actionOnGet : (bullet) =>
{
// 풀에서 객체를 꺼냈을 때 호출
bullet.gameObject.SetActive(true);
},
actionOnRelease : (bullet) =>
{
// 풀에 객체를 반환할 떄 호출
bullet.gameObject.SetActive(false);
},
actionOnDestory : (bullet) =>
{
// 풀의 객체를 아예 삭제할 때 호출
Destroy(bullet.gameObject);
},
collectionCheck : true, // 풀에 객체 없을 때 더 늘려줄것인지
defaultCapacity : 10,
maxSize: 20
);
}
public void SpawnBullet(Vector3 pos, Quaternion rot)
{
Bullet bullet = bulletPool.Get(); // 풀에서 총알 가져오기
bullet.transform.position = pos;
bullet.transform.rotation = rot;
bullet.Init(bulletPool); // 풀 참조 전달
}
}전략 패턴
- 타입에 따라 다른 일을 하게 하고 싶음
switch(myWeapon)
{
case Weapons.Gun :
break;
case Weapons.Bow :
...
}- 위와 같이 생긴거를 아래처럼 바꿀 수 있음
public interface IWeaponStrategy
{
void Attack();
}
public class GunStrategy : IWeaponStrategy
{
void Attack()
{
Debug.Log("총 빵야");
}
}
...
public class Player : MonoBehaviour
{
public IWeaponStrategy currentWeapon;
public void SetWeapon(IWeaponStrategy weaponStrategy)
{
currentWeapon = weaponStrategy;
}
public void Attack()
{
if(currentWeapon != null) currentWeapon.Attack();
else Debug.Log("무기가 없습니다!");
}
}
...상태 패턴
- 오브젝트 내부 상태에 따라 동작이 달라져야 할 때 쓰임
public interface IEnemyState
{
void Enter();
void Execute();
void Exit();
}
public class IdleState : IEnemyState
public class PatrolState : IEnemyState
public class AttackState : IEnemyState
public class EnemyObj : MonoBehaviour
{
private IEnemyState currentState;
void Start()
{
ChangeState(new IdleState());
}
void Update()
{
currentState?.Execute(0;)
}
public void ChangeState(IEnemyState newState)
{
if(currentState != null)
{
currentState.Exit();
}
currentState = newState;
if(currentState != null)
{
currentState.Enter();
}
}
}
- 상태가 직접 뭔가를 하게 하지 말아라!!! 상태가 그저 그 상태를 가지는 객체의 함수를 부를수는 있다.
- 새 상태를 추가한다 하더라도 굳이 기존 상태를 바꿀 필요가 없다
옵저버 패턴
- 관찰 대상이 변하는 걸 봐야할 때
// Subject : 관찰 대상
public class UnitySubject : MonoBehaviour
{
public UnityEvent<string> OnNotify = new UnityEvent<string>();
public void TriggerEvent()
{
OnNotify.Invoke("학습하시오 스튜던트");
}
}
// Observer : 관찰자
public class UnityObserver : MonoBehaviour
{
public UnitySubject subject;
void OnEnable()
{
subject.OnNotify.AddListener(OnNotifyReceived);
}
void OnDisable()
{
subject.OnNotify.RemoveListener(OnNotifyReceived);
}
void OnNotifyReceived(string message)
{
Debug.Log($"거부할 수 없는 명령 : {message}")
}
}학습하며 겪었던 문제점 & 에러
문제 1
- 문제&에러에 대한 정의
텍스쳐가 깨지는 현상이 있음
- 해결 방법
Shader를 Standard로 바꿈
문제 2
- 문제&에러에 대한 정의
분명 Singleton Generic으로 Input Manager를 만들었는데, 자꾸 null 오류가 났다.
- 내가 한 시도
AddComponent<T> 부분을 try-catch로 잡아봤다
- 해결 방법
알고보니, 문제는 여기였다.
private void Awake()
{
if (runtimeActions == null)
{
runtimeActions = Instantiate(defaultActions);
}
}defaultActions는 이미 날라가고 없기 때문에 Instantiate가 불가능했던 것.
- 새롭게 알게 된 점
DontDestroyOnLoad 가 만능은 아니다…
문제 3
- 문제&에러에 대한 정의
기껏 옮겼더니 이제는 EventSystem이 맛이 갔음
- 내가 한 시도
씬 로드 다시 할 때마다 runtimeActions에 있는 UI 파트를 다시 연결
- 해결 방법
private void Awake()
{
if (runtimeActions == null && defaultActions != null)
{
runtimeActions = Instantiate(defaultActions);
runtimeActions.name = defaultActions.name + "_Runtime";
}
SceneManager.sceneLoaded += OnSceneLoaded;
if(!Application.isBatchMode && Application.isPlaying)
DontDestroyOnLoad(gameObject);
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
UIModuleSettings();
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
// changed runtimeActions apply to EventSystem
private void UIModuleSettings()
{
uiModule = FindObjectOfType<InputSystemUIInputModule>();
if (uiModule == null)
{
return;
}
uiModule.actionsAsset = runtimeActions;
uiModule.move = InputActionReference.Create(runtimeActions.FindAction("UI/Move"));
uiModule.submit = InputActionReference.Create(runtimeActions.FindAction("UI/Submit"));
uiModule.cancel = InputActionReference.Create(runtimeActions.FindAction("UI/Cancel"));
uiModule.point = InputActionReference.Create(runtimeActions.FindAction("UI/Point"));
uiModule.leftClick = InputActionReference.Create(runtimeActions.FindAction("UI/Click"));
uiModule.scrollWheel = InputActionReference.Create(runtimeActions.FindAction("UI/ScrollWheel"));
uiModule.rightClick = InputActionReference.Create(runtimeActions.FindAction("UI/RightClick"));
uiModule.middleClick = InputActionReference.Create(runtimeActions.FindAction("UI/MiddleClick"));
Debug.Log("UI Module Settings Done.");
}- 새롭게 알게 된 점
DontDestroyOnLoad가 만능은 아니다 22