Infinite Fighter 개발일지 (12)

유영준·2023년 6월 5일
0

UE5 UNSEEN

목록 보기
12/18
post-thumbnail

23.05.29 ~ 2023.06.04 개발일지

AI 설계와 패링 구현

AI 설계

내 게임의 특성상 탐색의 부분은 필요가 없을거같아 태어남과 동시에 캐릭터를 공격하도록 설계했다

거리에 따라 원거리 공격을 할지 근거리 공격을 할지만 계산하도록 하였다

먼저 블랙보드와 비헤이비어 트리를 생성해주었다

AI 컨트롤러를 상속받는 커스텀 컨트롤러에 블랙보드와 비헤이비어 트리를 추가해주었다

IFEnemyController.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "AI/IFEnemyController.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardData.h"
#include "BehaviorTree/BlackboardComponent.h"

AIFEnemyController::AIFEnemyController()
{
    static ConstructorHelpers::FObjectFinder<UBlackboardData> BLACKBOARD
    (TEXT("/Game/InFiniteFighter/AI/AI/BB_IFEnemy.BB_IFEnemy"));
    if (BLACKBOARD.Succeeded())
        BBAsset = BLACKBOARD.Object;

    static ConstructorHelpers::FObjectFinder<UBehaviorTree> BEHAVIORTREE
    (TEXT("/Game/InFiniteFighter/AI/AI/BT_IFEnemy.BT_IFEnemy"));
    if (BEHAVIORTREE.Succeeded())
        BTAsset = BEHAVIORTREE.Object;
}

void AIFEnemyController::RunAI()
{
    UBlackboardComponent* BlackBoardPtr = Blackboard.Get();
    if (UseBlackboard(BBAsset, BlackBoardPtr))
    {
        bool RunResult = RunBehaviorTree(BTAsset);
        ensure(RunResult);
    }
}

void AIFEnemyController::StopAI()
{
    UBehaviorTreeComponent* BTComponent = Cast<UBehaviorTreeComponent>(BrainComponent);
    if (BTComponent)
    {
        BTComponent->StopTree();
    }
}

void AIFEnemyController::OnPossess(APawn* InPawn)
{
    Super::OnPossess(InPawn);

    RunAI();
}

적 클래스는 AI 컨트롤러 클래스가 작동하도록 추가시켜주었다

IFEnemy.cpp

AIFEnemy::AIFEnemy()
{
	...

	// setting Controller
	AIControllerClass = AIFEnemyController::StaticClass();
	AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
}

다음으로 공격 Task 를 만들어주었다 근접공격을 수행할 ShortAttack Task 는 간단하게 폰의 정보를 가져와 공격을 실행하도록 하였다

BTTask_ShortAttack.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "AI/BTTask_ShortAttack.h"
#include "AIController.h"
#include "IFEnemy.h"

UBTTask_ShortAttack::UBTTask_ShortAttack()
{
}

EBTNodeResult::Type UBTTask_ShortAttack::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
    EBTNodeResult::Type Result = Super::ExecuteTask(OwnerComp, NodeMemory);

	APawn* ControllingPawn = Cast<APawn>(OwnerComp.GetAIOwner()->GetPawn());
	if (nullptr == ControllingPawn)
	{
		return EBTNodeResult::Failed;
	}

	AIFEnemy* AIPawn = Cast<AIFEnemy>(ControllingPawn);
	if (nullptr == AIPawn)
	{
		return EBTNodeResult::Failed;
	}

	AIPawn->Attack();
	return EBTNodeResult::Succeeded;
}

현재까지의 상태를 보면 이러하다

작동또한 잘 하는것을 볼 수 있다

캐릭터 피격 판정

캐릭터에게도 피격판정을 추가해주었다

기본적인 데미지를 입는 방식은 적과 동일하고, 데미지를 체크하는 것도 다 구축이 되어 있어 간편하게 추가할 수 있었다

패링 판정

다음은 패링 판정이다 패링 모션이 따로 있고 키도 있지만, 그 외에 방어태세를 취하는 짧은 시간동안 패링이 가능하길 원했다

패링에 성공하면 적을 하던 행동을 취소하고 스턴 상태에 빠지고 그런 상태의 적이라면 추가했던 Execution이 가능하도록 구현했다

아직 러프하지만 대략적인 모습은 이러하다

일단은 구현을 최우선으로 했기에 비주얼적으로는 좋지 않지만...

스턴 상태가 되면 적이 스턴에 걸려 움직이지 않도록 구현하고자 했다

애님 인스턴스에 스턴에 대한 상태를 추가해주고, 스턴일때 움직이는 데코레이터를 추가했다

BTDecorator_StunCheck.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "AI/BTDecorator_StunCheck.h"
#include "AIController.h"
#include "IFEnemy.h"
#include "IFEnemyAnimInstance.h"

UBTDecorator_StunCheck::UBTDecorator_StunCheck()
{
    NodeName = TEXT("Stun Check");
}

bool UBTDecorator_StunCheck::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
{
    bool bResult = Super::CalculateRawConditionValue(OwnerComp, NodeMemory);

    AIFEnemy* ControllingPawn = Cast<AIFEnemy>(OwnerComp.GetAIOwner()->GetPawn());
    if (nullptr == ControllingPawn)
    {
        return false;
    }

    bResult = ControllingPawn->AnimInstance->GetStunState();

    return bResult;
}

이런 느낌으로 데코레이터를추가하고 비헤이비어 트리에 추가해주었다

다만 내가 생각한대로 작동해주지 않았는데, 데코레이터 BlackBoard 처럼 값이 변화하는 순간에 바로 다시 옮기기를 원했는데

이렇게 구현을 하니 Wait Task 가 끝난 이후 StunCheck 데코레이터를 검사하여 스턴이 정확하게 구현이 되지 않았다

이를 위해 추가로 서비스 노드를 포함해보았지만 이또한 해결하지 못했다

일단 다음의 가장 큰 과제는 이를 해결하는 것부터 시작해야겠다

profile
토비폭스가 되고픈 게임 개발자

0개의 댓글