UE5.1.1 C++从0开始(16.作业5思路分享)

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

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

总结一下这次的任务点:

  1. 用PlayerState来做一个Credit系统,需要在我们的ui内显示我们的分数
  2. 更新血药对象,每次使用血药都会扣除相应的分数
  3. 新增一个金币对象,每次和一个金币对象交互就会增加一定的分数
  4. 在地图内随机生成金币和血药
  5. 金币和血药需要从同一个父类中继承下来

整个分数系统和我们的血量其实差不多,无非就是增加减少,检查剩余的分数够不够我们用来和血药交互的。还是老规矩,直接上代码

SPlayerState.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerState.h"
#include "Delegates/DelegateCombinations.h"
#include "SPlayerState.generated.h"

//蓝图宏
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCreditChange, float, NewCredit);


UCLASS()
class ACTIONROGUELIKE_API ASPlayerState : public APlayerState
{
	GENERATED_BODY()

	ASPlayerState();

    //蓝图节点
	UPROPERTY(BlueprintAssignable)
	FOnCreditChange OnCreditChange;

private:
	float Credit;
    
private:
	float CreditMax;

public:
	UFUNCTION(BlueprintCallable,Category="Credit")
	const float GetCredit() {
		return Credit;
	}

public:
	UFUNCTION(BlueprintCallable, Category = "Credit")
	void AddCredit(float DeltaCredit);

	
};

SPlayerState.cpp

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


#include "SPlayerState.h"

ASPlayerState::ASPlayerState()
{
	CreditMax = 100;
	
	Credit = 0;
}

void ASPlayerState::AddCredit(float DeltaCredit)
{
    //我给分数加了个上下限,这个功能可加可不加
	Credit = FMath::Clamp(Credit + DeltaCredit, 0, CreditMax);
	
    //每次更改都会在日志里头打印出来
	UE_LOG(LogTemp, Warning, TEXT("Credit:%f"),Credit);
	
    //蓝图节点广播
	OnCreditChange.Broadcast(Credit);
}



各位应该看得出来,我创建的这个类只有得分这一项,其实看APlayerState.h里头你也能看到一个和分数一样的东西,就是Score。这个类在这里的作用单纯是存储我们的Credit用的,然后提供get set方法而已。同时我也在代码内写了一个广播,那么我在蓝图编辑器内是这样写的。

UE5.1.1 C++从0开始(16.作业5思路分享),UE5.1.1_C++,ue5,c++,游戏

然后就是我们的父类设计,我这里把它命名为SBaseCreditUseActor,因为我能找到的共同点就这点了。在这个类里面我使用了Interface,也就是说我们需要对着这些物品摁e才会触发事件。

SBaseCreditUseActor.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SGameplayInterface.h"
#include "SPlayerState.h"
#include "SBaseCreditUseActor.generated.h"

UCLASS()
class ACTIONROGUELIKE_API ASBaseCreditUseActor : public AActor , public ISGameplayInterface
{
	GENERATED_BODY()
	
    //接口实现
	void Interact_Implementation(APawn* InstigatorPawn) override;
	
	UPROPERTY(EditAnywhere,Category="Component")
	class UStaticMeshComponent* MeshComp;

public:
    //用来判断能否执行实现函数
	UFUNCTION(BlueprintCallable,Category="Credit")
	bool CanImplement(ASPlayerState* ASP);

    //实现函数
	UFUNCTION(BlueprintCallable,Category="Implementation")
	virtual void Implementation(ASPlayerState* ASP , APawn* InstigatorPawn);

public:
    //CreditNeed的get set方法
	UFUNCTION()
	void SetCreditNeed(float Creditneed);

	const float GetCreditNeed() {
		return CreditNeed;
	}

private:
	float CreditNeed;

public:	
	// Sets default values for this actor's properties
	ASBaseCreditUseActor();

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

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;


};

SBaseCreditUseActor.cpp

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


#include "SBaseCreditUseActor.h"

//接口实现函数
void ASBaseCreditUseActor::Interact_Implementation(APawn* InstigatorPawn)
{
	if (!CanImplement(InstigatorPawn->GetPlayerState<ASPlayerState>()))
	{
		return;
	}
	Implementation(InstigatorPawn->GetPlayerState<ASPlayerState>(),InstigatorPawn);
}

//判断能否执行实现函数的函数
bool ASBaseCreditUseActor::CanImplement(ASPlayerState*ASP)
{
	return ASP->GetCredit() >= CreditNeed;
}

//实现函数,这里我没写是因为这里的函数每个子类都不相同,所以我们这里的函数都会在子类里面重写
void ASBaseCreditUseActor::Implementation(ASPlayerState* ASP, APawn* InstigatorPawn)
{

}
//set方法
void ASBaseCreditUseActor::SetCreditNeed(float Creditneed)
{
	CreditNeed = Creditneed;
}

// Sets default values
ASBaseCreditUseActor::ASBaseCreditUseActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh Component"));
	RootComponent = MeshComp;

    //CreditNeed默认值
	CreditNeed = 25;

}

// Called when the game starts or when spawned
void ASBaseCreditUseActor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ASBaseCreditUseActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}


这一串代码其实就是我在之前的血瓶的代码的基础上抽象加上一点优化得到的代码,能适应大部分的情况,不过少数的子类仍然需要重写大量的父类函数。

首先是稍微简单一点的金币

SCoin.h

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

#pragma once

#include "CoreMinimal.h"
#include "SBaseCreditUseActor.h"
#include "SCoin.generated.h"

/**
 * 
 */
UCLASS()
class ACTIONROGUELIKE_API ASCoin : public ASBaseCreditUseActor
{
	GENERATED_BODY()

	ASCoin();

	virtual void Implementation(ASPlayerState* ASP, APawn* InstigatorPawn);
};

SCoin.cpp

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


#include "SCoin.h"

ASCoin::ASCoin()
{
	SetCreditNeed(0.0f);
}

void ASCoin::Implementation(ASPlayerState* ASP, APawn* InstigatorPawn)
{
	ASP->AddCredit(10);
	GetWorld()->DestroyActor(this);
}

这个类基本上没有做太多的改动

在之后就是改动比较大的血瓶类

SHealthPotion.h

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

#pragma once

#include "CoreMinimal.h"
#include "SBaseCreditUseActor.h"
#include "SHealthPotion.generated.h"

/**
 * 
 */
UCLASS()
class ACTIONROGUELIKE_API ASHealthPotion : public ASBaseCreditUseActor
{
	GENERATED_BODY()

	void Interact_Implementation(APawn* InstigatorPawn) override;

	virtual void Implementation(ASPlayerState* ASP, APawn* InstigatorPawn) override;

	UPROPERTY(EditDefaultsOnly,Category="Health")
	float HealthDelta;

	ASHealthPotion();
};

SHealthPotion.cpp

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


#include "SHealthPotion.h"
#include "SAttributeComponent.h"


void ASHealthPotion::Interact_Implementation(APawn* InstigatorPawn)
{
	USAttributeComponent* AttributeComp = USAttributeComponent::GetArrtibutes(InstigatorPawn);

    //主要改动是if的判断,我需要除了credit的扣除检测之外还要检测玩家血量,不能说满血也能扣除分数进行补血
	if (!CanImplement(InstigatorPawn->GetPlayerState<ASPlayerState>())||AttributeComp->GetHealth()==100)
	{
		return;
	}
	Implementation(InstigatorPawn->GetPlayerState<ASPlayerState>(), InstigatorPawn);
}

void ASHealthPotion::Implementation(ASPlayerState* ASP, APawn* InstigatorPawn)
{
	USAttributeComponent* AttributeComp = USAttributeComponent::GetArrtibutes(InstigatorPawn);
	AttributeComp->ApplyHealthChange(this, HealthDelta);
	ASP->AddCredit(-GetCreditNeed());
	GetWorld()->DestroyActor(this);
}

ASHealthPotion::ASHealthPotion()
{
	SetCreditNeed(25);
	HealthDelta = 20.0f;
}

写完以上这些之后,就剩下随机生成的问题了,还记得之前的机器人生成的那个函数吗?我们用相同的方法来做。

SGameModeBase.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "EnvironmentQuery/EnvQueryTypes.h"
#include "../../../../../UE_5.1/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryInstanceBlueprintWrapper.h"
#include "SGameModeBase.generated.h"

/**
 * 
 */
UCLASS()
class ACTIONROGUELIKE_API ASGameModeBase : public AGameModeBase
{
	GENERATED_BODY()

protected:

	UPROPERTY(EditDefaultsOnly,Category="AI")
	class UEnvQuery* SpawnBotQuery;

	UPROPERTY(EditDefaultsOnly, Category = "AI")
	class UEnvQuery* SpawnHealthQuery;

	UPROPERTY(EditDefaultsOnly,Category="AI")
	TSubclassOf<AActor> MinionClass;

	UPROPERTY(EditDefaultsOnly, Category = "AI")
	TSubclassOf<AActor> HealthClass;

	UPROPERTY(EditDefaultsOnly,Category="AI")
	class UCurveFloat* DifficultyCurve;

	FTimerHandle TimerHandle_SpawnBots;

	UPROPERTY(EditDefaultsOnly,Category = "AI")
	float SpawnTimerInterval;

	UFUNCTION()
	void SpawnBotTimerElapsed();

	UFUNCTION()
	void SpawnHealth();

	UFUNCTION()
	void OnQueryCompleted(class UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus);

	UFUNCTION()
	void OnQueryEnd(class UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus);

public:

	ASGameModeBase();

public:
	virtual void StartPlay() override;

	UFUNCTION(Exec)
	void KillAll();

	UFUNCTION()
	void RespawnPlayerElapsed(AController* Controller);

public:
	virtual void OnActorKilled(AActor* VictimActor, AActor* Killer);
	
};

SGameModeBase.cpp

// Fill out your copyright notice in the Description page of Project Settings.
#include "SGameModeBase.h"
#include "EnvironmentQuery/EnvQueryManager.h"
#include "EnvironmentQuery/EnvQueryTypes.h"
#include "EnvironmentQuery/EnvQueryInstanceBlueprintWrapper.h"
#include "/APP/Tpl/Home/Default/Public/AI/SAICharacter.h"
#include "/APP/Tpl/Home/Default/Public/SAttributeComponent.h"
#include "../../../../../UE_5.1/Engine/Source/Runtime/Engine/Public/EngineUtils.h"
#include "SCharacter.h"
#include "SPlayerState.h"
#include "SHealthPotion.h"

static TAutoConsoleVariable<bool> CVarSpawnBots(TEXT("su.SpawnBots"),true,TEXT("Enable Spawing Bots via timer."), ECVF_Cheat);

void ASGameModeBase::SpawnBotTimerElapsed()
{
    //看到下面这个函数没,就是我们插入的函数(其实是我偷懒,懒得再写一个timer了)
	SpawnHealth();
	if (!CVarSpawnBots.GetValueOnGameThread())
	{
		return;
	}

	int32 NrOfAliveBots = 0;
	for (TActorIterator<ASAICharacter>It(GetWorld()); It; ++It)
	{
		ASAICharacter* Bot = *It;

		USAttributeComponent* AttributeComp = USAttributeComponent::GetArrtibutes(Bot);
		if (ensure(AttributeComp) && AttributeComp->IsAlive())
		{
			NrOfAliveBots++;
		}
	}

	float MaxBotCount = 10.0f;

	if (DifficultyCurve)
	{
		MaxBotCount = DifficultyCurve->GetFloatValue(GetWorld()->TimeSeconds);
	}

	if (NrOfAliveBots >= MaxBotCount)
	{
		return;
	}

	UEnvQueryInstanceBlueprintWrapper* QuetyInstance = UEnvQueryManager::RunEQSQuery(this,SpawnBotQuery,this,EEnvQueryRunMode::RandomBest5Pct,nullptr);

	if (ensure(QuetyInstance))
	{
		FScriptDelegate QueryCompleted;
		QueryCompleted.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("&ASGameModeBase::OnQueryCompleted")));

		QuetyInstance->GetOnQueryFinishedEvent().Add(QueryCompleted);
	}

	
}

void ASGameModeBase::SpawnHealth()
{
	int32 HealthExist = 0;
	for (TActorIterator<ASHealthPotion>It(GetWorld()); It; ++It)
	{
		HealthExist++;
	}
	float MaxHealth = 5;
	if (MaxHealth<=HealthExist)
	{
		return;
	}
	
	UEnvQueryInstanceBlueprintWrapper* QueryInstance = UEnvQueryManager::RunEQSQuery(this, SpawnHealthQuery, this, EEnvQueryRunMode::RandomBest25Pct, nullptr);

	if (ensure(QueryInstance))
		{
		FScriptDelegate QueryStop;
		QueryStop.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("&ASGameModeBase::OnQueryEnd")));
		QueryInstance->GetOnQueryFinishedEvent().Add(QueryStop);
	}
	
	
}

void ASGameModeBase::OnQueryCompleted(UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus)
{
	if (QueryStatus != EEnvQueryStatus::Success)
	{
		UE_LOG(LogTemp,Warning,TEXT("Spawn EQS Failed!!!"))
		return;
	}


	TArray<FVector> Locations = QueryInstance->GetResultsAsLocations();

	if (Locations.IsValidIndex(0))
	{
		GetWorld()->SpawnActor<AActor>(MinionClass,Locations[0],FRotator::ZeroRotator);
	}
}

void ASGameModeBase::OnQueryEnd(class UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus)
{
	if (QueryStatus != EEnvQueryStatus::Success)
	{
		UE_LOG(LogTemp, Warning, TEXT("Spawn EQS Failed!!!"))
			return;
	}
	TArray<FVector> Locations = QueryInstance->GetResultsAsLocations();

	if (Locations.IsValidIndex(0))
	{
		GetWorld()->SpawnActor<AActor>(HealthClass, Locations[0], FRotator::ZeroRotator);
	}
}

ASGameModeBase::ASGameModeBase()
{
	SpawnTimerInterval = 2.0f;
}

void ASGameModeBase::StartPlay()
{
	Super::StartPlay();

	GetWorldTimerManager().SetTimer(TimerHandle_SpawnBots, this, &ASGameModeBase::SpawnBotTimerElapsed, SpawnTimerInterval, true);
}

void ASGameModeBase::KillAll()
{
	for (TActorIterator<ASAICharacter>It(GetWorld()); It; ++It)
	{
		ASAICharacter* Bot = *It;

		USAttributeComponent* AttributeComp = USAttributeComponent::GetArrtibutes(Bot);
		if (ensure(AttributeComp) && AttributeComp->IsAlive())
		{
			AttributeComp->Kill(this);
		}
	}
}

void ASGameModeBase::RespawnPlayerElapsed(AController* Controller)
{
	if (ensure(Controller))
	{
		Controller->UnPossess();

		RestartPlayer(Controller);

		//重生会扣50点Credit
		ASPlayerState* ASP = Cast<ASPlayerState>(Controller->PlayerState);
		if (ASP)
		{
			ASP->AddCredit(-50.0f);
		}
	}
}

//玩家被杀后复活的逻辑
void ASGameModeBase::OnActorKilled(AActor* VictimActor, AActor* Killer)
{
	ASCharacter* Player = Cast<ASCharacter>(VictimActor);
	if (Player)
	{
		FTimerHandle TimerHandle_RespawnDelay;

		FTimerDelegate Delegate;

		Delegate.BindUFunction(this,"RespawnPlayerElapsed",Player->GetController());

		float RespawnDelay = 2.0f;
		GetWorldTimerManager().SetTimer(TimerHandle_RespawnDelay,Delegate, RespawnDelay,false);
	}
}

仿照之前写的那个机器人生成的方法,同时我们把生成的函数直接插入到我们timer结束就会执行的那个函数里头(这是个偷懒的方法),有点投机取巧不过很方便。文章来源地址https://www.toymoban.com/news/detail-530473.html

到了这里,关于UE5.1.1 C++从0开始(16.作业5思路分享)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索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)
  • 【虚幻引擎UE】UE5 模型导入卡死的解决思路

    1.数据分类,命名规范 2.尽量不用布尔工具 3.布线拓扑检查,检查重复面破面 4.模型坐标偏移不可以太大(否则大概率出错) 5.材质共用,不用vray材质工具 6.检查平滑组 7.检查模型分组 8.切三角面(尽量不要出现四边形) 方法一:将max文件拆分为多个fbx文件分别导入,每次及

    2023年04月08日
    浏览(216)
  • 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 C++(十七)— 射线检测

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

    2024年01月18日
    浏览(82)
  • 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++ UObject实例化

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

    2024年02月21日
    浏览(31)
  • UE5 C++ UENUM 和 USTRUCT

    一.首先在APawn里声明 UENUM 和 USTRUCT。UENUM 有两种定义方式 一种是使用命名空间: 还有是继承uint8: 通过申明class类 别名来替代 USTRUCT的定义 上面的第二种有类似但仍然有很多的差异: 首先要有GENERATED_USTRUCT_BODY()这个函数 并且参数要有 宏定义UPRPERTY 二.在 AMyPawn 里定义 En

    2024年02月22日
    浏览(32)
  • Ue5.1创建C++项目(Rider)

    1、下载地址 2、选择左侧“Visual Studio Community 2019” 3、选择这两个 4、单体里添加这几个: 注意最后一个选下边这个 5、下载完成后到这个目录 将原来的14.29.30133文件夹重复名,改成14.29.30136,否则报错 整整baidu、google了1天,网上都没有解决办法 Unable to find valid 14.29.30136 too

    2024年02月02日
    浏览(40)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包