Unity 19일차 - Unity 개인 프로젝트

한예준·2025년 5월 1일

오늘은 강의를 조금 복습해보고, 유니티로 개인 프로젝트를 진행했다. 진행 중 구현했던 몇 가지 주요 기능들과 문제들을 몇 가지 정리하고자 한다.


개인 프로젝트 진행

NPC 상호작용

  • MainScene에서 NPC와 상호작용 하기 위해 NPC에게 가까이 갔을 때 충돌 처리를 하는, Box Collider 2D 컴포넌트를 붙여주었다.
  • 기본적인 Collider 범위보다 조금 더 넓게, 그리고 isTrigger를 활성화시켜서 범위 안에 들어갔을 때에 상호작용 할 수 있도록 만들었다.
  • 하지만 그랬더니 플레이어 캐릭터가 NPC를 통과하는 문제가 발생했다.
  • 디테일을 챙기기 위해 플레이어 캐릭터가 NPC를 통과하지 못하도록 수정해주었다. 수정 내용은 다음과 같다.
    • NPC에 역할이 다른 두 개의 Collider 사용.
    • 상호작용 트리거: IsTrigger = true. 물리적 충돌을 담당한다.
      플레이어의 접근을 감지한다. OnTriggerEnter2D를 활용하였다.
  • 이후 실행해보니 의도한대로 구현되었음을 확인하였다.

NPC 가상 메서드 활용

  • 각 NPC가 서로 비슷한 역할을 하는데, 단일 스크립트로 구현 시 확장성을 확보할 수 없었다.
  • 따라서 상속 개념을 활용하기로 했다.
    • 부모 클래스: BaseNPCController
public class BaseNPCController : MonoBehaviour
{
    protected bool isPlayerInRange = false;
.
.
.
    protected virtual void OnTriggerEnter2D(Collider2D collider2D)
    {
        if (collider2D.CompareTag("Player"))
        {
            isPlayerInRange = true;
            Debug.Log("플레이어 접근");
        }
    }
.
.
.
    public virtual void Interact()
    {
        Debug.Log("NPC와 상호작용");
    }
}
  • 자식 클래스: ElfNPC, DwalfNPC
//ElfNPC 예시
public class ElfNPC : BaseNPCController
{
    public override void Interact()
    {
        Debug.Log("엘프 NPC와 상호작용했습니다.");
    }
}

이를 통해 다양한 NPC들을 손쉽게 추가할 수 있었다.


프로젝트 관리

  • 에셋이 증가함에 따라 효율적인 프로젝트의 관리의 필요성을 느끼게 되었다.
  • 따라서 씬별/기능별로 스크립트 및 애니메이션 등을 분리하였다.
    • 예를 들어, MainScene의 ElfNPC 스크립트는 Scripts/MainScene/NPC/ElfNPC.cs와 같은 식으로 스크립트를 구성하였고 애니메이션도 마찬가지로 구성하였다.

[SerializeField] vs public ?

  • 유니티 에디터에서 스크립트에서 할당한 변수를 Inspector 창에 노출시켜 손쉽게 수정하는 두가지 방법이다.
  • 하지만 public은 해당 변수를 어떤 다른 스크립트에서도 접근할 수 있기 때문에 예상치 못한 버그가 발생할 수 있다.
  • 반면 [SerializeField]를 활용하면 변수 접근은 제한하면서 Inspector 창에 노출은 가능하다.
  • 따라서 다른 스크립트에서 해당 변수에 직접 접근해야 하는 경우에는 public을 사용하고, 그렇지 않은 경우에는 [SerializeField]를 활용하는 것이 좋겠다.

PlayerPrefs 활용

  • 게임을 종료하거나 재시작해도 최고 점수와 같은 간단한 데이터를 저장하고 불러오는 역할을 한다.
  • PlayerPrefs는 유니티에서 제공하는 가장 간단한 데이터 저장 방식이다.
  • int, float, string 타입의 데이터를 저장하고 불러올 수 있다.
  • 구현 예시
//F_GameManager.cs
public class F_GameManager : MonoBehaviour
{
	.
	.
	.
    private void Awake()
    {
	.
	.
	.
        bestScore = PlayerPrefs.GetInt(BestScoreKey, 0);
	.
    .
    .
    public void CheckBestScore()
    {
        if (currentScore > bestScore)
        {
            bestScore = currentScore;
            PlayerPrefs.SetInt(BestScoreKey, bestScore);
	.
    .
    .
  • 하지만 PlayerPrefs는 보안에 취약하다는 약점이 있다. 데이터가 암호화되지 않기 때문이다.
  • 또한 복잡한 데이터 구조를 저장하기에 불편하다.
  • 따라서 간단한 설정값, 최고 점수, 레벨 잠금 해제 여부 등 가벼운 데이터를 저장하는 데에 유용하게 사용할 수 있다.

회고 및 느낀점

  • 오늘 기능 구현을 하며 C# TRPG 팀프로젝트 할 때의 경험이 많은 도움이 되었다.
  • 먼저 GitHub의 Branch 기능을 통해 기능별로 혹은 씬별로 Branch를 나눠가며 작업을 했는데, 이를 통해 크게 오류가 났던 것을 다행히도 복구할 수 있었다.
  • 또한 팀프로젝트를 하며 익혔던 개발 구조를 조금이나마 활용해 볼 수 있었다.
  • 특히 가상 메서드를 이용한 방식은 현재 진행한 NPC오브젝트 뿐만 아니라, 여러 적 몬스터나 투사체, 무기 등을 만들 때에도 효과적으로 사용할 수 있겠다.
  • 또한 프로젝트 폴더를 팀프로젝트할 때처럼 일정한 구조를 가지고 관리하니 프로젝트 가독성이 올라갔다.
  • 지금 당장은 크게 눈에 보이지 않더라도 프로젝트 규모가 커지면 커질수록 이렇게 관리하는 습관이 중요할 것이라 생각한다.
  • 또한 [SerializeField], PlayerPrefs등의 용도를 제대로 알고 나니 사용하게 훨씬 편리했다.
  • 사실 이전까지는 '어떤 구조로 프로젝트를 진행할지'에 대한 설계를 해도, 그 설계를 채워나갈만한 도구가 부족했는데, 이렇게 실습을 진행하며 도구를 하나하나 얻어가는 느낌이다.

0개의 댓글