您现在的位置是:首页 >技术教程 >UE5.1.1C++从0开始(12.EQS)网站首页技术教程

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

楚江_wog1st 2024-08-16 00:01:02
简介UE5.1.1C++从0开始(12.EQS)

怕有些朋友不知道教程指的是哪一个,我在这里把教程的网址贴出来: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:从左到右的子项中,一旦有一个子项可以执行,那么执行完这个子项之后就直接返回,就算后面的子项能执行,也不执行了。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。