게임개발일지/리그오브워치

[리그오브워치개발일지] #7 기본 게임 규칙 : 타워와 넥서스 구조물

김진우 개발일지 2023. 10. 18. 23:32

Git

레포지토리 주소 : https://github.com/kjinwoo12/UE5Game_LeagueOfWatch
기준 브랜치 : 7_Structures

개발내용 정리

이전글에서는 미니언의 자동공격 기능을 만들면서 자동이동과 함께 미니언의 기본 기능을 완성했다. 플레이어의 주 무대라고 할 수 있는 공격로의 핵심 요소인 미니언은 기지에서 생성되어 상대 기지로 전진하며 전선 역할을 수행할 수 있게 되었다.

넥서스 & 넥서스가 파괴되는 모습

미니언이 상대 기지로 전진하는 목적은 "넥서스"라고 불리는 상대의 구조물을 파괴하기 위함이다. "넥서스"는 게임의 승리와 패배에 직접적으로 관여하는 오브젝트다. 각 팀의 기지에는 "넥서스" 구조물이 존재하며, 공격을 받아 파괴된다면 해당 넥서스를 보유했던 팀은 패배하게 된다. 게임을 진행하면서 상대방을 처치하고 재화를 모으며 아이템을 구매하는 등의 모든 행위들은 이 "넥서스"를 파괴하기 위한 것이다.

타워 & 타워가 공격하는 모습

넥서스와 미니언, 아군 플레이어를 지키기 위한 오브젝트도 존재한다. 타워는 높은 체력과 공격력을 가지고 있고, 일정 사거리 이내로 들어온 적 캐릭터를 공격해 접근을 막는다. 각각의 공격로에는 아군 타워 3개, 적군 타워 3개가 존재하며 넥서스로 접근하는 적 오브젝트를 차단한다. 또, 전방에 있는 타워가 부숴지기 전까지 후방에 있는 타워와 넥서스에는 피해를 입히지 못하기 때문에 제거 대상 1순위다.

이번 글에서는 넥서스와 타워를 만들어볼 예정이다. 아래는 이전 개발 내용과 앞으로 만들 개발 내용을 정리한 것이다. 이전 글에서 완성된 기능들은

취소선으로

처리했다. 정리하면서 추가된 내용이 있으니 참고.

  • 게임진행 규칙 :게임이 진행되는 동안 세 개의 공격로에서 각각 30초 간격으로 미니언 6마리가 생성되고, 적 기지를 향해 이동하면서 적 진영의 오브젝트를 공격한다.
    • 미니언
      • 체력
      • 자동공격
        • 공격 이펙트 - 이펙트는 개발 시간 단축을 위해 게임 룰 완성 후 작업
        • 피격 이펙트 - 이펙트는 개발 시간 단축을 위해 게임 룰 완성 후 작업
    • 진영 소속 오브젝트 (예: 포탑)
      • 전방 오브젝트 파괴 전까지 무적
  • - 디버그를 위해 타이머 기능과 생성 기능만 추가하고 규칙 적용 안함
  • 체력 규칙 : 체력이 있는 모든 오브젝트는 체력이 0 이하가 되면 파괴되거나 죽는다
  • .
  • 게임 승리 규칙 : 게임의 최종 목표는 적 진영 중요 건물(이하 "넥서스")을 파괴하는 것이다.
    • 넥서스
      • 체력
      • 전방 오브젝트 파괴 전까지 무적

넥서스

넥서스...? 넥서스 맞다.

게임 승리 규칙과 관련있는 넥서스를 먼저 만들어보자. 간단하게 기본 메시인 원기둥 모양으로 넥서스를 만들었다. 지금은 단순하고 밋밋하지만 나중에 성 문이나 장벽처럼 꾸미면 훨씬 보기 좋을 것이다.

넥서스에 필요한 것은 넥서스의 '체력'과 '파괴 시 게임 종료 이벤트'이다. 넥서스에는 체력 외 능력치가 없으니 미니언을 만들 때보다 훨씬 간단하게 구현할 수 있다. 최대 HP와 현재 HP 변수를 추가하고, 데미지 수신 이벤트에서 데미지만큼 현재 HP를 감소시키면 끝이다. '파괴 시 게임 종료 이벤트'의 경우에는 어느 팀 넥서스가 파괴되었는지 게임 모드에 정보를 전달하고 게임 모드에서 세부 내용을 처리하자.

태그 MinionAttackTarget 추가

넥서스는 미니언이 공격할 수 있는 오브젝트 중 하나다. 미니언 AI가 오브젝트를 탐지하고 공격하도록 만드는 방법은 #6 미니언 AI - 자동공격 에서 AIC_Minion를 다루는 부분에서 설명을 했다. 바로 MinionAttackTarget 태그를 액터에 추가하는 것이다.

BP_GameMode_IngameLevel 넥서스 파괴 이벤트 처리

넥서스 파괴 시 게임 승리/패배 위젯을 띄우려고 한다. LeagueOfWatch/Widgets/IngameLevel에 승리 또는 패배 시 띄울 위젯을 추가하고 게임 모드에서 해당 위젯을 띄우는 간단한 작업이다. 먼저 플레이어의 팀을 가져와야하기 때문에 플레이어의 정보를 다루는 역할을 하는 PlayerState를 만들 필요가 있다. BP_PlayerState_IngameLevel을 만들고 ETeam 타입 변수를 생성한다. #3 기본 게임 규칙 구현 : 플레이어 캐릭터에서 다룬 BPI_TeamSystem 인터페이스를 추가해 GetTeam 함수를 메시지 호출할 수 있도록 만들어준다. Team 변수를 반환하도록 만들면 끝이다.

게임모드에서는 커스텀이벤트 OnNexusDestroyed를 추가한다. 플레이어와 부숴진 넥서스의 팀을 비교해서 팀이 다르다면 승리 위젯을, 패배하면 패배 위젯을 뷰포트에 추가한다.

승리&패배 위젯

WBP_IngameLevel_Win

승리&패배 위젯은 간단하게 화면에 텍스트를 띄우고 레벨 재시작 버튼을 추가했다.

타워

타워  & 범위액터 작동 순서

다음은 타워를 만들 차례다.타워를 만들기 위해서는 범위 안에 들어오는 적을 감지하고, 감지한 적을 공격하는 기능이 필요하다. 감지 기능에는 미니언과 같이 AI 인식 기능을 사용하기보다, 인식범위 액터를 만들고 타워와 연결해 사용하는 것이 타워의 일관된 적 감지에 도움이 될 것이라고 판단했다. 인식범위 액터를 따로 만드는 이유는 공격 범위를 컴포넌트로 만들면 미니언의 AI 인식 기능에서 범위 컴포넌트도 타워로 인식해 공격할 가능성이 있기 때문이다.

적 감지 범위 액터

①번을 담당하는 적 감지 범위 액터다. 이름은 BP_TowerAttackArea이다. 이벤트 디스패처 OnUpdateAttackTarget 를 만들어서 타워가 이 액터와 연결된 후 공격할 수 있도록 감지된 적 액터 목록을 전달한다. 오버랩 이벤트가 발생한 모든 액터를 전달할 수는 없기 때문에, 미니언 공격 타겟 때와 마찬가지로 TowerAttackTarget태그를 가진 액터만 전달한다.

타워 본체

타워의 역할은 적 감지 범위 액터에서 식별된 액터를 가져와 공격을 수행하는 것이다. 적 감지 범위 액터와 연결 후 공격 대상을 식별하는 것과 만들어야 한다. OnUpdateAttackTarget 변수를 만들어 편집가능, 스폰시 노출을 켜주고 BeginPlay에서 OnUpdateAttackTarget이벤트를 바인딩하면 끝이다. 추가로 타워도 부서지기 때문에 피격시 데미지 처리를 해주고, 미니언이 공격할 수 있도록 MinionAttackTarget 태그를 추가한다.

타워 공격

먼저 타워가 어떻게 공격하는지 파악해보자. 타워의 공격은 아래와 같은 순서로 이루어진다.

  1. 적이 감지되지 않았을 때 정지
  2. 적이 감지되면 경고음과 함께 붉은 선으로 타게팅
  3. 투사체 발사
  4. 투사체가 적 추적
  5. 명중 후 데미지 적용
  6. 적이 범위를 벗어나면 붉은 선 타게팅 해제. 단, 투사체는 계속 적 추적

이를 토대로 만들어야할 기능은 공격 기능, 발사될 투사체, 팀 식별이다. 붉은 선과 경고음은 효과의 영역이므로 생략한다.

투사체

타워 투사체 액터인 BP_TowerProjectile는 생성됐을 때 지정된 Target을 목표로 날아간다. 명중하면 데미지를 준 후 사라진다. 명중 전에 타겟이 소멸할 가능성이 있으므로 대응 코드를 넣어둔다. 만약 타겟이 사라지게 된다면 타겟의 마지막 위치로 투사체가 이동하게 된다.

투사체를 발사하는 기능은 단순하다. BP_TowerProjectile 액터를 생성하면서 적절한 파라미터를 넘겨주면 끝이다. BP_TowerDoAttack 함수를 추가해 액터를 생성한다.

DoAttack 함수가 호출되는 시점은 BP_Tower에서 적을 공격하는 시점이다. 매 프레임마다 공격하는 것이 아닌 공격 속도에 따라 딜레이가 발생하는 것은 BP_Minion을 만들 때 구현했던 것과 동일하다. 코드 중복이 발생하지 않도록 처리할 필요가 있었다.

공격 딜레이

BP_CoolTimerComponent 컴포넌트를 추가한다. BP_Minion에 있는 코드와 비슷한 형태로 만들면 된다. 물론 기존 코드를 대체할 생각이다. 공격 딜레이는 물론 쿨타임이 존재하는 스킬을 추가하게 되었을 때도 활용할 예정이다.

쿨타임 발생 시 Start 이벤트를 호출시킨다. 이후 컴포넌트의 CurrentCoolTime 변수를 필요한 곳에 사용하면 된다. 쿨타임이 종료되면 이벤트 디스패처 OnCoolTimeDone가 호출된다. 이 컴포넌트는 전투 관련이므로 이전에 데미지 타입을 만들었을 때 정리한 위치인 Core/CombatSystem에 같이 정리해두자. 이제 타워와 미니언에 적용해야 한다.

타워 적용

미니언 적용

BP_Minion

DoAttack

타워에서 DoAttack 호출

AttackTargetTowerAttackArea 에 의해 감지되었을 때 DoAttack을 호출하고, 공격 딜레이가 끝난 후에도 AttackTarget이 있다면 다시 DoAttack을 호출한다. 미니언과 다른 점은, 미니언의 DoAttack의 경우 BTTask에 의해 계속 호출되므로 이벤트 대신에 쿨타임을 계산해 호출하지만 타워는 Task가 아니라 자체적으로 공격 시점을 정하기 때문에 OnCoolTimeDone 이벤트를 활용한다는 것이다.

팀 식별

아군을 제외한 오브젝트만 공격하고 싶다면 미니언과 같이 ETeam을 추가해서 공격 시, 또는 오브젝트 감지 시 같은 팀인지 검사하면 된다. 타워에 BPI_TeamSystem 인터페이스를 추가하고, BP_TowerAttackArea 에서는 다른 팀인 경우에만 AttackTargets에 액터를 추가한다. 타워의 BeginPlay에서 연결된 BP_TowerATtackArea에 팀을 전달하면 끝이다.

BP_TowerAttackArea

BP_Tower

타워 완성 모습