//유틸리티 상수
public static partial class ADefine
{
#region 씬 관리자
public static readonly string NAME_UI_CAMERA = "UI Camera";
public static readonly string NAME_MAIN_CAMERA = "Main Camera";
public static readonly string NAME_UI_ROOT = "Canvas";
public static readonly string NAME_OBJECT_ROOT = "ObjectRoot";
public static readonly string NAME_SCENE_MANAGER = "SceneManager";
public static readonly float DEFAULT_PLANE_DISTANCE = 5.0f;
#end region
}
1. 확장성
2. 사용 편리
3. 은닉성(Monobehaviour을 잘 숨겨야 함. 메모리 관리를 위함)
partial: partial 키워드는 클래스, 구조체, 인터페이스 키워드 바로 앞에 위치시키며 2개 이상의 파일에 걸쳐 Type를 나눌 수 있게 된다.
-partial Class는 C# 2.0에 도입된 기능으로, 클래스를 여러 파일에 나눠서 정의할 수 있다.
- 여기서 사용되고 있는 KDefine는 논리적으로 1개의 클래스이다.
=> 컴파일될 때 병합시키기 때문.
// 1. 유틸리티 함수
public static partial class KDefine
{
//readonly: 상수화
const vs readonly
const: 초기화 이후 값을 변경할 수 없음. 선언하는 시점에만 초기화 가능(컴파일 타임 상수)
readonly: 초기화 이후 값을 변경할 수 없다. 선언하는 시점과 생성자에서 초기화(1번). 런타임 상수
EX) 게임을 실행시키면 일단 한얓ㅎ 번 초기 해상도로 실행을 시키고 유저가 본인의 사양에 맞는 해상도를 설정하면 해상도를 상수화시켜버리는 행위 등에 자주 사용된다.
해상도 자체는 한 번 설정이 되면 잘 안바뀌는 옵션
//컴파일 타임 항수는 변수가 실제 값으로 대체가 되고 런타입 상수는 변수 참조형식이기 때문에 성능과 속도를 고려하면 const가 더 우수
단 인스턴스마다 다른 값을 할당시키고 싶거나 사용자 정의 타입이라면 readonly를 사용하면 됨
애초에 사용자 정의 타입은 const 안먹힌다.
//해상도
public static readonly int SCREEN_WIDTH = 1280;
public static readonly int SCREEN_HEIGHT = 720;
public static readonly float UNIT_SCALE = 0.01f;
//
}
//전역 메서드
/////////////////////////
//전역 함수
public static partial class Function
{
//게임 객체를 생성한다
public static GameObject CreatObject(string, a_oName, GameObject.a_oParent, boolbIsStayWorldState = false);
//SetParent의 월드 속성 유지 매개 변수가 true로 설정되면 월드 상에 존재했을 떄의 속성을
그대로 유지하기 때문에 특정 객체의 하위에 종속이 될 경우 부모 객체의 크기에 따라 자식 객체 크기 값의
변화가 발생한다.
var oGameObject = new GameObject(a_oName);
oGameobject.transform.SetParent(a+oParent?.transform, a_bIsStayWorld);
return GameObejct;
//1. 컴포넌트를 탐색한다.
public static T FindComponent<T>(string a) where T : Component
{
var GameObject = Gameobject.Find(a_oName);
return oGamObject?.GetComponentChildrne<T>();
}
//1. 컴포넌트를 추가한다.
public static T AddComponent<T>(GameObject a_oGameObject) where T : Component
{
var oComponent = a_oGameObject.Getcomponent<T>();
if(oComponent == null
{
oComponent = a_oGameObject.AddComponent<T>();
}
return oComponent;
}
//1. 비동기 작업을 대기한다.
public static IEnumerator WaitAsyncOperation(AsyncOperation a_oAsyncOperation,
System.Action<AsyncOperation> a_oCallBack)
{
while(!a_oAsyncOperation.isDone)
{
yield return new WaitForEndOfframe();
a_oCallBack?.Invoke(a_oAsyncOperation);
}
}
//! 함수를 지연 호출한다.
private static IEnumerator DoLateCall(System.Action<object[]> a_oCallBack,
float a_fDelay, object[] a_oParams)
{
yield return new WaitForSeconds(a_fDelay);
a_oCallBack?.Invoke(a_oParams);
}
}
public class CSceneLoader : CSingleton<CSceneLoader>
{
//!씬을 변경한다
public void LoadScene(int a_nIndex)
{
//GetScenePathByBuildIndex
//SceneList의 빌드 인덱스가 가진 씬을 리스트로 담을 수 있다.
//빌드 인덱스: 빌드 설정 창에 지정된 씬 목록에 대한 인덱스
string oScenePath = SceneUtility.GetScenePathByBuildIndex(a_nIndex);
this.LoadScene(oScenePath);
}
//!씬을 변경한다.
public void LoadScene(string a_oName)
{
SceneManager.LoadScene(a_oName, LoadSceneMode.Single);
}
//!씬을 로드한다.
public void LoadScene(int a_nIndex, LoadSceneMode a_eLoadSceneMode = LoadSceneMode.Single)
{
/*
LoadSceneMode.Single : 디폴트 값
- 현재 씬의 오브젝트를 모두 Destroy하고 새롭게 씬을 로드.
LoadSceneMode.Additive
- 현재 씬에 새로운 씬을 추가적으로 덧대어 불러오겠다.
*/
}
//!씬을 로드한다.
public void LoadScene(string a_oName, LoadSceneMode a_eLoadSceneMode = LoadSceneMode.Single)
{
SceneManager.LoadScene(a_oName, a_eLoadSceneMode);
}
//! 씬을 로드한다
publci void LoadSceneAsync(int a_nIndex,1System.Action<AsyncOperation> a_oCallback,
float a_fDelay = 0,LoadSceneMode a_eLoadSceneMode = LoadSceneMode.Single)
{
string oScenePath = SceneUtility.GetScenePathByBuildIndex(a_nIndex);
this.LoadSceneAsync(oScenePath, a_oCallBack, a_fDelay, a_eLoadSceneMode);
}
public void LoadSceneAsync(string a_oName,
1System.Action<AsyncOperation> a_oCallback, float a_fDelay = 0,
LoadSceneMode a_eLoadSceneMode = LoadSceneMode.Single;
{
StartCoroutine(this.DoLoadSceneAsynd(a_oName, a_oCallBack, a_fDelay, a_eLoadSceneMode));
}
private IEnumerator DoLoadSceneAsync(string a_oName)
1System.Action<AsyncOperation> a_oCallback, float a_fDelay,
LoadSceneMode a_eLoadSceneMode)
{
yield return null;
var oAsyncOperation = SceneManager.LoadSceneAsync(a_oName, a_eLoadSceneMode);
yield return Function.WaitAsyncOperation(oAsyncOperation, a_oCallBack);
}
}
public abstract class CSingleton<T> : CComponent where T : CComponent
{
private static T m_oInstance = null;
public static T instance
{
get
{
if(m_oInstance == null)
{
var oGameObject = new GameObject(typeof(T).ToString());
m_oInstance = Function.AddComponent<T>(oGameObject);
DontDestroyOnLoad(oGameObject);
}
}
}
//!인스턴트를 생성한다
public static T Create()
{
return CSingleton<T>.Instance;
}
//!컴포넌트
//추상 클래스
public abstract class CComponent : MonoBehaviour
{
#region
[HideInInspector] public Transform m_oTransform = null;
[HideInInspector] public Rigidbody m_oRigidbody = null;
[HideInInspector] public Rigidbody2D m_oRigidbody2D = null;
#endregion
/*
추상 클래스를 활용한 설계 단계에서는 호출 순서도 고민을 해봐야 한다.
Awake() 함수는 해당 컴포넌트가 다른 게임 오브젝트에 추가되는 시점(AddComponent)에 호출되는 반면
Start()함수는 해당 로직이 실행되는 프레임의 마지막 또는 다음 프레임이 동작할 때 호출된다.
*/
//초기화
public virtual void Awake() //추상 클래스이므로 가상함수로 처리
{
m_oTransform = this.transform;
m_oRigidbody = this.GetComponentInChildren<Rigidbody>();
m_oRigidbody2D = this.GetComponentInChildren<Rigidbody2D>();
}
//초기화
public virtual void Start()
{
//! Do Nothing //아무것도 하지 않음을 알려주기 위해 메모..
}
//상태를 갱신
public virtual void Update()
{
//! Do Nothing
}
//상태를 지연갱신
public virtual void LateUpdate()
{
//! Do Nothing
}
}
//씬 관리자
public class CSceneManager : CComponent
{
#region public 변수
public float m_fPlaneDistance = KDefine.DEFAULT_PLANE_DISTANCE;
#endregion
//UI 카메라 프로퍼티
public static Camera UICamera
{
get
{
return Function.FindComponent<Camera>(KDefine.NAME_UI_CAMERA);
}
}
//메인 카메라 프로퍼티
public static Camera MainCamera
{
get
{
return Function.FindComponent<Camera>(KDefine.NAME_MAIN_CAMERA);
}
}
// UI 루트 프로퍼티
public static GameObject UIRoot
{
get
{
return GameObject.Find(KDefine.NAME_UI_ROOT);
}
}
public static GameObject ObjectRoot
{
get
{
return GameObject.Find(KDefine.NAME_OBJECT_ROOT);
}
}
//현재 씬 관리자 프로퍼티
public static GameObject CurrentSceneManager
{
get
{
return GameObject.Find(KDefine.NAME_SCENE.MANAGER);
}
}
//Find 느린데 쓰는 이유? 런타임 이전에 미리 찾아오고 시작하는 것이므로!
//초기화
public override void Awake()
{
base.Awake(); // 상속된 어웨이크도 작동하게 만들어줌.
SetupUICamera();
SetupMainCamera();
//모니터 주파수에 맞춰 렌더링 퍼포먼스를 조절하고 '티어링' 현상을 방지하겠다~는 목적
QualitySetting.vSyncCount = 0;
//60 프레임으로 고정
Application.targetFrameRate = 60;
Screen.SetResolution(KDefine.SCREEN_WIDTH, KDefine.SCREEN_HEIGHT, false);
}
//상태를 갱신
public override void Update()
{
base.Update();
if(Input.GetKeyDown(KeyCode.Escape))
{
//CSceneLoader.Instance.LoadScene(0);
CSceneLoader.Instance.LoadSceneAsync(0, (a_oAsyncOperation) =>
{
Debug.LogFormat("Percent: {0}", a_oAsyncOperation.progress); //람다식 이용
});
}
}
/*
프로젝션(투영)
- 투영은 3D 장면에서 2D 표면을 얻는 과정
- 크게 두 가지가 있으며 Perspective는 3D / orthographic은 2D에서 많이 사용된다.
Perspective(원근 투영) / orthographic (직교 투영)
원근 투영: 원근감, 카메라가 보고 있다면 가까이에 있는 물체는 카메라의 앞으로 올수록
스케일을 위아래로 늘려 원근감을 부여한다.
직교 투영: 오브젝트를 원근감 없이 수직 위에서 내려다 보듯이 투영
isometric
*/
// UI카메라를 설정한다.
protected void SetupUICamera()
{
if(CSceneManager.UICamera != null)
{
CSceneManager.UICamera.orthographic = true;
CSceneManager.UICamera.orthographicSize =
(KDefine.SCREEN_HEIGHT / 2.0f) * KDefine.UNIT_SCALE
}
}
// 메인 카메라를 설정한다.
protected void SetupMainCamera()
{
if(CSceneManager.MainCamera != null)
{
float fPlaneHeight = (KDefine.SCREEN_HEIGHT / 2.0f) * KDefine.UNIT_SCALE;
float fFieldOfView = Mathf.Atan(fPlaneHeight / m_fPlaneDistance);
CSceneManager.MainCamera.orthographic = false;
CSceneManager.MainCamera.fieldOfView = (fFieldOfView * 2.0f) * Mathf.Rad2Deg;
//호도법 알아봐!
}
}
//접근제어자 public, private, protected, internal
//internal 알아보기
}
public class CSoundManager : MonoBehaviour
{
}
+) 추가로 알아볼 것
추상클래스
메모리 대기
메모리 구현화
'이론(면접)' 카테고리의 다른 글
LINQ (0) | 2022.07.15 |
---|---|
Attribute (0) | 2022.07.01 |
SendMessage (ray) (0) | 2022.07.01 |
변수 표기법 (0) | 2022.06.30 |
배열 / 정적 클래스 / 확장메서드 (0) | 2022.06.29 |