오늘 학습 키워드

유니티 숙련 팀 프로젝트

오늘 학습 한 내용을 나만의 언어로 정리하기

몬스터 만들기

  • 일단 기존에 강의를 듣고 만들었던 것과 동일하게 시도.

스탠다드 반 강의 (주제 : 디자인 패턴)

  • 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