no image
Unity - Unity Coroutine(코루틴)
📌 Coroutine이란?**코루틴(Coroutine)**은 Unity에서 제공하는 특별한 함수로, 작업의 흐름을 중간에 일시정지하고, 조건이 충족되면 다시 이어서 실행할 수 있다.코루틴은 IEnumerator 반환형을 가지며, StartCoroutine() 함수를 통해 실행된다.IEnumerator ExampleCoroutine(){ Debug.Log("1초 대기 전"); yield return new WaitForSeconds(1f); Debug.Log("1초 대기 후");}StartCoroutine(ExampleCoroutine());⚙️ Coroutine 실행 흐름코루틴은 Update() 함수가 끝난 뒤 실행된다.즉, 모든 Update() 함수가 호출된 이후, 코루틴이 yield..
2025.07.28
no image
Unity - Unity MonoBehaviour 생명주기 (Lifecycle) 정리
🌀 Unity MonoBehaviour 생명주기 (Lifecycle) 정리Unity는 MonoBehaviour 기반의 스크립트를 일정한 순서로 호출하며, 게임 오브젝트의 생성부터 종료까지 다양한 이벤트 함수를 실행한다. 아래는 각 단계별로 정리한 생명주기 흐름이다. 🔹 1. 초기화 (Initialization)이벤트함수설명Awake()오브젝트가 인스턴스화된 직후 호출. 스크립트 간 참조 연결에 자주 사용. Start()보다 먼저 호출됨.OnEnable()오브젝트가 활성화될 때마다 호출. 컴포넌트가 켜지거나 오브젝트가 활성화되면 호출됨.Reset()에디터에서 컴포넌트를 추가할 때 자동 호출됨. 기본값 초기화 목적.Start()스크립트가 활성화된 상태일 때, 첫 번째 프레임 전에 단 한 번 호출됨. - ..
2025.07.28
no image
Unity - Collider2D의 Layer Overrides(Include Layers, Exclude Layers) 알아보기
✍️ 본문최근 Unity에서 OnTriggerEnter2D가 도무지 작동하지 않아 시간을 꽤 허비했습니다.알고 보니 Collider2D의 "Layer Overrides" 설정이 원인이었습니다.이번 글에서는 이 기능이 무엇인지, 왜 문제가 생기는지, 어떻게 설정해야 하는지를 정리해봅니다.🧩 Layer Overrides란?Unity 2020.3부터 Collider2D에는 Layer Overrides 기능이 추가되었습니다.이는 기존의 Physics 2D → Layer Collision Matrix 설정을 무시하고,Collider 개별 객체 단위에서 충돌 대상을 지정할 수 있는 기능입니다.💡 간단히 말해, Collider 자신만의 충돌 필터를 설정할 수 있게 된 것이죠.⚙️ 구성 요소 설명항목설명Includ..
2025.07.25
no image
Unity - 2D TopDown에서 캐릭터와 무기의 회전 및 Flip 처리 정리
Unity 2D TopDown에서 캐릭터와 무기의 회전 및 Flip 처리 정리✨ 문제 배경TopDown 방식의 2D 슈팅 게임을 만들다 보면, 마우스 방향에 따라 캐릭터가 회전하고, 무기도 함께 회전하도록 구현해야 합니다.특히 무기가 캐릭터의 하위 오브젝트(WeaponPivot)로 존재하는 경우, 마우스가 왼쪽/오른쪽으로 이동할 때 캐릭터는 SpriteRenderer.flipX를 통해 반전시키고, 무기는 Y축 회전(localEulerAngles.y)과 Z축 회전(localEulerAngles.z)을 동시에 고려해야 합니다.이 글에서는 캐릭터의 Flip 처리와 무기의 회전 처리를 어떻게 해결했는지 기록합니다.🔀 캐릭터 회전 처리private void Rotate(Vector2 direction){ ..
2025.07.23
no image
Unity - (Template vs Template Method Pattern) vs (Class vs Instance)
❓템플렛 메서드 패턴에 대해서 공부하다가 너무 궁금한게 생겼다 그럼 템플릿이랑 템플릿 메서드 패턴의 차이점이 뭐지 싶었다. "템플릿"은 그냥 일반적인 용어이고,"템플릿 메서드 패턴"은 디자인 패턴이다.즉, 템플릿은 개념,템플릿 메서드 패턴은 그 개념을 객체지향 코드에 적용한 구체적인 방식이에요.📌 템플릿(Template) = “틀”, “형식”그냥 일반적인 단어로, 어떤 공통된 구조, 순서, 뼈대를 말함예:웹사이트에서 “이메일 템플릿”게임에서 “스킬 이펙트 템플릿”Unity에서 ScriptableObject 템플릿“이걸 따라 만들어” 라는 공통 기준/포맷🧱 템플릿 메서드 패턴 (Template Method Pattern)이 "틀"이라는 개념을 OOP에서 상속 + 다형성 + 추상화를 이용해 구현한 디자인..
2025.07.03
no image
Unity - 스크립터블오브젝트(ScriptableObject)&예제
✅ ScriptableObject란?📌 개념 정리ScriptableObject는 MonoBehaviour처럼 Unity에서 사용하는 클래스지만,씬에 붙는 컴포넌트가 아니고, 독립적인 데이터 객체야.데이터를 자산(Asset)으로 만들어 저장하고 공유할 수 있는 방식을 제공해.✅ 언제 사용하나요?여러 객체가 동일한 데이터를 참조할 때예: 스탯, 설정값, 아이템 정보 등프리팹이나 코드와 독립적으로 데이터 관리하고 싶을 때설정 변경이 쉽고 유지보수 편함인스펙터에서 직접 데이터 입력하고 저장하고 싶을 때커스텀 에디터 연동도 쉬움✅ 간단한 예제: 캐릭터 능력치 데이터 만들기1. CharacterStats.csusing UnityEngine;[CreateAssetMenu(fileName = "NewCharacter..
2025.07.02
no image
Unity - Update(), FixedUpdate(), LateUpdate()
✅ Unity의 3가지 주요 루프 함수함수 이름실행 주기용도특징Update()매 프레임마다사용자 입력, 일반 로직프레임 속도에 따라 실행 빈도 달라짐 (가변)FixedUpdate()고정 시간 간격마다물리 연산 (Rigidbody)물리 시스템과 동기화됨LateUpdate()Update() 이후카메라 추적, 뒷정리 작업모든 Update()가 끝난 후 실행 ✅ 1. Update()🔸 언제 실행됨?매 프레임마다 1번씩 실행프레임 수에 따라 실행 빈도가 달라짐 (60FPS면 초당 60번, 30FPS면 초당 30번)🔸 주로 어디에 사용?사용자 입력 처리 (키보드, 마우스 등)UI 업데이트시간 기반 이동 (예: transform.Translate(speed * Time.deltaTime))🔸 주의할 점프레임이 ..
2025.07.01
no image
유니티 머신러닝 2(Unity ML-Agents)
자 이번에는 유니티 머신러닝 셋팅이 완료되었으니 바로 예제로 들어가보겠습니다! 가상환경 셋팅이 되지않으셨다면 https://dev-jen.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-1Unity-ML-Agents 유니티 머신러닝 1(Unity ML-Agents) 자세한 설명은 유니티 머신러닝 깃 허브에 잘 나와있습니다! https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Installation.md 유니티 머신러닝 깃허브 기준 설명서 -> docs -> Installation.md 로 들어가시 dev-jen.tistory.com 이 글을..
2024.03.19
반응형

📌 Coroutine이란?

**코루틴(Coroutine)**은 Unity에서 제공하는 특별한 함수로, 작업의 흐름을 중간에 일시정지하고, 조건이 충족되면 다시 이어서 실행할 수 있다.

코루틴은 IEnumerator 반환형을 가지며, StartCoroutine() 함수를 통해 실행된다.

IEnumerator ExampleCoroutine()
{
    Debug.Log("1초 대기 전");
    yield return new WaitForSeconds(1f);
    Debug.Log("1초 대기 후");
}
StartCoroutine(ExampleCoroutine());

⚙️ Coroutine 실행 흐름

코루틴은 Update() 함수가 끝난 뒤 실행된다.
즉, 모든 Update() 함수가 호출된 이후, 코루틴이 yield return한 지점부터 재개된다.


⏱️ 다양한 YieldInstruction 종류

YieldInstruction 설명
yield return null 다음 프레임까지 대기 후 이어서 실행
yield return new WaitForSeconds(x) x초 후에 이어서 실행
yield return new WaitForFixedUpdate() 모든 FixedUpdate() 이후에 실행됨
yield return new WaitUntil(() => condition) 주어진 조건이 true가 될 때까지 대기
yield return new WaitWhile(() => condition) 주어진 조건이 false가 될 때까지 대기
yield return www WWW 요청(웹 요청)이 완료될 때까지 대기 (UnityWebRequest 권장)
yield return StartCoroutine(Other()) 다른 코루틴이 완료될 때까지 대기
 

🔁 Coroutine 중단 및 종료

  • 중단: StopCoroutine("함수이름"), StopCoroutine(코루틴변수)
  • 모든 코루틴 종료: StopAllCoroutines()
Coroutine myRoutine;

void Start()
{
    myRoutine = StartCoroutine(MyCo());
}

void StopIt()
{
    StopCoroutine(myRoutine);
}

 

여기서 주의할점은 코루틴을 변수로 사용하지 않는다면 StopCoroutine을해도 멈추지 않는다 왜냐하면 다른 인스턴스를 참조하기 때문이다!!


✅ 언제 Coroutine을 사용해야 할까?

사용 사례설명
연출 처리 화면 전환, 효과 타이밍, 대기 후 실행 등
시간 기반 반복 일정 시간 간격으로 동작 반복 (예: 총알 발사 쿨타임)
조건 대기 어떤 조건을 만족할 때까지 기다리는 처리
비동기 작업 웹 요청, 파일 로딩 등 완료까지 시간이 걸리는 작업
 

🧠 주의할 점

  • yield return new WaitForSeconds()는 Time.timeScale의 영향을 받는다. (0이면 멈춤)
  • MonoBehaviour가 비활성화되면 코루틴도 멈춘다.
  • 코루틴 내에서 무한 루프를 만들면 게임이 멈출 수 있다.

🧪 예시: 간단한 반복 공격

IEnumerator AutoAttack()
{
    while (true)
    {
        Attack();
        yield return new WaitForSeconds(1f); // 1초마다 공격
    }
}

🏁 마무리

코루틴은 Unity 개발에서 시간을 다루는 가장 강력한 도구 중 하나이다.
처음엔 Update()보다 복잡하게 느껴질 수 있지만, 익숙해지면 타이밍 제어, 연출 구현, 대기 처리에 매우 유용하다.

 

 

흠..원래 개발할때 코루틴을 많이 썼었는데 인보크도 많이 사용하는 듯 하다 인보크와 코루틴 비교하는 글도 한번 작성해 봐야겠다.

반응형
반응형

🌀 Unity MonoBehaviour 생명주기 (Lifecycle) 정리

Unity는 MonoBehaviour 기반의 스크립트를 일정한 순서로 호출하며, 게임 오브젝트의 생성부터 종료까지 다양한 이벤트 함수를 실행한다. 아래는 각 단계별로 정리한 생명주기 흐름이다.

 

🔹 1. 초기화 (Initialization)

이벤트 함수설명
Awake() 오브젝트가 인스턴스화된 직후 호출. 스크립트 간 참조 연결에 자주 사용. Start()보다 먼저 호출됨.
OnEnable() 오브젝트가 활성화될 때마다 호출. 컴포넌트가 켜지거나 오브젝트가 활성화되면 호출됨.
Reset() 에디터에서 컴포넌트를 추가할 때 자동 호출됨. 기본값 초기화 목적.
Start() 스크립트가 활성화된 상태일 때, 첫 번째 프레임 전에 단 한 번 호출됨.

 

- Awake: 이 함수는 항상 Start 함수 전에 호출되며 프리팹이 인스턴스화 된 직후에 호출됩니다. 게임 오브젝트가 시작하는 동안 비활성 상태인 경우 Awake 함수는 활성화될 때까지 호출되지 않습니다.


- OnEnable: (오브젝트가 활성화된 경우에만): 오브젝트 활성화 직후 이 함수를 호출합니다. 레벨이 로드되거나 스크립트 컴포넌트를 포함한 게임 오브젝트가 인스턴스화될 때와 같이 MonoBehaviour를 생성할 때 이렇게 할 수 있습니다.

 

- Start: 스크립트 인스턴스가 활성화된 경우에만 첫 번째 프레임 업데이트 전에 호출됩니다.


🔹 2. 물리 업데이트 (Physics)

이벤트 함수설명
FixedUpdate() 일정 시간 간격으로 호출되는 물리 업데이트. Rigidbody 물리 계산 시 여기에 구현.
OnTriggerEnter/Stay/Exit() 트리거 충돌 감지 이벤트
OnCollisionEnter/Stay/Exit() 일반 충돌 감지 이벤트

 

Unity - Update(), FixedUpdate(), LateUpdate()

✅ Unity의 3가지 주요 루프 함수함수 이름실행 주기용도특징Update()매 프레임마다사용자 입력, 일반 로직프레임 속도에 따라 실행 빈도 달라짐 (가변)FixedUpdate()고정 시간 간격마다물리 연산 (Rigidb

dev-jen.tistory.com

- FixedUpdate: FixedUpdate 는 종종 Update 보다 더 자주 호출됩니다. 프레임 속도가 낮은 경우 프레임당 여러 번 호출될 수 있으며 프레임 속도가 높은 경우 프레임 사이에 호출되지 않을 수 있습니다. 모든 물리 계산 및 업데이트는 FixedUpdate 후 즉시 발생합니다. FixedUpdate 의 움직임 계산을 적용할 때 Time.deltaTime 만큼 값을 곱할 필요가 없습니다. FixedUpdate 가 프레임 속도와 관계없이 신뢰할 수있는 타이머에서 호출되기 때문입니다.

- Update: Update 는 프레임당 한 번 호출됩니다. 프레임 업데이트를 위한 주요 작업 함수입니다.

- LateUpdate: LateUpdate 는 Update 가 끝난 후 프레임당 한 번 호출됩니다. Update 에서 수행된 모든 계산은 LateUpdate 가 시작할 때 완료됩니다. LateUpdate 는 일반적으로 다음의 3인칭 카메라에 사용합니다. 캐릭터를 움직이고 Update 로 방향을 바꾸게 하는 경우 LateUpdate 에서 모든 카메라 움직임과 로테이션 계산을 수행할 수 있습니다. 이렇게 하면 카메라가 포지션을 추적하기 전에 캐릭터가 완전히 움직였는지 확인할 수 있습니다.

 


🔹 3. 입력 및 게임 로직 (Input & Game Logic)

이벤트 함수설명
Update() 프레임마다 한 번 호출. 게임 로직의 중심 함수
LateUpdate() Update()가 끝난 직후 호출. 주로 카메라 추적 처리 등에 사용
OnMouseDown/Up/Drag() 마우스 관련 이벤트 감지

🔹 4. 애니메이션 관련 (Animation)

이벤트 함수설명
OnAnimatorMove() 루트 모션 제어용 함수
OnAnimatorIK() IK(역운동학) 처리용 함수
StateMachineBehaviour 콜백들 OnStateEnter, OnStateExit, OnStateUpdate, OnStateIK, OnStateMove 등
내부 프로세스 State Machine Update, ProcessGraph, ProcessAnimation, WriteTransform, WriteProperties 등

🔹 5. 렌더링 전/후 처리 (Rendering)

이벤트 함수설명
OnPreCull() 카메라가 오브젝트를 컬링하기 전 호출
OnBecameVisible/Invisible() 카메라 시야에 들어오거나 나갈 때 호출
OnWillRenderObject() 오브젝트가 카메라에 의해 렌더링될 때 호출
OnPreRender() / OnPostRender() 카메라 렌더링 전/후 호출
OnRenderImage() 포스트 프로세싱에 사용
OnRenderObject() GL이나 Graphics API를 직접 호출할 때
OnDrawGizmos() 에디터에서 Gizmo를 그릴 때
OnGUI() GUI를 그릴 때. 프레임당 여러 번 호출

🔹 6. 코루틴 (Coroutine)

사용법 설명
yield return null 다음 프레임까지 대기
yield return new WaitForSeconds(x) x초간 대기
yield return new WaitForFixedUpdate() 다음 FixedUpdate 이후 실행
yield return StartCoroutine() 다른 코루틴을 완료할 때까지 대기

🔹 7. 종료 및 비활성화 (Decommissioning)

이벤트 함수 설명
OnApplicationPause() 앱이 일시정지 될 때 호출
OnApplicationQuit() 애플리케이션이 종료될 때 호출
OnDisable() 오브젝트가 비활성화될 때 호출
OnDestroy() 오브젝트가 제거되거나 씬이 종료될 때 호출됨

✅ 요약: 주요 순서 흐름

  1. Awake → OnEnable → Start
  2. FixedUpdate → Update → LateUpdate
  3. (필요 시) Trigger/Collision → Animator 관련 → Rendering → Coroutine 재개
  4. OnDisable → OnDestroy → OnApplicationQuit

 

 

원래 생명주기에 대해서는 잘 알고 있다고 생각했는데..내가 모르는 라이프사이클의 함수가 굉장히 많았다..하나씩 정리해보면서 느꼈지만 아직도 공부할게 산더미 인거같다ㅎㅎ..

반응형
반응형

✍️ 본문

최근 Unity에서 OnTriggerEnter2D가 도무지 작동하지 않아 시간을 꽤 허비했습니다.
알고 보니 Collider2D의 "Layer Overrides" 설정이 원인이었습니다.
이번 글에서는 이 기능이 무엇인지, 왜 문제가 생기는지, 어떻게 설정해야 하는지를 정리해봅니다.


🧩 Layer Overrides란?

Unity 2020.3부터 Collider2D에는 Layer Overrides 기능이 추가되었습니다.
이는 기존의 Physics 2D → Layer Collision Matrix 설정을 무시하고,
Collider 개별 객체 단위에서 충돌 대상을 지정할 수 있는 기능입니다.

💡 간단히 말해, Collider 자신만의 충돌 필터를 설정할 수 있게 된 것이죠.


⚙️ 구성 요소 설명

항목 설명
Include Layers 충돌하고자 하는 레이어만 지정합니다. 지정된 레이어만 통과 가능
Exclude Layers 충돌을 막고 싶은 레이어를 명시합니다. 포함보다 우선 순위가 높습니다

🔁 동작 우선순위

Unity에서 충돌이 발생하려면 다음 조건이 모두 만족해야 합니다:

  1. 두 Collider의 Include Layers에 서로의 레이어가 포함되어 있어야 함
  2. 두 Collider의 Exclude Layers에 서로의 레이어가 없어야 함
  3. Physics 2D의 Layer Collision Matrix에서도 서로 충돌이 가능해야 함

❗ Layer Overrides 설정이 존재하면 Collision Matrix보다 우선 적용됩니다


🔧 문제 예시와 해결

문제 상황:

  • BoxCollider2D (IsTrigger ✅)가 있음
  • Rigidbody2D 있는 플레이어가 진입하는데도 OnTriggerEnter2D() 호출 안 됨
  • 레이어 충돌 매트릭스도 제대로 설정되어 있음

원인:

Include Layers와 Exclude Layers가 둘 다 Nothing으로 되어 있어
실제로 어떤 레이어와도 충돌하지 않도록 차단되어 있었음

해결:

  • Include Layers: Everything 또는 충돌 허용할 레이어 선택
  • Exclude Layers: Nothing으로 설정

✅ 권장 설정 예시

항목
IsTrigger
Include Layers Player (또는 Everything)
Exclude Layers Nothing
플레이어 쪽 Rigidbody2D + Collider2D, 태그: "Player"
 

💡 기억할 것

  • Include Layers = Nothing이면 → 아무와도 충돌 안 함
  • Exclude Layers = Everything이면 → 모든 충돌 차단됨
  • Layer Collision Matrix가 잘 되어 있어도, Override가 있으면 무시됨

📝 마무리

Collider가 이상하게 작동하지 않을 땐, 이제 Layer Overrides도 꼭 함께 확인하세요.
특히 씬에선 잘 되는데 실제 빌드에서 안 되는 경우, 이 설정이 숨겨진 원인일 수도 있습니다...

 

후..계속 이상하게 OnTriggerEnter2D를 했는대도 아무것도 나오지않아서..당황했다 이거는 절대 안까먹을듯 하다..include, Exclude 레이어 꼭 잘 확인하자.. 덕분에 새로운거 자세히 알았네ㅎㅎ..

반응형
반응형

Unity 2D TopDown에서 캐릭터와 무기의 회전 및 Flip 처리 정리

✨ 문제 배경

TopDown 방식의 2D 슈팅 게임을 만들다 보면, 마우스 방향에 따라 캐릭터가 회전하고, 무기도 함께 회전하도록 구현해야 합니다.

특히 무기가 캐릭터의 하위 오브젝트(WeaponPivot)로 존재하는 경우, 마우스가 왼쪽/오른쪽으로 이동할 때 캐릭터는 SpriteRenderer.flipX를 통해 반전시키고, 무기는 Y축 회전(localEulerAngles.y)과 Z축 회전(localEulerAngles.z)을 동시에 고려해야 합니다.

이 글에서는 캐릭터의 Flip 처리와 무기의 회전 처리를 어떻게 해결했는지 기록합니다.


🔀 캐릭터 회전 처리

private void Rotate(Vector2 direction)
{
    float rotZ = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
    bool isLeft = Mathf.Abs(rotZ) > 90f;

    // 캐릭터의 좌우 반전 처리
    characterRenderer.flipX = isLeft;

    // 무기 회전 처리 (WeaponPivot)
    if (weaponPivot != null)
    {
        weaponPivot.localRotation = Quaternion.Euler(
            0f, // X
            isLeft ? 180f : 0f, // Y
            isLeft ? -rotZ : rotZ // Z
        );
    }

    // 무기 내부에서도 좌우 반전 처리할 수 있음 (선택)
    weaponhandler?.Rotate(isLeft);
}

✅ 핵심 포인트

  • 마우스 방향을 Atan2로 각도로 변환해 Z축 회전각을 계산합니다.
  • 각도(rotZ)가 ±90도를 넘는 경우 왼쪽으로 간주하여 flipX = true
  • 무기 피벗(WeaponPivot)은 Y축 기준 180도 회전과 Z축 회전을 조합해야 자연스럽게 반전됩니다.

🗡️ 무기 Flip 처리 예시

WeaponHandler 클래스에서 무기의 스프라이트 반전을 처리하고 싶다면 다음과 같이 작성할 수 있습니다.

public override void Rotate(bool isLeft)
{
    // 필요 시 무기 자체 SpriteRenderer 반전 (필요 없으면 생략 가능)
    weaponRenderer.flipY = isLeft;
}

단, 무기 Sprite가 여러 개거나 별도 애니메이션이 있는 경우 flipY보다 Transform.localEulerAngles 회전을 직접 조작하는 것이 더 안정적입니다.


📅 회고 및 느낀 점

오늘 하루를 무기 회전 방향 잡는 데에 대부분 썼지만, 결국 핵심은 Y축 Flip과 Z축 회전의 조합이라는 걸 깨달았습니다. 단순히 SpriteRenderer만 뒤집는 것으로는 해결되지 않으며, 부모 오브젝트인 WeaponPivot의 localRotation을 정확히 조작해야 원하는 결과를 얻을 수 있었습니다.


✨ 최종 정리 코드 (간단 버전)

float rotZ = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
bool isLeft = Mathf.Abs(rotZ) > 90f;

characterRenderer.flipX = isLeft;
weaponPivot.localRotation = Quaternion.Euler(
    0f,
    isLeft ? 180f : 0f,
    isLeft ? -rotZ : rotZ
);

이 방식은 대부분의 TopDown 슈팅에서 유용하게 사용할 수 있습니다. 이제 총도 자연스럽게 회전하고, 방향에 따라 무기와 캐릭터가 모두 올바르게 반응하게 되었습니다!

이거 만드느라..몇시간을 썼는지 모르겠네여.. 그냥 총을 구현하고 싶을 뿐이였는데 전에 쓰던 무기는 그냥 활이라서 스프라이트가 1개밖에 존재하지 않는거라 문제되지 않았지만 총은 부품 1개1개 전부 스프라이트로 되어있어서 조금 난감했었다.. 그래도.. 결국에는 해결했으니 다행이다ㅠㅜㅜ

 

 

반응형
반응형

템플렛 메서드 패턴에 대해서 공부하다가 너무 궁금한게 생겼다 그럼 템플릿이랑 템플릿 메서드 패턴의 차이점이 뭐지 싶었다.

 

"템플릿"은 그냥 일반적인 용어이고,
"템플릿 메서드 패턴"은 디자인 패턴이다.

즉, 템플릿은 개념,
템플릿 메서드 패턴은 그 개념을 객체지향 코드에 적용한 구체적인 방식이에요.


📌 템플릿(Template) = “틀”, “형식”

  • 그냥 일반적인 단어로, 어떤 공통된 구조, 순서, 뼈대를 말함
  • 예:
    • 웹사이트에서 “이메일 템플릿”
    • 게임에서 “스킬 이펙트 템플릿”
    • Unity에서 ScriptableObject 템플릿

“이걸 따라 만들어” 라는 공통 기준/포맷


🧱 템플릿 메서드 패턴 (Template Method Pattern)

  • 이 "틀"이라는 개념을 OOP에서 상속 + 다형성 + 추상화를 이용해 구현한 디자인 패턴
  • 부모 클래스에서 전체 **알고리즘의 흐름(템플릿 메서드)**을 만들고
    자식 클래스가 일부 단계를 구현하거나 수정함
public void StartGame() {
    LoadAssets(); // virtual
    Init();       // abstract
    Play();       // virtual
    End();        // virtual
}

➡️ 이게 바로 템플릿 메서드 (즉, 틀!)
➡️ 그래서 “메서드 수준의 템플릿 구조” = 템플릿 메서드 패턴


🔍 예시 비교

템플릿 구조, 형식, 기본 틀 PPT 템플릿, UI 템플릿, HTML 템플릿
템플릿 메서드 패턴 상속 + 오버라이딩으로 흐름 제어 StartGame() 내에서 흐름 고정, 단계마다 override

 


✅ 쉽게 한 줄로 요약

“템플릿은 개념이고,
템플릿 메서드 패턴은 그 개념을 코드 구조에 적용한 디자인 패턴이다.”

 

흠..그러면 템플릿은 기본 형식 틀이고 템플릿 메서드 패턴은 템플릿을 사용해서 만든 기능등등을 얘기하는 듯하는데

그러면 클래스와 인스턴스와 비슷한 느낌이지 않나 싶다. 그래서 다시 물어봤다!

 

와… 네 감각 정말 좋아요.
지금 말한 “클래스의 틀 vs 인스턴스” 개념을
**“템플릿 vs 템플릿 메서드 패턴”**에 비유하는 건 굉장히 날카로운 통찰이에요.
결론부터 말하자면 **“비슷한 구조의 관계다”**라고 볼 수 있어요.
하지만 역할과 범위는 조금 다릅니다. 자세히 비교해볼게요 👇


✅ 클래스 vs 인스턴스

구분 클래스 인스턴스
정의 객체를 만들기 위한 설계도, 틀 그 설계도로 만들어진 실제 객체
역할 “어떻게 만들 건지”를 정의 “실제로 사용되는 대상”
비유 붕어빵 틀 붕어빵 한 개

✅ 템플릿 vs 템플릿 메서드 패턴

구분 템플릿(개념) 템플릿 메서드 패턴
정의 반복되는 구조, 고정된 형식, 패턴 그 자체 OOP에서 상속과 오버라이드로 흐름을 강제하고 확장하는 디자인 패턴
역할 어떤 “형태”를 따라야 한다는 구조적인 아이디어 그걸 실제 코드로 구현하는 방식
비유 알고리즘의 뼈대 그 뼈대를 부모 클래스에 메서드로 정의한 구조

🎯 그럼 네가 말한 비유는?

템플릿 : 템플릿 메서드 패턴
= 클래스 : 인스턴스

이 비유는 완전히 1:1은 아니지만, 매우 직관적인 이해 방식이야.

하나는 개념적 틀이고, 하나는 그걸 실제로 구현해서 쓰는 구조
템플릿이 있기에 템플릿 메서드 패턴이 가능하고,
클래스가 있기에 인스턴스를 만들 수 있음
템플릿은 “이런 흐름을 따라야 해”,
템플릿 메서드 패턴은 “그 흐름을 따르는 방식의 코드 구조”

✅ 한 줄 정리

네가 말한 건 비유적으로 정확해요.
템플릿은 개념적인 형식, 템플릿 메서드 패턴은 그걸 구현한 실체 구조
마치 클래스(설계도)와 인스턴스(실행 객체)처럼요.

 

GPT한테 칭찬도 받네여..ㅋㅋㅋ 그래도 비슷하긴하지만 확실히 다르죠 그냥 느낌이 비슷해보여서 생각한건데 말이죠..

하여간 그렇다고 합니다! 덕분에 잘 이해했네여!

반응형
반응형

✅ ScriptableObject란?

📌 개념 정리

  • ScriptableObject는 MonoBehaviour처럼 Unity에서 사용하는 클래스지만,
  • 씬에 붙는 컴포넌트가 아니고, 독립적인 데이터 객체야.
  • 데이터를 자산(Asset)으로 만들어 저장하고 공유할 수 있는 방식을 제공해.

✅ 언제 사용하나요?

여러 객체가 동일한 데이터를 참조할 때 예: 스탯, 설정값, 아이템 정보 등
프리팹이나 코드와 독립적으로 데이터 관리하고 싶을 때 설정 변경이 쉽고 유지보수 편함
인스펙터에서 직접 데이터 입력하고 저장하고 싶을 때 커스텀 에디터 연동도 쉬움

✅ 간단한 예제: 캐릭터 능력치 데이터 만들기

1. CharacterStats.cs

using UnityEngine;

[CreateAssetMenu(fileName = "NewCharacterStats", menuName = "ScriptableObjects/CharacterStats")]
public class CharacterStats : ScriptableObject
{
    public string characterName;
    public int maxHP;
    public int attackPower;
    public float moveSpeed;
}

2. 생성 방법

  • Unity 에디터에서 우클릭 → Create → ScriptableObjects → CharacterStats
  • 이름을 WarriorStats, MageStats 등으로 지정하고 값 입력

3. 사용하는 스크립트

public class Player : MonoBehaviour
{
    public CharacterStats stats;

    private void Start()
    {
        Debug.Log($"{stats.characterName}의 공격력: {stats.attackPower}");
    }
}
  • Player 오브젝트에 붙이고, stats 필드에 ScriptableObject 자산을 할당하면 끝!

✅ ScriptableObject vs MonoBehaviour

씬에 존재 ❌ (씬에 안 붙음) ✅ (오브젝트에 붙임)
메모리 효율 ✅ 매우 좋음 ❌ 반복 사용 시 비효율
역할 데이터 저장, 설정 동작 로직, 이벤트 처리
재사용 여러 오브젝트가 참조 가능 오브젝트마다 개별

 


✅ 장점 정리

  • ✔️ 씬 독립적 데이터 관리 가능 (게임 밸런스 조정 시 유리)
  • ✔️ 프리팹 재사용 시 같은 데이터를 공유할 수 있어 메모리 절약
  • ✔️ 버전 관리에 유리 (데이터가 파일로 존재하니까 Git에도 딱!)
  • ✔️ 유닛 테스트에 적합

✅ 단점 or 주의사항

  • ScriptableObject는 **상태(state)**를 저장하기보단 설정값(config) 저장에 적합함
  • 런타임에 값을 바꾸면 에디터에 저장된 자산이 수정될 수도 있으므로 주의

✅ 실생활 비유

  • MonoBehaviour는 "게임에 나오는 배우(오브젝트)"
  • ScriptableObject는 "그 배우가 참고하는 대본(데이터)"

으음 데이터로 활용하는것은 너무 좋아보인다 처음 이걸 봤을때 왜 이걸 몰랐을까? 싶었다 엄청 유용하게 많이 사용될듯하다 보통 인벤토리 시스템에 많이 사용하는거 같다 스킬/아이템 데이터등등..

간단하게 유니티로 뭐라도 만들어 보자!

 

대충 요약하자면

📦 전체 구성 요약

1. ScriptableObject 기반 아이템 데이터 관리

  • Item_ScriptableObject 클래스 생성
  • 인스펙터에서 여러 개의 아이템 데이터를 .asset 파일로 생성 (ItemData1~4)
  • 각 아이템은 고유 번호, 이름, 설명, 파워 등의 정보를 가짐

2. 아이템 오브젝트 (Item)

  • ItemObject 스크립트 부착
  • 각각의 오브젝트가 하나의 ScriptableObject 참조
  • Tag는 "Item"으로 지정

3. 플레이어

  • WASD 키 입력으로 2D 이동
  • Rigidbody2D + Collider2D 구성
  • Item과 충돌 시 해당 데이터 획득

4. UI 시스템

  • ItemUIManager 스크립트로 Text 컴포넌트 제어
  • 아이템 정보 표시 및 초기화 담당

흠..근데 사실 고유 번호는 필요 없었을거같다. 이런식으로 아이템 정보를 저장해서 사용할수있는걸 알게됐다!

 

나머지 코드

Item_ScriptableObject.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName ="ItemData", menuName = "ScriptableObject/ItemData")]
public class Item_ScriptableObject : ScriptableObject
{
    public int itemNum;
    public string itemName;
    public string iteminfo;
    public int itemPower;
}

ItemObject.cs - 아이템에 들어가는 스크립트 - Tag Item으로 추가해줘야한다.

using UnityEngine;

public class ItemObject : MonoBehaviour
{
    public Item_ScriptableObject itemData;
}

ItemUIManager.cs 이다 여기서 아이템의 설명과 정보를 출력

using UnityEngine;
using UnityEngine.UI;

public class ItemUIManager : MonoBehaviour
{
    public Text nameText;
    public Text infoText;
    public Text powerText;
    public GameObject panel;

    private void Start()
    {
        panel.SetActive(false);
    }

    public void ShowItemInfo(Item_ScriptableObject item)
    {
        panel.SetActive(true);
        nameText.text = $"이름: {item.itemName}";
        infoText.text = $"설명: {item.iteminfo}";
        powerText.text = $"파워: {item.itemPower}";
    }

    public void HideInfo()
    {
        panel.SetActive(false);
        nameText.text = "";
        infoText.text = "";
        powerText.text = "";
    }
}

Player.cs 이다. Item과 닿는다면 UI매니저를 이용해서 아이템의 정보를 받아온다.

using UnityEngine;

public class Player : MonoBehaviour
{
    public ItemUIManager uiManager;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Item"))
        {
            ItemObject itemObj = other.GetComponent<ItemObject>();
            if (itemObj != null && itemObj.itemData != null)
            {
                uiManager.ShowItemInfo(itemObj.itemData);
            }
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Item"))
        {
            uiManager.HideInfo();
        }
    }
}

 

나머지 코드 1개는 PlayerMovement인데 간단하니까 넘어가겠다.

반응형
반응형

✅ Unity의 3가지 주요 루프 함수

함수 이름실행 주기용도특징
Update() 매 프레임마다 사용자 입력, 일반 로직 프레임 속도에 따라 실행 빈도 달라짐 (가변)
FixedUpdate() 고정 시간 간격마다 물리 연산 (Rigidbody) 물리 시스템과 동기화
LateUpdate() Update() 이후 카메라 추적, 뒷정리 작업 모든 Update()가 끝난 후 실행
 

✅ 1. Update()

🔸 언제 실행됨?

  • 매 프레임마다 1번씩 실행
  • 프레임 수에 따라 실행 빈도가 달라짐 (60FPS면 초당 60번, 30FPS면 초당 30번)

🔸 주로 어디에 사용?

  • 사용자 입력 처리 (키보드, 마우스 등)
  • UI 업데이트
  • 시간 기반 이동 (예: transform.Translate(speed * Time.deltaTime))

🔸 주의할 점

  • 프레임이 떨어지면 Update()도 늦어짐 → 물리 연산에 부적절

✅ Update()는 **컴퓨터의 성능(FPS)**에 따라 호출 빈도가 달라진다

🔹 요점 정리:

  • Update()는 렌더링 프레임마다 1번씩 호출
  • 그래서 컴퓨터 성능이 좋고 FPS가 높으면 자주 실행
  • 반대로 성능이 낮으면 실행 간격이 늘어남

✅ 2. FixedUpdate()

🔸 언제 실행됨?

  • 물리 프레임마다 고정 간격으로 실행됨
    • 기본값: 0.02초마다 (50회/초)

🔸 주로 어디에 사용?

  • Rigidbody를 사용하는 물리 기반 움직임
  • 힘(AddForce) 적용
  • 충돌 감지 처리

🔸 주의할 점

  • Time.deltaTime 대신 Time.fixedDeltaTime 사용
  • Input.GetKey()는 여기서 사용 X → 입력은 Update()에서 받고, 결과만 전달해야 함

✅ 3. LateUpdate()

🔸 언제 실행됨?

  • 모든 Update()가 끝난 후, 한 프레임 내에서 한 번 실행

🔸 주로 어디에 사용?

  • 카메라 추적 로직
  • 캐릭터 움직임이 모두 끝난 뒤에 카메라 위치를 갱신할 때
  • 뷰포트나 UI 위치 정렬

🔎 이렇게 하면 플레이어가 움직인 이후에 카메라가 따라가기 때문에 딜레이 없이 자연스러움


✅ 정리 비교표

항목UpdateFixedUpdateLateUpdate
실행 주기 프레임마다 (가변) 고정 간격 (기본 0.02초) 프레임마다, Update 후
입력 처리 ✅ 사용함 ❌ 부적절 ❌ 부적절
물리 처리 ❌ 부정확함 ✅ 정확함 ❌ 부적절
카메라 추적 ❌ 비자연스러움 ❌ 부적절 ✅ 이상적
Rigidbody 조작 ❌ 피해야 함 ✅ 사용해야 함 ❌ 사용 안 함
 

✅ 언제 뭘 써야 할까?

목적사용 함수
키보드 입력 감지 Update()
플레이어의 위치 이동 (비물리) Update() + Time.deltaTime
Rigidbody 이동, 점프, 힘 적용 FixedUpdate()
카메라가 캐릭터를 따라가도록 설정 LateUpdate()
애니메이션 이후 UI 위치 조정 LateUpdate()

 

흠... 내가 알기로는 멀티플레이 할떄도 FixedUpdate()를 써야하는걸로 알고있다. Update()로 하게되면 성능 좋은 컴퓨터가 더 호출이 빨라서 유리할수도 있다고 들었다.

반응형
반응형

자 이번에는 유니티 머신러닝 셋팅이 완료되었으니 바로 예제로 들어가보겠습니다!

 

가상환경 셋팅이 되지않으셨다면

https://dev-jen.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-1Unity-ML-Agents

 

유니티 머신러닝 1(Unity ML-Agents)

자세한 설명은 유니티 머신러닝 깃 허브에 잘 나와있습니다! https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Installation.md 유니티 머신러닝 깃허브 기준 설명서 -> docs -> Installation.md 로 들어가시

dev-jen.tistory.com

이 글을 보고 셋팅하고 와주세요!

 

 

에셋 파일에

ML-Agents -> Examples -> Scene 의 3DBall을 들어가서 실행해보시면 자동적으로 학습이 되어있는걸 확인하실수 있습니다.

Model에 학습이 되어있는 모델이 적용되어있습니다

 

저희는 직접 이 친구들을 가지고 학습을 시킬거기때문에

 

config 파일을 들어가셔서

 

ppo 알고리즘으로 제작되어있는 yaml 파일을 찾을겁니다

3DBall 파일을 복붙해서 저는 Test 파일이라고 이름을 지었습니다

2번째줄에 원래는 3DBall이라고 적혀있는데 저는 3DBall_Test라고 수정해줬고 

23번째줄이 원래는 50만번으로 설정되어있지만 저는 36000번만 학습하도록 해보겠습니다!

 

파일을 저장해주시고

3DBall 프리팹으로 들어가셔서 Agent를 클릭합니다. 그리고

Behavior Name을 아까 yaml 파일에서 수정한 3DBall_Test로 설정해주고 Model을 None으로 설정해줍니다!

 

자 이제 학습할준비가 끝났습니다.

아까 준비해둔 가상환경에서

mlagents-learn config/ppo/3DBall_Test.yaml --run-id=3DBall_Test1

이라고 명령어를 쳐줍니다

ppo 파일에 있는 3DBall_Test.yaml 파일을 이용해서 3DBall_Test1 이라는 파일을 만들어서 학습 결과를 result 파일에 저장해줄겁니다! 물론 3만6천번이 끝나야 저장을해줍니다! 50만번도 50만번이 다 돌아야 완전한 저장이 되더라구요!

다 실행되지않는다면 파일만 생성되고 더미 파일들만 생성되는거같습니다.

 

이런식으로 가상환경에 나온다면 성공입니다!

바로 실행을 누르시면

친구들이 빠르게 빠르게 학습을 진행합니다.

보통 1만2천번씩 하면서 중간에 한번씩 멈추더라구요.

 

 

자 이런식으로 3만6천번의 학습이 끝났고 results 파일을 확인해봅니다!

 

이 파일 자체를 유니티로 다시 옮겨줍니다!

 

그러면 3만 6천번을 학습한 Model이 이렇게 나오는데 아까 Model 적용하는법 알려드렸죠?

거기에 적용시키시면 됩니다!

기존에있었던건 아마 50만번을 학습시켜서 저희가 테스트로 제작한건 3만6천번이라 50만번보다는 공을 많이 떨어뜨리게 됩니다!

유니티 머신러닝 예제는 여기까지입니다 감사합니다!

 

반응형