01
18

과정명 : 내일배움캠프 Unity 게임개발 3기

전체진행도 : 19일차

부분진행도 : Chapter3 - 1일차

작성일자 : 2024.01.18(목)

개발일지 목록 : 클릭


1. 진행중인 과정에 대해

글자 서식을 정돈하기 위해, 티스토리의 글 작성법을 마크다운 위주로 바꾸었다. 특히 외부에서 마크다운 형식의 컨텐츠를 가져올 때 그대로 가져오기 위해서는 마크다운 모드를 쓰지 않으면 안되기 때문.

기본모드/마크다운/HTML 모드를 오가는 도중에 손실되는 정보가 상당하기 때문에(특히 마크다운으로 전환 시, 이미지 속성등이 모두 사라지는 등, 마크다운에서 지원하지 않는 작성법은 모두 손실된다) 개발자로서 가장 필요로 하는 마크다운을 메인으로 하고, 필요 시 기본모드로 넘어가 추가적인 편집을 할 생각이다.

새로운 6시간정도 분량의 새로운 유니티 입문 강의를 지급받아, 4일 간 강의를 보며 공부하고 개인과제를 하는 주차이다. 오늘 셔플한 새로운 조는 이전 조에 비해 많이 조용한듯.

오후 3시정도까지는 너무 피곤하여 졸다 깨다를 반복하다가 이후에서야 강의를 확인하며 학습했다. 강의 난이도가 생각보다 높은 것을 보고 당황하였다. 저녁을 먹고 와서도 다들 조용히 자기 할 일 하는 중. 일단 강의를 두시간 분량(약 1/3정도?) 듣기는 했는데, 학습과 과제까지 하는 시간이 4일밖에 주어지지 않아 시간이 많이 빡빡한 편이다.

이제 보니, 오늘은 강의를 수강하고 나머지 시간은 개인과제를 하도록 캠프 Docs에 적혀있다. 오늘 발제 세션이 끝난 뒤의 실 학습 가능한 시간이 식사시간과 일지 작성하는 시간 제외하고 6시간정도 였을텐데, 6시간의 강의를 이 시간에 소화하라는 것은 상당히 무리가 있지 않나 생각했다.

2. 오늘 학습에 대해

Input 요소의 설정 변경

아래와 같은 키입력을 유니티 스크립트에서 사용 할 수 있는데

float x = Input.GetAxis("Horizontal");

Edit - Project Settings - Input Manager 에서 Horizontal, MouseX 등의 이름 변경이나 상세설정 등을 할 수 있다.

GetAxis와 GetAxisRaw

Input.GetAxis("Horizontal") 와는 달리 Input.GetAxisRaw("Horizontal") 는 스무스한 변화(-1 ~ 0 ~ 1) 없이 입력 순간부터 등속(-1,0,1)으로 움직이게 한다.

*C# 문법, ?.

OnMoveEvent?.Invoke(direction); 와 같이 ?. 을 사용하면, OnMoveEventNull이 아닐 경우, Invoke(direction)을 실행한다.

유니티 라이센스 오류 해결

수강을 위해 유니티 버전을 2022.3.2f로 낮춘 후, 패키지 관리자를 사용하려고 보니 라이센스 이슈가 있었다.

라이센스 문제로 보여, 유니티 허브에서 라이센스 관리 메뉴로 이동.

이처럼 Refresh 버튼을 누르면 라이센스의 갱신을 할 수 없다는 내용이 나온다.

유니티 라이센스 Data 삭제 : 해당 스레드에서 유니티 데이터폴더를 지운 후 해결되었다는 덧글들이 많아 해보았지만 해결되지 않았다.

라이센스 정보가 사라진 것은 덤.

최하단 댓글 중 Unity Hub의 로그인을 다시 해서 해결되어다는 내용을 보고, 재로그인을 해 보았더니 해결되었다.

라이센스 시작일이 꽤 오래전이라 뭔가 아깝다는 생각이 들어 복원방법을 찾아보다가 포기한 후, 새로 무료 라이센스를 얻기를 하였는데, 다행히 시작일이 예전에 쓰던 라이센스와 동일했다.

라이센스 문제가 해결되어, 유니티에서의 패키지 관리자도 정상적으로 작동하였다.

유니티 상태 현황판

라이센스 문제를 해결하며 얻은 정보. 유니티 운영측의 상태를 표시해주는 서비스이다.

유니티 상태 현황판

Input System

유저 입력에 대해 전체적으로 관리해주는 에셋.

패키지 매니저에서 Input System을 설치하여 사용한다.

Project 탭에서 우클릭 - CreateInput Actions를 생성해준 뒤, 더블클릭하여 열어준 후 새로운 스키마를 생성한다.

생성한 스키마 예)Keyboard&Mouse 가 선택된 것을 확인 후, Action Maps에 새로운 항목을 추가한 후, 여러 입력과 그 입력에 대한 행동을 아래와 같이 작성한다.

그리고, 이를 사용할 스크립트들도 만들어준다.

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

public class PlayerInputController : TopDownCharacterController
{
    private Camera _camera;
    private void Awake()
    {
         _camera = Camera.main;
    }
    public void OnMove(InputValue value)
    {
        Debug.Log("OnMove"+value.ToString());
    }
    public void OnLook(InputValue value)
    {
        Debug.Log("OnLook" + value.ToString());
    }
    public void OnFire(InputValue value)
    {
        Debug.Log("OnFire" + value.ToString());
    }
}

Player오브젝트에 위 스크립트 컴포넌트를 추가.
Player Input이라는 컴포넌트도 검색해 추가하며, Player InputActions 속성에 위에서 만들어둔 Input Action 도 추가한다.

Behavior의 밑 내용을 보면, OnMove, OnLook, OnFire 등의 메서드가 스크립트 내에 있다면, 이벤트에 이 메서드들이 반응하도록 해 준다는 내용이라는 듯.

해당 내용과 관련하여 너무 이해가 안되어 ChatGPT에게 여러번 질문하여 구조를 이해하였다.

Player Input은 위에서 미리 매핑해둔 듯이(wasd는 Move), 'w'의 입력을 받으면 Send Messages 동작을 시도하는데, Player 오브젝트 내에 추가된 !!!모든 컴포넌트!!!를 뒤적이며 OnMove 메서드를 찾아 실행시킨다.

PlayerInputController 내에 존재하는 OnMove 메서드를 도대체 어떻게 실행시키는지 연결점을 도무지 찾지 못했는데, 위와 같은 한 문장을 이해하고 나니 모든 의문점이 해결되었다.

이어서 OnMove 메서드는 CallMoveEvent를 실행시키고

CallMoveEvent는 미리 준비된 목록에 존재하는 메서드들을 모두 수행한다.

이처럼 특정 이벤트가 발생하면 해당 이벤트를 필요로하는 모든 기능에 이벤트가 발생했다는 것을 알려주는 것을 옵저버 또는 구독 시스템 이라고 한다는 듯 하다.

관련 QA 내용은 하단 GPT 문답에 적어두었다.

스크립트 생성 시 내용 설정

스크립트를 생성하면 주석과 함께 Start와 Update메서드가 적혀있는데, 이렇게 기본적으로 보이는 내용을 편집하는 방법이라고 한다.

유니티 아이콘 우클릭 - 파일 위치 열기 - Data(폴더) - Resources(폴더) - ScriptTemplates(폴더) - 81-C# Script-NewBehaviourScript.cs

해당 클래스의 내용을 수정한다.

3. 과제에 대해

  • 강의 나머지 2/3분량 마치기
  • 개인 과제 진행하기

4. 참고자료

5. GPT4 문답

유니티 프로젝트 이름 작명법

[You]

유니티 프로젝트 이름을 정하고 있는데, 보통의 경우 여러 단어로 이루어진 이름을 지을 때 대소문자 등 작명 규칙을 어떻게 사용하니?

[ChatGPT]

Unity 프로젝트의 이름을 정할 때, 일반적으로 "카멜 케이스(CamelCase)" 또는 "파스칼 케이스(PascalCase)"와 같은 작명 규칙을 사용합니다. 이러한 규칙은 여러 단어를 결합할 때 각 단어의 시작을 대문자로 표시하여 단어 간의 구분을 명확하게 합니다. 다음은 두 가지 주요 작명 스타일에 대한 설명입니다:

  1. 카멜 케이스 (CamelCase): 이 방식에서는 첫 단어를 소문자로 시작하고 이후의 각 단어는 대문자로 시작합니다. 예를 들어, myUnityProject와 같이 사용됩니다. 카멜 케이스는 주로 변수나 함수 이름에 사용됩니다.
  2. 파스칼 케이스 (PascalCase): 이 방식에서는 모든 단어를 대문자로 시작합니다. 예를 들어, MyUnityProject와 같이 사용됩니다. 파스칼 케이스는 클래스 이름, 네임스페이스, 프로젝트 이름 등에 자주 사용됩니다.

프로젝트 이름을 지을 때는 일반적으로 파스칼 케이스를 사용하는 것이 좋습니다. 이는 프로젝트 이름이 종종 클래스나 네임스페이스와 유사한 형태로 사용되기 때문입니다. 또한, 프로젝트 이름은 의미를 명확하게 전달할 수 있도록 간결하고 기억하기 쉬운 이름을 선택하는 것이 좋습니다.

예시:

  • SpaceAdventureGame
  • VirtualRealitySimulator
  • MobilePuzzleGame

이러한 규칙은 프로젝트를 더욱 조직적이고 일관된 방식으로 관리하는 데 도움이 됩니다. 프로젝트 이름을 결정할 때는 프로젝트의 내용과 목적을 잘 나타낼 수 있는 이름을 선택하는 것이 중요합니다.


Input System 에 대해

[You]

현재 Player에 다음 스크립트 컴포넌트가 추가되어 있어.

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

public class PlayerInputController : TopDownCharacterController
{
    private Camera _camera;
    private void Awake()
    {
         _camera = Camera.main;
    }
    public void OnMove(InputValue value)
    {
        Vector2 moveInput = value.Get<Vector2>().normalized;
        CallMoveEvent(moveInput);
    }
    public void OnLook(InputValue value)
    {
        Vector2 newAim = value.Get<Vector2>();
        Vector2 worldPos = _camera.ScreenToWorldPoint(newAim);
        newAim = (worldPos - (Vector2)transform.position).normalized;
        if (newAim.magnitude >= .9f)
        {
            CallLookEvent(newAim);
        }

    }
    public void OnFire(InputValue value)
    {
        Debug.Log("OnFire" + value.ToString());
    }
}

그리고 Player에는 Player Input이라는 컴포넌트도 추가되어있는데, Actions 속성에 TopDownController2D 라는 InputAction 을 넣어놓은 상태야.

Behavior은 Send Messages로 설정되어있고, 아래 적혀있는 설명을 보면
Will SendMessage() to GameObject: OnDeviceLost, OnDeviceRegained, OnControlsChanged, OnMove, OnLook, OnFire
라고 적혀있어.

PlayerInputController라는 스크립트에 존재하는 OnLook, OnMove, OnFire 라는 메서드를 어떤 식으로 실행시키는지 연결고리가 어떻게 되어있는지 도무지 이해가 되지 않아.

다른 스크립트도 참고삼아 적어둘게.

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

public class TopDownCharacterController : MonoBehaviour
{
    public event Action<Vector2> OnMoveEvent;
    public event Action<Vector2> OnLookEvent;

    public void CallMoveEvent(Vector2 direction)
    {
        OnMoveEvent?.Invoke(direction);
    }
    public void CallLookEvent(Vector2 direction)
    {
        OnLookEvent?.Invoke(direction);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TopDownMovement : MonoBehaviour
{
    private TopDownCharacterController _controller;
    private Rigidbody2D _rigidbody;
    private Vector2 _movementDirection = Vector2.zero;

    private void Awake()
    {
        _controller = GetComponent<TopDownCharacterController>();
        _rigidbody = GetComponent<Rigidbody2D>();
    }
    private void Start()
    {
        _controller.OnMoveEvent += Move; // 메서드를... OnMoveEvent에 추가하네
    }
    private void Move(Vector2 direction)
    {
        _movementDirection = direction;
    }
}

[ChatGPT]

Unity의 PlayerInput 컴포넌트와 관련된 스크립트들이 어떻게 연결되어 있는지 궁금해하시는군요. Unity의 입력 시스템, 특히 PlayerInput 컴포넌트는 약간 복잡할 수 있지만, 기본적으로 이해하면 간단합니다. 각 부분을 단계별로 살펴보겠습니다.

PlayerInput 컴포넌트

PlayerInput 컴포넌트는 Unity의 새로운 입력 시스템의 핵심입니다. 이 컴포넌트는 입력을 처리하고, 입력에 대응하는 이벤트를 발생시킵니다. 여기서 중요한 것은 Behavior 설정입니다. "Send Messages" 옵션은 PlayerInput 컴포넌트가 입력 이벤트를 감지할 때, 이벤트에 해당하는 이름의 메서드를 해당 게임 오브젝트의 스크립트에서 호출하도록 합니다.

PlayerInputController 스크립트

이 스크립트에는 OnMove, OnLook, OnFire라는 메서드들이 정의되어 있습니다. 이 메서드들은 PlayerInput 컴포넌트에 의해 호출됩니다. 예를 들어, 사용자가 이동 키를 누르면 PlayerInput 컴포넌트는 OnMove 메서드를 호출합니다.

OnMove 메서드는 입력 값을 받아서 이를 CallMoveEvent 메서드에 전달합니다. 이렇게 하면 TopDownCharacterController 클래스에 정의된 OnMoveEvent 이벤트가 발생합니다.

TopDownCharacterController 스크립트

이 스크립트는 OnMoveEventOnLookEvent라는 이벤트를 정의합니다. 다른 스크립트는 이 이벤트에 메서드를 등록할 수 있고, 이벤트가 발생하면 등록된 메서드가 호출됩니다.

TopDownMovement 스크립트

이 스크립트는 TopDownCharacterControllerOnMoveEventMove 메서드를 등록합니다. 그래서 PlayerInputController에서 OnMove 메서드를 호출하여 OnMoveEvent 이벤트를 발생시킬 때, TopDownMovementMove 메서드가 호출됩니다.

연결 고리

요약하면, 사용자의 입력은 PlayerInput 컴포넌트에 의해 감지되고, PlayerInputController 스크립트의 메서드를 호출합니다. 이 메서드들은 TopDownCharacterController의 이벤트를 발생시키고, 다른 스크립트에서 이 이벤트에 등록된 메서드들이 호출됩니다. 이 과정을 통해 입력이 실제 게임 내 행동으로 변환됩니다.

[You]

사용자의 입력은 PlayerInput 컴포넌트에 의해 감지되고, PlayerInputController 스크립트의 메서드를 호출합니다.
라고 적혀있는데, PlayerInputController 가 해당 오브젝트의 컴포넌트로 추가되어있다는것 만으로, PlayerInputPlayerInputController의 안에있는 OnMove 등의 메서드에 바로 접근하는거야?

[ChatGPT]

네, 맞습니다. Unity의 새로운 입력 시스템에서 PlayerInput 컴포넌트는 입력과 관련된 이벤트를 감지하고, 이를 스크립트에 연결된 메서드로 전달합니다. 이 연결은 PlayerInput 컴포넌트의 설정과 스크립트에 정의된 메서드 이름에 의해 이루어집니다.

PlayerInput 컴포넌트는 "Behavior" 설정을 "Send Messages"로 설정했을 때, 다음과 같이 작동합니다:

  1. 감지된 입력에 대응하는 메서드 이름 확인: 예를 들어, PlayerInput 컴포넌트의 "Actions" 설정에 "Move"라는 액션이 정의되어 있고, 사용자가 이동 입력을 하면, PlayerInput 컴포넌트는 "OnMove"라는 이름의 메서드를 찾습니다.
  2. 메서드 호출: 만약 PlayerInput 컴포넌트가 추가된 게임 오브젝트에 PlayerInputController 스크립트가 있고, 그 안에 "OnMove"라는 메서드가 정의되어 있다면, PlayerInput 컴포넌트는 이 메서드를 자동으로 호출합니다.

이 과정은 PlayerInput 컴포넌트가 스크립트의 메서드 이름을 기반으로 자동으로 연결을 수행한다는 점에서 중요합니다. 따라서, PlayerInput 컴포넌트의 액션 이름과 스크립트의 메서드 이름이 일치해야 올바른 연결이 이루어집니다. 예를 들어, "Move" 액션이 있으면, 스크립트 내에 "OnMove"라는 메서드가 정의되어 있어야 합니다.

[You]

즉, PlayerInput은 게임 오브젝트 내의 모든 컴포넌트를 뒤적여서 OnMove 메서드를 찾는다는거지? 아니면 PlayerInputController라는 이름을 가진 컴포넌트 내만 탐색한다던가?

[ChatGPT]

Unity의 PlayerInput 컴포넌트는 "Send Messages" 동작 모드를 사용할 때, 해당 게임 오브젝트에 부착된 모든 컴포넌트를 대상으로 메서드를 탐색합니다. 즉, PlayerInput 컴포넌트는 특정한 스크립트 이름(예: PlayerInputController)을 찾는 것이 아니라, 게임 오브젝트에 부착된 모든 컴포넌트 안에서 해당 이벤트와 일치하는 메서드 이름(예: OnMove)을 찾습니다.

이 과정은 다음과 같습니다:

  1. 입력 이벤트 감지: 사용자의 입력이 PlayerInput에 의해 감지됩니다.
  2. 메서드 탐색: PlayerInput 컴포넌트는 해당 게임 오브젝트에 부착된 모든 컴포넌트를 검사하여, 입력 이벤트와 일치하는 메서드 이름을 찾습니다. 예를 들어, 이동 입력에 대해서는 OnMove라는 메서드를 찾습니다.
  3. 메서드 실행: 일치하는 메서드가 발견되면, PlayerInput 컴포넌트는 그 메서드를 호출합니다.

따라서, PlayerInputController라는 특정한 이름의 스크립트를 찾는 것이 아니라, 입력 이벤트에 대응하는 메서드를 게임 오브젝트에 부착된 모든 컴포넌트에서 찾아 호출합니다. 이렇게 하면, 여러 스크립트가 같은 게임 오브젝트에 존재하더라도 각각의 스크립트에서 필요한 입력 처리를 할 수 있습니다.


반응형
COMMENT