[TIL] 27일 차 - Unity 숙련주차 강의 정리 (2)

ChangBeom·2025년 3월 5일

TIL

목록 보기
28/53
post-thumbnail

[1. 인터페이스 (Interface)]

이전에도 인터페이스에 대해 정리한 적이 있지만 인터페이스는 매우 중요하므로 복습 겸 다시한번 정리해보려고 한다.


인터페이스는 클래스의 다중 상속이 허용되지 않는 C#에서 매우 중요한 요소이다. 왜냐하면 인터페이스는 다중 상속이 가능하기 때문이다.

<인터페이스란?>

추상 클래스보다 높은 수준의 추상 멤버로만 구성된 클래스를 뜻한다. 그래서 인터페이스는 모든 멤버들이 abstract의 속성을 가지게 되며, public으로 간주된다.

간단하게 설명하면 인터페이스는 상속받을 클래스에게 틀을 제시한다고 생각하면된다.

인터페이스를 통해 클래스들은 공통적인 동작을 정의하고, 이러한 동작들을 구현하는 클래스들은 해당 인터페이스를 구현함으로써 공통 규약을 준수할 수 있다.

인터페이스의 주요 특징은 다음과 같다.

  • 추상화 : 인터페이스는 추상적인 개념으로, 실제로 구현된 메서드가 없고, 메서드의 시그니처만을 가진다. 따라서 인터페이스는 인스턴스화될 수 없으며, 구현체가 필요하다.
  • 메서드 시그니처 : 인터페이스는 구현 클래스가 반드시 구현해야하는 메서드들의 시그니처를 정의한다. 메서드의 이름, 매개변수, 반환 타입이 포함된다.
  • 다중 상속 가능 : 클래스는 하나의 클래스만 상속받을 수 있지만, 여러 인터페이스를 동시에 구현할 수 있다. 이를 통해 다중 상속을 흉내내는 것이 가능하다.
  • 강제적 구현 : 클래스가 인터페이스를 구현하면, 인터페이스에서 정의한 모든 메서드를 반드시 구현해야 한다. 이로 인해 클래스는 인터페이스에 정의된 동작을 강제로 구현하게 된다.
  • 인터페이스 간 확장 : 인터페이스는 다른 인터페이스를 확장할 수 있다. 이를 통해 더 큰 범위의 공통 동작을 정의할 수 있다.

이러한 특징들을 보면 알 수 있듯이 인터페이스를 사용하는 이유는 코드의 결합도를 낮추기 위함이다.

코드의 결합도가 높으면 클래스 간 의존도가 높다는 뜻이고, 이는 코드의 유연성이 떨어진다는 의미이다. 따라서 구체적 구현 클래스보다 작은 단위의 여러 인터페이스를 사용해서 다중 상속 받으면 코드의 결합도를 낮출 수 있다.

게다가 협업의 관점에서 봤을 때 다음과 같은 장점이 존재한다.

  • 개발 기간 단축 : 인터페이스라는 구현되지 않은 틀만 작성하면 구현 클래스에서 코드 작성 및 개발 가능
  • 표준화 가능 : 여러명의 개발자가 작업해도 정형화된 작업이 가능
  • 독립적인 프로그래밍이 가능 : 선언은 인터페이스에서 구현은 클래스에서

[2. 스크립터블 오브젝트 (ScriptableObject)]

스크립터블 오브젝트는 클래스 인스턴스와는 별도로 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너이다. 스크립터블 오브젝트를 사용하면 값의 사본이 생성되는 것을 방지하여 프로젝트의 메모리 사용을 줄일 수 있다.

이와 같은 특징을 활용하여 다음과 같은 경우에 활용된다.

  • 데이터 컨테이너로 데이터 공유에 사용할 수 있고, 이를 통해 메모리 사용량을 줄일 수 있다.
    • 기존 시스템은 하나의 컴포넌트에 변수를 정의하면 프리팹을 인스턴싱해서 만드는 만큼 메모리 할당이 발생한다.
    • 스크립터블 오브젝트는 데이터를 참조 형태로 오브젝트에서 가져올 수 있게 함으로써 메모리 할당을 최소화하고 고유한 값을 가질 수 있게 한다.
  • 프리팹에서 변화가 없는 동일한 데이터를 사용하는 경우, 스크립터블 오브젝트로 해당 데이터를 관리하면 편리성과 최적화 효과를 얻을 수 있다.

<예시> : 스크립터블 오브젝트를 사용한 아이템

[CreateAssetMenu(fileName = "Item", menuName =  "New Item")]
public class ItemData : ScriptableObject
{
    [Header("Info")]
    public string displayName;
    public string description;
    public ItemType type;
    public Sprite icon;
    public GameObject dropPrefab;

    [Header("Stacking")]
    public bool canStack;
    public int maxStackAmount;

    [Header("Consumable")]
    public ItemDataConsumable[] consumalbes;

    [Header("Equip")]
    public GameObject equipPrefab;
}

위와 같이 ScriptableObject를 상속받으면 스크립터블 오브젝트를 만들수 있다.

  • CreatAssetMenu를 통해 Hierarchy 우클릭 -> Create -> New Item으로 생성할 수 있다.


[3. AI 네비게이션]

AI 네이게이션은 인공지능이 게임이나 시뮬레이션 등 가상 환경에서 이동하는 방법을 결정하는 기술이다. 주로 3D 게임에서 캐릭터나 NPC가 지능적으로 이동하도록 만들어진다. 이를 위해 AI 네비게이션 시스템은 지형, 장애물, 목표 지점 등을 고려하여 적절한 경로를 생성하고 이동하는데 사용된다.

AI 네비게이션을 구현하는 주요 기술과 개념을 하나씩 알아보자.

  • Navigation Mesh (네비게이션 매쉬)
    • 3D 공간을 그리드로 나누어 이동 가능한 지역과 장애물이 있는 지역을 구분하는 매쉬이다.
    • 캐릭터가 이동할 수 있는 영역과 이동할 수 없는 영역을 정의하고, 이를 기반으로 경로를 계산한다.

상세 설정에 대해 간단하게 설명하면 다음과 같다.

<Agent Radius>
지형에 Agent가 얼마나 가깝게 다가갈 수 있는지

<Agent Height>
Agent가 다가갈 수 있는 공간의 높이

<Max Slope>
Agent가 걸어올라갈 수 있는 경사의 기울기

<Step Height>
Agent를 멈춰세우는 장애물의 높이

Hierarchy 창에서 네비게이션 매쉬를 적용할 오브젝트를 선택 후 Bake를 클릭하면 경로를 생성할 수 있다.

  • Pathfinding (경로 탐색)
    • 캐릭터의 현재 위치에서 목표 지점까지 가장 적절한 경로를 찾는 알고리즘이다.
    • 주로 A* 알고리즘 이 사용되며, 지정된 목표 위치까지 최단 경로를 탐색한다.
  • Steering Behavior (스티어링 동작)
    • 캐릭터나 NPC가 경로를 따라 이동할 때, 보다 자연스러운 동작을 구현하는데 사용한다.
    • 동적으로 캐릭터의 이동 방향과 속력을 조정하여 부드럽고 현실적인 이동을 시뮬레이션한다.
  • Obstacle Avoidance (장애물 피하기)
    • 캐릭터가 이동 중에 장애물과 충돌하지 않도록 하는 기술
    • 각종 센서나 알고리즘을 사용하여 장애물을 감지하고 피하는 동작을 수행
    • NavMesh Obstacle 컴포넌트를 사용하면 장애물을 정의할 수 있음

상세 설정에 대해 간단하게 설명하면 다음과 같다.

<Shape>
Collider의 모양이 Box인지 Capsule인지 선택 할 수 있다.

<Center>
장애물의 중심

<Size>
장애물의 크기

<Carve>
활성화해야 agent가 장애물로 인식할 수 있도록 네비매쉬에 구멍을 뚫는다.

<Move Threshold>
장애물이 이 수치 이상 움직이면 새로운 장애물의 위치를 토대로 다시 네비매쉬에 구멍을 뚫는다.

<Time To Stationary>
이 수치 이상 움직이지 않으면 장애물이 멈춘 것으로 판단

<Carve Only Stationary>
장애물이 정적일 때만 장애물로 취급한다.

  • Local Avoidance (근접 회피)
    • 여러 캐릭터나 NPC가 서로 충돌하지 않도록 하는 기술
    • 캐릭터들 사이의 거리를 유지하거나 회피 동작을 수행하여 서로 부딪히지 않도록 한다.
    • NavMesh Agent 컴포넌트를 사용하면 근접 회피 기능 구현 가능


0개의 댓글