UE5.1.1C++从0开始(12.EQS)

文章介绍了如何使用C++为游戏AI实现自定义行为树任务,如发射子弹,并结合蓝图编辑器。AICharacter通过PawnSensingComponent感知玩家并更新目标。行为树中的Sequence节点按照顺序执行子任务,若一个失败则停止,Selector节点则在找到一个可执行子任务后立即停止,不再执行后续任务。
摘要由CSDN通过智能技术生成

怕有些朋友不知道教程指的是哪一个,我在这里把教程的网址贴出来:https://www.bilibili.com/video/BV1nU4y1X7iQ?p=1

前段时间去了趟广州,和朋友一起玩了两天,咕咕了,这几天加油把咕咕咕的部分补上来

这一章的C++代码比较少,大部分都是蓝图编辑器完成。我把代码贴完之后,聊一下我对于行为树的不同节点的作用的看法吧。

首先是行为树的自定义任务,SBTTask,此处的自定义task作用是发射子弹,与我们之前写的ASCharacter.cpp内的那部分代码很相似。

SBTTask_RangedAttack.h

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

#pragma once

#include "CoreMinimal.h"
#include "BehaviorTree/BTTaskNode.h"
#include "SBTTask_RangedAttack.generated.h"

/**
 * 
 */
UCLASS()
class ACTIONROGUELIKE_API USBTTask_RangedAttack : public UBTTaskNode
{
    GENERATED_BODY()

        virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
    
protected:
    UPROPERTY(EditAnywhere,Category="AI")
    TSubclassOf<AActor>ProjectileClass;


};

SBTTask_RangedAttack.cpp

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


#include "AI/SBTTask_RangedAttack.h"
#include "AIModule/Classes/AIController.h"
#include "GameFramework/Character.h"
#include "BehaviorTree/BlackboardComponent.h"

EBTNodeResult::Type USBTTask_RangedAttack::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
    AAIController* MyController = OwnerComp.GetAIOwner();
    if (ensure(MyController))
    {
        ACharacter* MyPawn = Cast<ACharacter>(MyController->GetPawn());
        if (MyPawn == nullptr)
        {
            return EBTNodeResult::Failed;
        }

        FVector MuzzleLocation = MyPawn->GetMesh()->GetSocketLocation("Muzzle_01");

        AActor* TargetActor = Cast<AActor>(OwnerComp.GetBlackboardComponent()->GetValueAsObject("TargectActor"));

        if (TargetActor == nullptr)
        {
            return EBTNodeResult::Failed;
        }

        FVector Direction = TargetActor->GetActorLocation() - MuzzleLocation;
        FRotator MuzzleRotation = Direction.Rotation();

        FActorSpawnParameters Params;
        Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

        AActor* NewProj = GetWorld()->SpawnActor<AActor>(ProjectileClass, MuzzleLocation, MuzzleRotation, Params);

        NewProj->SetInstigator(MyPawn);
         
        return NewProj ? EBTNodeResult::Succeeded : EBTNodeResult::Failed;
    }

    return EBTNodeResult::Failed;

    return EBTNodeResult::Type();
}

给AICharacter加上PawnSensingComponent

SAICharacter.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "SAICharacter.generated.h"

UCLASS()
class ACTIONROGUELIKE_API ASAICharacter : public ACharacter
{
    GENERATED_BODY()

protected:
    UPROPERTY(EditAnywhere,Category="Component")
    class UPawnSensingComponent* PawnSensingComp;

    UFUNCTION()
    void OnPawnSee(APawn * Pawn);

public:
    // Sets default values for this character's properties
    ASAICharacter();

protected:
    virtual void PostInitializeComponents() override;
};

SAICharacter.cpp

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


#include "AI/SAICharacter.h"
#include "AIModule/Classes/AIController.h"
#include "AIModule/Classes/BehaviorTree/BlackboardComponent.h"
#include "AIModule/Classes/Perception/PawnSensingComponent.h"
#include "Delegates/Delegate.h"

void ASAICharacter::OnPawnSee(APawn* Pawn)
{
    AAIController* AIC = Cast<AAIController>(GetController());
    if (AIC)
    {
        UBlackboardComponent* BBC = AIC->GetBlackboardComponent();

        BBC->SetValueAsObject("TargectActor",Pawn);
    }
}

// Sets default values
ASAICharacter::ASAICharacter()
{
    PawnSensingComp = CreateDefaultSubobject<UPawnSensingComponent>("PawnSensingComp");
}

void ASAICharacter::PostInitializeComponents()
{
    Super::PostInitializeComponents();
    //给组件的事件绑定函数
    FScriptDelegate OnSee;
    OnSee.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ASAICharacter::OnPawnSee")));
    PawnSensingComp->OnSeePawn.Add(OnSee);
}

绑定的函数的用途是:当我们的玩家走到了检测范围内的时候,就会将玩家赋值给黑板上的TargetActor属性。就不需要我们从一开始就在Controller里头赋值了。

C++的内容就这么多,可能涉及到AI的,除了自定义的内容,其它的都可以在蓝图里面实现吧,包括我们的自定义的任务节点也是在蓝图内调用实现的。

行为树的节点,教程目前就涉及了两样:Sequence 和 Selector,我在进行各种尝试之后,对这两个节点有了点自己的看法

Sequence:从左到右的子项中,如果有一个执行不了,直接返回,就不继续执行下面的子项了。

Selector:从左到右的子项中,一旦有一个子项可以执行,那么执行完这个子项之后就直接返回,就算后面的子项能执行,也不执行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楚江_wog1st

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值