Unity-#12.UI와 Enemy AI

CHO WanGi·2024년 4월 29일

Unity

목록 보기
13/13

다형성(Polymorphism)

객체 지향의 특징 중 하나,
AI인 좀비와 플레이어 캐릭터 모두, 생명체로 동작하는 클래스가 공유하는
LivingEntity상속하고 그 위에 자신만의 기능을 추가

public class Monster: MonoBehaviour{

	public void Attack(){
   		Debug.Log("공격");
    }
}

public class Orc: Monster{

	public void WarCry(){
   		Debug.Log("전투함성");
    }
}

public class Dragon: Monster{

	public void Fly(){
   		Debug.Log("날기");
    }
}

위 코드에선 Monster 클래스를 Orc와 Dragon이 각각 상속하고
각자의 WarCry와 Fly 기능을 각각 추가하였다.

Orc orc = FindObjectOfType<Orc>();
Monster monster = orc;
monster.Attack(); // 실행가능
monster.Warcry(); // 실행불가

Monster monster = orc; 코드가 실행되면, Orc 타입의 오브젝트가
Monster 타입으로 취급,
다만, Attack 메서드는 Monster 타입에 있어서 실행이 가능하지만,
WarCry는 Orc 오브젝트 고유의 기능.
따라서 상위 클래스인 Monster 에서 호출하면, 없는 메소드기 때문에 실행이 불가능 한 것.

다형성을 활용한 패턴

다양한 자식 타입을 하나의 부모 타입으로 다루어 간결한 코드로 활용가능

public void WarCry(){
	Debug.Log("전투함성");
}

Monster[]monsters = FindObjectsOfType<Monster>();
for (int i = 0; i < monsters.Length; i++) {
	monsters[i].damage = 10;
}

또한Monster[]monsters = FindObjectsOfType<Monster>(); 로 Monster 타입의 오브젝트인 Orc 와 Dragon을 한꺼번에 검색이 가능

이유는 Monster 타입을 두 오브젝트 모두 상속했기 때문에 Monster 타입으로 취급되기 때문.

Override

메서드에도 다형성을 적용하여, 같은 이름의 메서드가 서로 다른 방식으로 동작하는 것이 가능
즉, 부모 클래스의 메서드를 상속받은 자식클래스에서 재정의 하는 것.

public class Monster: MonoBehaviour{

	public void Attack(){
   		Debug.Log("공격");
    }
}

public class Orc: Monster{

	public Override void Attack(){
    	base.Attack();
   		Debug.Log("Orc 공격");
    }
}
  • base
    오버라이드시 원형을 유지하면서 확장할 수도, 완전히 처음부터 메서드를 다시 만들 수도 있음
    base.Attack();는 부모 클래스의 메서드를 그대로 실행,
    만약 이것이 없다면 바닥부터 새로 만드는 것.

LivingEntity 기반 클래스

게임 속 생명체의 공통기능

  • 체력
  • 체력 회복
  • 공격
  • 생존 및 사망
	public class LivingEntity : MonoBehaviour, IDamageable {}

IDamageable을 상속하기 때문에 OnDamage() 메서드를 반드시 구현

  • Protected get, Protected Set
    public float health { get; protected set; } // 현재 체력

위 코드는 public get, protected set, 값을 가져오는 것은 아무데서나 가능하지만, 현재 체력 값을 설정하는 경우는 외부 클래스에선 접근이 불가능하고, 자식 클래스에서만 접근이 가능

Action

입력과 출력이 없는 메서드를 가리킬 수 있는 델리게이트(=대리자)
void SomeFunction() 처럼 입력 및 출력이 없는 메서드 등록 가능
등록된 메서드는 원하는 시점에 매번 실행 가능

Public class Cleaner : MonoBehaviour {
	Action onclean;
    
    void Start(){
    	onClean += CleaningRoomA;
        onClean += CleaningRoomB;

    }
    
    void Update(){
    	onClean();
    }
    
    void CleaningRoomA() {
    	Debug.Log("A청소");
    }	
    void CleaningRoomB() {
    	Debug.Log("B청소");
    }	
}

+= 를 사용하여 메서드 등록이 가능.
이름만 명시하여 등록, 만약 괄호를 붙여버리면 실행하고 반환값을 할당하게 됨.

따라서 onClean() 을 실행하면 등록된 메서드인 CleaningRoomA, CleaningRoomB 모두 실행됨.

이벤트

이벤트는 연쇄 동작을 이끌어내는 사건
이벤트와 이벤트 리스너로 오브젝트를 구분
C#에서는 델리게이트를 클래스 외부로 공개하여 이벤트를 구현

  • 견고한 커플링 해소
public Class Player: MonoBehaviour {
	public GameData gameData;
    
    public void Die(){
    	gameData.Save();
    }
    
    public void GameData : MonoBehaviour{
    	public void Save() {
        	Debug.Log('게임저장');
        }
    }
}

Player 클래스와 GameData 클래스가 강력히 결합된 상태
그런데 Player는 게임 저장 관련 기능을 담당할 필요가 없음
단, GameData는 Player 오브젝트의 생존/사망 정보를 추적할 필요가 있는 상태

--> Player 클래스에서 onDeath 를 제공받는 것으로 개선이 가능

public Class Player: MonoBehaviour {
	public GameData gameData;
    
    public void Die(){
    	onDeath();
    }
    
    public void GameData : MonoBehaviour{
    
    	public void Start() {
    		Player player = FindObjectOfType<Player>();
            player onDeath += Save;
        }
	
    	public void Save() {
        	Debug.Log('게임저장');
        }
    }
}

Player의 onDeath 이벤트를 구독하여, Player 오브젝트는 상대방 옵젝을 파악할 필요가 없게 되고, GameData만 이를 파악할 수 있음.

  • event 타입
    델리게이트 타입의 변수는 event 키워드를 붙여 선언 가능
    event 키워드가 붙는 다면 클래스 외부에선 해당 델리게이트를 실행할 수 없음
public Class Player: MonoBehaviour {
	public event Action onDeath;
    
    public void Die(){
    	onDeath();
    }
    
    public void GameData : MonoBehaviour{
        public void Start() {
                Player player = FindObjectOfType<Player>();
                player onDeath += Save;
                player.onDeath(); // player 밖에선 onDeath X
            }
    	public void Save() {
        	Debug.Log('게임저장');
        }
    }
}

체력 UI

UGUI 의 캔버스는 게임 화면을 기준으로 UI 를 배치
체력 슬라이더는 Player 를 기준으로 따라다녀야 함.

--> 캔버스 컴포넌의 렌더모드를 전역 공간(World Space)로 변경

  • 상호작용
    Interactable필드가 체크된 경우 사용자의 클릭 혹은 드래그 등을 통해 UI 게임 오브젝트와 상호작용 가능

유니티는 실시간으로 장애물을 피하며 이동하는 인공지는을 만드는 내비게이션 시스템 제공

  • NavMesh : 에이전트가 걸어다닐 수 있는표면
    • 정적 게임 옵젝 대상, 실시간 생성 불가
  • NavMesh Agent : 내비 메시 위 경로를 계산하고 이동하는 캐릭터 또는 컴포넌트
  • NavMesh Obstacle: 에이전트의 경로를 막는 장애물
  • Off Mesh Link : 끊어진 내비메시 영역 사이를 잇는 연결 지점
profile
제 Velog에 오신 모든 분들이 작더라도 인사이트를 얻어가셨으면 좋겠습니다 :)

0개의 댓글