UE5.1.1 C++从0开始(18.游戏标签)

这篇具有很好参考价值的文章主要介绍了UE5.1.1 C++从0开始(18.游戏标签)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

教程的链接:https://www.bilibili.com/video/BV1nU4y1X7iQ

这一章刚开始听可能有点晕,就记得最后做的几个功能其它全忘记了,我在这里做一个总结:

  1. 我们并没有从头开始像构建GAS一样构建一个游戏标签,我们使用的是官方给的数据类型,我们在代码内初始化的是标签容器,我们在容器内写明这个类带着什么标签,而标签的定义在蓝图编辑器内操作。我们所检查的也是对标签容器进行检查,具体行为是对容器内的标签进行比对,而不是直接检查我们的标签容器
  2. 我们给SAction类上了个互斥锁,也就是在CanStart函数内增加了一个bIsRunning的检查和一个BlockedTags标签的检查,如果正在运行或正在运行的行为的GrantTags内包含BlockedTags内的任意一个标签的话,那么下一个命令将不会被执行。我们在SActionComponent类内使用了这个互斥锁。
  3. 我们在蓝图内演示了游戏标签不但能够充当一个互斥锁的效果,还能够当一个钥匙与门锁的一个效果。教程内演示了只有当拿到固定的卡的时候才能够打开对应的箱子。
  4. 我们做了个反弹子弹的效果(有点类似于OW内源氏的e,不过这个e并不是按照我们的视角进行移动的,而是原路返回)
  5. 我们给我们的ai角色增加了受击后显示受伤的伤害显示以及更改了血条位置

我认为游戏标签应该不止这么一点点的功能,肯定还有很多教程内没有提到的功能。例如我们的不同的子弹上能够加上不同的标签,一些子弹是附带火焰伤害的,一些子弹会附带别的buff或debuff;再或者我们与NPC的交互中也可以使用标签,比如我们的装备可能会有标签赋予给我们,然后NPC可以对不同的标签作出不同的反应(有点像塞尔达那种)

废话不多说,上代码:

SAction.h

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

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "GameplayTagContainer.h"
#include "SAction.generated.h"

/**
 * 
 */
UCLASS(Blueprintable)
class ACTIONROGUELIKE_API USAction : public UObject
{
	GENERATED_BODY()

protected:

	UFUNCTION(BlueprintCallable,Category="Action")
	USActionComponent* GetOwningComponent() const;

	//在事件激活的时候增加到Actor上,事件结束后就移除
	UPROPERTY(EditDefaultsOnly,Category="Tags")
	FGameplayTagContainer GrantsTags;

	//用于检查我们是否能够运行该事件
	UPROPERTY(EditDefaultsOnly, Category = "Tags")
	FGameplayTagContainer BlockedTags;

	bool bIsRunning;

public:
    //互斥锁
	UFUNCTION(BlueprintCallable,Category = "ACtion")
	bool IsRunning() const;

    //新增检测函数,用于充当互斥锁
	UFUNCTION(BlueprintNativeEvent, Category = "Action")
	bool CanStart(AActor* Instigator);

	
	UPROPERTY(EditDefaultsOnly,Category="Action")
	FName ActionName;
	
	UFUNCTION(BlueprintNativeEvent,Category="Action")
	void StartAction(AActor* Instigator);

	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Action")
	void StopAction(AActor* Instigator);

	class UWorld* GetWorld() const override;
};

SAction.cpp

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


#include "SAction.h"
#include "Logging/LogMacros.h"
#include "SActionComponent.h"

USActionComponent* USAction::GetOwningComponent() const
{
	return Cast<USActionComponent>(GetOuter());
}

bool USAction::IsRunning() const
{
	return bIsRunning;
}

bool USAction::CanStart_Implementation(AActor* Instigator)
{
    //首先检测是否有相同的Action被短时间内快速的多次激活,如果有而且已经有一个Action正在执行,那么我们就直接返回,不执行新的Action
	if (IsRunning())
	{
		return false;
	}
	
    //第二步,检测我们的组件对象是否正在执行一个与我们最新输入的命令所执行的Action类冲突,也就是说Action内的BlockedTags是否与正在执行的Action所赋予组件的tags有任何的重叠,如果有重叠,那么最新输入的Acion不会被执行
	USActionComponent* Comp = GetOwningComponent();

	if (Comp->ActiveGameplayTags.HasAny(BlockedTags))
	{
		return false;
	}

	return true;
}

void USAction::StartAction_Implementation(AActor* Instigator)
{
	UE_LOG(LogTemp, Log, TEXT("Running: % s"), *GetNameSafe(this));

	USActionComponent* Comp = GetOwningComponent();
	Comp->ActiveGameplayTags.AppendTags(GrantsTags);

	bIsRunning = true;

}

void USAction::StopAction_Implementation(AActor* Instigator)
{
	UE_LOG(LogTemp, Log, TEXT("Stopped: % s"), *GetNameSafe(this));

	ensureAlways(bIsRunning);

	USActionComponent* Comp = GetOwningComponent();
	Comp->ActiveGameplayTags.RemoveTags(GrantsTags);

	bIsRunning = false;
}

class UWorld* USAction::GetWorld() const
{
	UActorComponent* Comp = Cast<UActorComponent>(GetOuter());
	if (Comp)
	{
		return Comp->GetWorld();
	}
	return nullptr;
}

SActionComponent.h

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

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameplayTagContainer.h"
#include "SActionComponent.generated.h"


class USAction;

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ACTIONROGUELIKE_API USActionComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tags")
	FGameplayTagContainer ActiveGameplayTags;

protected:
	UPROPERTY()
	TArray<USAction*> Actions;

	UPROPERTY(EditAnywhere, Category = "Actions")
	TArray<TSubclassOf<USAction>> DefaultActions;

public:
	UFUNCTION(BlueprintCallable,Category="Actions")
	void AddAction(TSubclassOf<USAction>ActionClass);

	UFUNCTION(BlueprintCallable, Category = "Actions")
	bool StartActionByName(AActor* Instigator, FName ActionName);

	UFUNCTION(BlueprintCallable, Category = "Actions")
	bool StopActionByName(AActor* Instigator, FName ActionName);

public:	
	// Sets default values for this component's properties
	USActionComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

		
};

SActionComponent.cpp

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


#include "SActionComponent.h"
#include "SAction.h"

void USActionComponent::AddAction(TSubclassOf<USAction>ActionClass)
{
	if (!ensure(ActionClass))
	{
		return;
	}
	USAction* NewAction =  NewObject<USAction>(this,ActionClass);
	if (NewAction)
	{
		Actions.Add(NewAction);
	}
}

bool USActionComponent::StartActionByName(AActor* Instigator, FName ActionName)
{
	for (USAction *Action : Actions)
	{
		if (Action&&Action->ActionName==ActionName)
		{
            //此处使用了互斥锁
			if (!Action->CanStart(Instigator))
			{
				continue;
			}

			Action->StartAction(Instigator);
			return true;
		}
	}
	return false;
}

bool USActionComponent::StopActionByName(AActor* Instigator, FName ActionName)
{
	for (USAction* Action : Actions)
	{
		if (Action && Action->ActionName == ActionName)
		{

			if (Action->IsRunning())
			{
				Action->StopAction(Instigator);
				return true;
			}

		}
	}
	return false;
}

USActionComponent::USActionComponent()
{
	PrimaryComponentTick.bCanEverTick = true;
}


// Called when the game starts
void USActionComponent::BeginPlay()
{
	Super::BeginPlay();

	for (TSubclassOf<USAction> ActionClass : DefaultActions)
	{
		AddAction(ActionClass);
	}

	// ...
	
}


// Called every frame
void USActionComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
	FString DebugMessage = GetNameSafe(GetOwner()) + " : " + ActiveGameplayTags.ToStringSimple();
	GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::White, DebugMessage);
}


蓝图演示我们不做过多的赘述,接下来是增加一个子弹原路返回的功能。

子弹原路返回的功能我没有写在普通魔法子弹的类里面,而是写在魔法子弹的基类里面,不过在子类和基类里面写其实大差不差,只不过在基类里面写,所有的子类子弹都能被反弹罢了。

主要更改函数是下面这个:

void ASFatherMagicProjectile::OnComponentOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{

	if (OtherActor&&OtherActor!=GetInstigator())
	{

		//由于AI和PlayerCharacter两个类都有ActionComp的组件,我们可以直接无脑抓取OtherActor的USActionComponent
		USActionComponent* ActionComp = Cast<USActionComponent>(OtherActor->GetComponentByClass(USActionComponent::StaticClass()));
        //对组件进行存在与否的判断以及组件的标签容器内是否有魔法子弹所自带的标签进行判断
		if (ActionComp&&ActionComp->ActiveGameplayTags.HasTag(ParryTag))
		{
			//调转方向
			MovementComp->Velocity = -MovementComp->Velocity;
			//将Instigator设置为反弹的那个人
			SetInstigator(Cast<APawn>(OtherActor));

			return;
		}

		if (USGameplayFunctionLibrary::ApplyDirectionalDamage(GetInstigator(), OtherActor, Damage, SweepResult))
		{
			Explode();
		}

	}
}

我们在基类的.h文件内增加了这个参数

	UPROPERTY(EditDefaultsOnly, Category = "Damage")
	FGameplayTag ParryTag;

然后在蓝图内进行标签赋值,再回到上面的函数代码,各位应该能看懂大概是个啥意思了。

最后的一点时间教程在说给我们的AI增加一个伤害显示和血条位置的调整,我觉得这个东西应该不需要再复述了,这个东西在老早之前的教程内就教过了,就是我们的几个黄色的正方体,做受到伤害就闪一下的那一节课。只需要用相同的方法在AI的蓝图内写一遍就可以了。

最后,这一块的知识运用的点可能相对前面会比较散,所以大家如果有什么不太明白的地方一定记得问我。只要我会我都会尽全力给大家用大家能理解的方式讲解,如果正好遇上了我也不会的问题,我们就一起寻找答案。文章来源地址https://www.toymoban.com/news/detail-524228.html

到了这里,关于UE5.1.1 C++从0开始(18.游戏标签)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • UE5.1.1C++从0开始(4.虚幻的接口以及交互功能)

    这一个章节对于第一次接触虚幻的人来说可以说是最绕的一个点,因为老师突然给你塞了很多的概念,对于这一块的学习,我个人的推荐是:先把蓝图搞明白了,再对应到C++的代码中,不然一定会被整的晕头转向。还是,有不懂的点就来问我。 主要有几个大点: 接口 自定义

    2024年02月04日
    浏览(30)
  • UE5.1.1创建C++工程失败解决办法

    闲来无事,更新了一下UE5.1.1,妈蛋创建C++项目居然失败, 错误截图如下: 妈蛋,后面一堆乱码,鬼知道是啥错误! 咋解决?步步高打火机,直接复制第一段的Running后面的代码到cmd中执行。 这下看的懂了, ‘dotnet’ 不是内部或外部命令,也不是可运行的程序 一般出现xxx不

    2024年02月01日
    浏览(38)
  • UE5学习笔记(1)——从源码开始编译安装UE5

    0.1 在windows的话,建议装一个Git bash,同时还要有自己的github账号,注册github账号这里就不再赘述了,安装git bash后,设置自己的github账号。或者在windows装一个WSL。 0.2 把自己的github账号关联Epic官方,必须关联之后才能下载Unreal的源码。关联方式见官方教程 0.3 安装VS 2022,这里

    2024年02月08日
    浏览(31)
  • UE4/UE5引擎 FPS游戏逆向工程

    课程详细目录 : UE引擎逆向 入门到精通 联系方式 :点击课程详细目录查看 简介: 🔥 本课程全部采用C++编程 🔓 对抗加解密逆向过程:我们将深入探讨如何对抗游戏的加密与解密机制 🕵️ 功能的寻找与实现:学完课程后,您将能够迅速定位并实现游戏内各种功能 学完本

    2024年02月02日
    浏览(30)
  • Ue5 C++ metahuman

    参考官网: 创建MetaHuman | Epic Developer Community (epicgames.com) 参考: Quixel Bridge中的MetaHuman | Epic Developer Community (epicgames.com) 参考:导出到虚幻引擎5 | Epic Developer Community (epicgames.com) 参考:在Sequencer中使用MetaHuman | Epic Developer Community (epicgames.com) 待补充

    2024年02月10日
    浏览(32)
  • UE5回合制游戏【2-摄像机控制】(蓝图版)

    上一篇文章完成了一些基础的设置,这篇文章主要来设置一下摄像机。 摄像机的控制主要有鼠标滚轮控制缩放,WASD键控制前后左右移动,QE键控制左右旋转。 首先打开BP_Pawn,然后添加Spring和Camera组件。 层级关系如下图 我们把摄像机放到弹簧臂下面,这样摄像机就能跟着弹

    2024年02月03日
    浏览(39)
  • ue5 c++ interface 接口

    https://docs.unrealengine.com/5.2/en-US/interfaces-in-unreal-engine/ 1 纯c++ 接口  没有ufunction 2 纯c++ 有ufunction

    2024年02月10日
    浏览(32)
  • UE5 C++(十七)— 射线检测

    射线检测简单来说就是通过相机发射一条射线,用来检测对象的一种检测机制。 官网介绍:使用射线进行命中判定 这里主要介绍4种常用的射线检测方式。 关键API: LineTraceSingleByChannel 声明变量 MyCharacter.h 在Tick中实现通道进行射线检测 MyCharacter.cpp 编译 之后,在场景中添加

    2024年01月18日
    浏览(81)
  • UE5 C++ UObject实例化

    一.创建UObject C++类  在MyObject中声明结构体FMyDataTableStruct 在MyPawn里面,先将头文件里包含 MyObject.h 在MyPawn中声明一个UMyObject类型的指针 TSubclassOf  是提供 UClass 类型安全性的模板类。例如您在创建一个投射物类,允许设计者指定伤害类型。您可只创建一个 UClass 类型的 UPROPER

    2024年02月21日
    浏览(30)
  • UE5 C++ 静态加载资源和类

    一.上篇文章创建组件并绑定之后 在Actor中加载初始化了组件,现在在组件中赋值。使用static ConstructorHelpers::FObjectFinderTTempName(TEXT(\\\"Copy Reference\\\"));再用TempName.Object 里面的资源都来自StarterContent   效果如下: 二.静态加载类 1.在Actor中再声明一个AActor类  2.在静态加载类时使用

    2024年02月21日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包