UE求职Demo开发日志#23 线性任务系统数据层实现

1 按上期设计创建数据结构(做了一些修改)

USTRUCT(BlueprintType)
struct ARPG_CPLUS_API FQuestNode
{GENERATED_USTRUCT_BODY()// 记录前置节点IDUPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNode")TArray<int> PredecessorNodeIDs;// 区分检查前置条件类型(任意一个完成或全部完成)UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNode")bool bRequireAllPredecessors;// 记录唯一后置节点IDUPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNode")int SuccessorNodeID;// 记录当前节点IDUPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNode")int NodeID;// 标记是否完成UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNode")bool bIsCompleted;
};
// 任务条件检查结构
USTRUCT(BlueprintType)
struct ARPG_CPLUS_API FQuestCondition
{GENERATED_USTRUCT_BODY()// 当前值UPROPERTY(EditAnywhere, BlueprintReadWrite)float CurrentValue;// 需要达到的值UPROPERTY(EditAnywhere, BlueprintReadWrite)float NeededValue;// 物品ID,0表示空信息UPROPERTY(EditAnywhere, BlueprintReadWrite)int ItemID{0};// 描述文本(可以为空)UPROPERTY(EditAnywhere, BlueprintReadWrite)FString DescriptionText;
};
USTRUCT(BlueprintType)
struct ARPG_CPLUS_API FQuestNodeData : public FTableRowBase
{GENERATED_USTRUCT_BODY()// 当前节点IDUPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNodeData")int NodeID;// 任务提示文本UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNodeData")FString QuestHintText;// 任务条件检查类型UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNodeData")EQuestType QuestType{EQuestType::None};// 任务条件检查结构数组UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestNodeData")TArray<FQuestCondition> Conditions;
};
USTRUCT(BlueprintType)
struct ARPG_CPLUS_API FQuestStructure : public FTableRowBase
{GENERATED_USTRUCT_BODY()// 任务IDUPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestStructure")int QuestID;// 当前正在执行的任务节点IDUPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestStructure")int CurrentNodeID;// 任务节点数组UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestStructure")TArray<FQuestNode> QuestNodes;// 结尾任务节点ID数组(任意一个完成即整个任务完成)UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="QuestStructure")TArray<int> EndNodeIDs;
};

2 创建对应的DataTable

 3 实现任务逻辑

3.1 创建变量记录任务

UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category="QuestManagerComponent")
TArray<FQuestStructure> CurrentQuests{};UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category="QuestManagerComponent")
TArray<FQuestNodeData> CurrentQuestNodes{};UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category="QuestManagerComponent")
TArray<FQuestStructure> CompletedQuests{};

3.2 要用到的执行函数

。。太多了请看VCR 

// Fill out your copyright notice in the Description page of Project Settings.#include "Quest/QuestManagerComponent.h"// Sets default values for this component's properties
UQuestManagerComponent::UQuestManagerComponent()
{// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features// off to improve performance if you don't need them.PrimaryComponentTick.bCanEverTick = true;// 加载 DataTablestatic ConstructorHelpers::FObjectFinder<UDataTable> QuestStructureDataTableFinder(TEXT("/Game/Data/DataTable/QuestStructureDataTable.QuestStructureDataTable"));if (QuestStructureDataTableFinder.Succeeded()){QuestStructureDataTable = QuestStructureDataTableFinder.Object;}// 加载 DataTablestatic ConstructorHelpers::FObjectFinder<UDataTable> QuestNodeDataTableFinder(TEXT("/Game/Data/DataTable/QuestNodeDataTable.QuestNodeDataTable"));if (QuestNodeDataTableFinder.Succeeded()){QuestNodeDataTable = QuestNodeDataTableFinder.Object;}// ...
}// Called when the game starts
void UQuestManagerComponent::BeginPlay()
{Super::BeginPlay();LogCurrentQuests();LogCurrentQuestNodesData();AcceptQuest(1);LogCurrentQuests();LogCurrentQuestNodesData();if(CurrentQuestNodesData.Num() >= 1){for(auto& t:CurrentQuestNodesData[0].Conditions){t.CurrentValue=t.NeededValue;}}UE_LOG(LogTemp,Warning,TEXT("CheckQuestNodeCompleted(1)==%d"),CheckQuestNodeCompleted(1));//CompleteQuest(1);LogCurrentQuests();LogCurrentQuestNodesData();// ...
}// Called every frame
void UQuestManagerComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{Super::TickComponent(DeltaTime, TickType, ThisTickFunction);// ...
}bool UQuestManagerComponent::AcceptQuest(int QuestId)
{if(!QuestStructureDataTable||!QuestNodeDataTable)return false;//DataTable无效返回falseTArray<FName> QuestStructureRowNames= QuestStructureDataTable->GetRowNames();for (const auto& RowName : QuestStructureRowNames){FQuestStructure* RowData = QuestStructureDataTable->FindRow<FQuestStructure>(RowName,FString(""),true);if(RowData->QuestID==QuestId)//找到对应的任务{AddToCurrentQuestsWithoutRepeat(*RowData);//添加到现有任务数组if(RowData->QuestNodes.Num()>0){TArray<FName> QuestNodeDataRowNames= QuestNodeDataTable->GetRowNames();for(FQuestNode QuestNode : RowData->QuestNodes)//遍历当前任务里的所有任务节点{for (const auto& QuestNodeDataRowName : QuestNodeDataRowNames){FQuestNodeData* QuestNodeDataRowData=QuestNodeDataTable->FindRow<FQuestNodeData>(QuestNodeDataRowName,FString(""),true);if(QuestNodeDataRowData&&QuestNodeDataRowData->NodeID==QuestNode.NodeID)//找到任务节点数据{AddToCurrentQuestNodesDataWithoutRepeat(*QuestNodeDataRowData);//添加到任务数据数组break;}}}}return true;}}return false;
}bool UQuestManagerComponent::AddToCurrentQuestsWithoutRepeat(FQuestStructure StructureToAdd)
{for(FQuestStructure QuestStructure:CurrentQuests){if(QuestStructure.QuestID==StructureToAdd.QuestID){return false;}}CurrentQuests.Add(StructureToAdd);return true;
}bool UQuestManagerComponent::AddToCurrentQuestNodesDataWithoutRepeat(FQuestNodeData NodeDataToAdd)
{for(FQuestNodeData QuestNodeData : CurrentQuestNodesData){if(QuestNodeData.NodeID==NodeDataToAdd.NodeID){return false;}}CurrentQuestNodesData.Add(NodeDataToAdd);return true;
}void UQuestManagerComponent::LogCurrentQuestNodesData()
{UE_LOG(LogTemp,Warning,TEXT("LogCurrentQuestNodesData-->Start,Num==%d"),CurrentQuestNodesData.Num());for(FQuestNodeData QuestNodeData:CurrentQuestNodesData){UE_LOG(LogTemp,Warning,TEXT("Quest Node Id: %d"),QuestNodeData.NodeID);UE_LOG(LogTemp,Warning,TEXT("Quest Node QuestHintText: %s"),*QuestNodeData.QuestHintText);UE_LOG(LogTemp,Warning,TEXT("Quest Node QuestType: %d"),QuestNodeData.QuestType);for(FQuestCondition QuestCondition:QuestNodeData.Conditions){UE_LOG(LogTemp,Warning,TEXT("Quest Node Condition:CurrentValue==%f NeededValue==%f itemID==%d DescriptionText==%s"),QuestCondition.CurrentValue,QuestCondition.NeededValue,QuestCondition.ItemID,*QuestCondition.DescriptionText);}}UE_LOG(LogTemp,Warning,TEXT("LogCurrentQuestNodesData-->End"));
}void UQuestManagerComponent::LogCurrentQuests()
{UE_LOG(LogTemp,Warning,TEXT("LogCurrentQuests-->Start,Num==%d"),CurrentQuests.Num());for(FQuestStructure QuestStructure:CurrentQuests){UE_LOG(LogTemp,Warning,TEXT("Quest Id: %d"),QuestStructure.QuestID);UE_LOG(LogTemp,Warning,TEXT("Quest CurrentNodeID: %d"),QuestStructure.CurrentNodeID);for(FQuestNode QuestNode:QuestStructure.QuestNodes){UE_LOG(LogTemp,Warning,TEXT("Quest NodeID:%d"),QuestNode.NodeID);}for(int endid:QuestStructure.EndNodeIDs){UE_LOG(LogTemp,Warning,TEXT("Quest EndNodeID:%d"),endid);}}UE_LOG(LogTemp,Warning,TEXT("LogCurrentQuests-->End"));
}bool UQuestManagerComponent::CompleteQuest(int QuestId)
{for(int index=0;index<CurrentQuests.Num();index++){if(CurrentQuests[index].QuestID==QuestId){CurrentQuests.RemoveAt(index);//暂时不移除QuestNodesDatareturn true;}}return false;
}bool UQuestManagerComponent::CheckQuestNodeCompleted(int QuestNodeID)
{for(const auto& QuestNodeData:CurrentQuestNodesData){if(QuestNodeData.NodeID==QuestNodeID){for(const auto& QuestCondition:QuestNodeData.Conditions){if(QuestCondition.CurrentValue<QuestCondition.NeededValue||QuestCondition.CurrentValue==0){return false;}}return true;//所有条件均CurrentValue>=NeededValue}}//没找到指定id返回falsereturn false;
}

4 测试

测试代码:

void UQuestManagerComponent::BeginPlay()
{Super::BeginPlay();LogCurrentQuests();LogCurrentQuestNodesData();AcceptQuest(1);LogCurrentQuests();LogCurrentQuestNodesData();if(CurrentQuestNodesData.Num() >= 1){for(auto& t:CurrentQuestNodesData[0].Conditions){t.CurrentValue=t.NeededValue;}}UE_LOG(LogTemp,Warning,TEXT("CheckQuestNodeCompleted(1)==%d"),CheckQuestNodeCompleted(1));CompleteQuest(1);LogCurrentQuests();LogCurrentQuestNodesData();// ...
}

读取前:

接受任务1后:

 手动完成任务节点1的任务:

	if(CurrentQuestNodesData.Num() >= 1){for(auto& t:CurrentQuestNodesData[0].Conditions){t.CurrentValue=t.NeededValue;}}

此时check任务节点1:

UE_LOG(LogTemp,Warning,TEXT("CheckQuestNodeCompleted(1)==%d"),CheckQuestNodeCompleted(1));

 之后完成任务,看到已被清除:

这里写的完成任务是最终调用,不能直接调用,要包装条件检查

5 (补充)任务面板数据显示,提交任务测试

//TODO:

//1.任务数据持久化

//2.对外提供修改指定任务节点的Value的接口

//3.完成任务后加入已完成队列,记录所有完成任务信息

//4.按照任务类型细化UI显示,比如item类任务显示item图标等信息

//5.添加任务奖励,并在任务完成时获得物品或者执行其他逻辑

        这里的UI设计的是动态的,全部绑定了任务系统的信息,更新信息写在了函数里,手动调用

测试的时候手动把完成条件全部满足了,大部分时间用来实现了,这里就不多写实现过程了,就是获取数据->显示数据。

提交函数:

若通过检查并且是EndNode里的任意一个,完成整个任务

若通过检查但不是EndNode里的,设置CurrentNodeID为后继节点ID

bool UQuestManagerComponent::TryCommitQuestCurrentNode(int QuestId)
{for(auto& Quest:CurrentQuests){if(Quest.QuestID==QuestId){if(CheckQuestNodeCompleted(Quest.CurrentNodeID)){if(Quest.EndNodeIDs.Contains(Quest.CurrentNodeID)){UE_LOG(LogTemp,Warning,TEXT("TryCommitQuestCurrentNode-->Success!CompletedId: %d,QuestId:%d Completed"),Quest.CurrentNodeID,QuestId);CompleteQuest(QuestId);return true;}UE_LOG(LogTemp,Warning,TEXT("TryCommitQuestCurrentNode-->Success!CompletedId: %d"),Quest.CurrentNodeID);Quest.CurrentNodeID=GetQuestNodeByNodeID(Quest,Quest.CurrentNodeID).SuccessorNodeID;UE_LOG(LogTemp,Warning,TEXT("NextId: %d"),Quest.CurrentNodeID);return true;}UE_LOG(LogTemp,Warning,TEXT("TryCommitQuestCurrentNode-->Failed Because Check is False."));return false;}}UE_LOG(LogTemp,Warning,TEXT("TryCommitQuestCurrentNode-->Failed Because QuestID is Not Found."));return false;
}

初始(代码里接取了任务1,按钮绑定了提交任务1函数):

 提交一次后:

提交两次后,因为属于整个任务的结尾Node,因此任务完成: 

 输出:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/13457.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql8安装时提示-缺少Microsoft Visual C++ 2019 x64 redistributable

MySQL8.0安装包mysql-8.0.1-winx64进行安装&#xff0c;提示&#xff1a;This application requires Visual Studio 2019 x64Redistributable, Please install the Redistributable then runthis installer again。出现这个错误是因为我们电脑缺少Microsoft Visual C 这个程序&…

K8s 分布式存储后端(K8s Distributed Storage Backend)

K8s 分布式存储后端 在 K8s 中实现分布式存储后端对于管理跨集群的持久数据、确保高可用性、可扩展性和可靠性至关重要。在 K8s 环境中&#xff0c;应用程序通常被容器化并跨多个节点部署。虽然 K8s 可以有效处理无状态应用程序&#xff0c;但有状态应用程序需要持久存储来维护…

生产环境超实用shell脚本一

生产环境超实用shell脚本一 Shell脚本作为一种强大的自动化工具&#xff0c;能够帮助运维人员轻松应对各种复杂的任务。 本文将为您介绍服务器健康检查、日志清理、备份以及监控等多个方面&#xff0c;并详细阐述每个脚本的功能和应用场景&#xff0c;助力您提升运维效率&…

IM 即时通讯系统-46-OpenIM 提供了专为开发者设计的开源即时通讯解决方案

IM 开源系列 IM 即时通讯系统-41-开源 野火IM 专注于即时通讯实时音视频技术&#xff0c;提供优质可控的IMRTC能力 IM 即时通讯系统-42-基于netty实现的IM服务端,提供客户端jar包,可集成自己的登录系统 IM 即时通讯系统-43-简单的仿QQ聊天安卓APP IM 即时通讯系统-44-仿QQ即…

spy-debugger + Charles 调试移动端/内嵌小程序H5

简介说明&#xff1a; PC端可以用F12进行console等进行调试&#xff0c;但移动端App中使用webview就无法进行实时调试&#xff0c;针对这种情况 1. 安装 全局安装 spy-debugger sudo npm install spy-debugger -g // window不用加sudo2. spy-debugger 证书 其实spy-debugg…

深度整理总结MySQL——SQL的执行顺序和流程

SQL的执行顺序和流程 SQL的执行顺序执行一条select语句,发生了什么呢连接器查询缓存解析SQL执行SQL预处理器优化器执行器 总结 SQL的执行顺序 这是一条标准的查询语句: 但实际上并不是从上到下去解析的,真实的执行顺序是: 我们先执行from,join来确定表之间的连接关系&#x…

使用 Ollama 在 Windows 环境部署 DeepSeek 大模型实战指南

文章目录 前言Ollama核心特性 实战步骤安装 Ollama验证安装结果部署 DeepSeek 模型拉取模型启动模型 交互体验命令行对话调用 REST API 总结个人简介 前言 近年来&#xff0c;大语言模型&#xff08;LLM&#xff09;的应用逐渐成为技术热点&#xff0c;而 DeepSeek 作为国产开…

Redis有哪些常用应用场景?

大家好&#xff0c;我是锋哥。今天分享关于【Redis有哪些常用应用场景?】面试题。希望对大家有帮助&#xff1b; Redis有哪些常用应用场景? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis 是一个高性能的键值对存储数据库&#xff0c;它有许多应用场景&…

115,【7】 攻防世界 web fileinclude

进入靶场 试着访问了几个文件&#xff0c;都没得到信息&#xff0c;f12看看源码 还真有 <?php // 检查是否开启了错误显示功能 // ini_get 函数用于获取 PHP 配置选项的值&#xff0c;这里检查 display_errors 选项是否开启 if( !ini_get(display_errors) ) {// 如果错误…

SpringBoot开发(五)SpringBoot接收请求参数

1. SpringBoot接收请求参数 1.1. 获取参数的方式 &#xff08;1&#xff09;通过request对象获取参数   &#xff08;2&#xff09;RequestParam(针对请求头方式为x-www-form-ur lencoded)   &#xff08;3&#xff09;RequestBody(针对请求头方式为application/json)   …

如何理解多态,以及由此引出的抽象类和纯虚函数

文章目录 1. 多态2. 抽象类和纯虚函数 1. 多态 静态多态&#xff1a; 动态多态&#xff1a; #include <iostream> #include <string> using namespace std;// 动物的基类 class Animal { public:Animal(string name) : _name(name) {}virtual void bark() {} …

java基础2(黑马)

一、变量里的数据在计算机中的存储原理 1.二进制 .二进制&#xff1a;只有0、1&#xff0c; 按照逢二进一的方式表示数据。 十进制数字11转换为&#xff1a;1011 方法&#xff1a;除二取余法 计算机中表示数据的最小单元&#xff0c;一个字节&#xff08;Byte&#xff0c;简…

【算法篇】贪心算法

目录 贪心算法 贪心算法实际应用 一&#xff0c;零钱找回问题 二&#xff0c;活动选择问题 三&#xff0c;分数背包问题 将数组和减半的最小操作次数 最大数 贪心算法 贪心算法&#xff0c;是一种在每一步选择中都采取当前状态下的最优策略&#xff0c;期望得到全局最优…

数据结构与算法学习笔记----博弈论

# 数据结构与算法学习笔记----博弈论 author: 明月清了个风 first publish time: 2025.2.6 ps⭐️包含了博弈论中的两种问题Nim游戏和SG函数&#xff0c;一共四道例题&#xff0c;给出了具体公式的证明过程。 Acwing 891. Nim游戏 [原题链接](891. Nim游戏 - AcWing题库) 给…

Yageo国巨的RC系列0402封装1%电阻库来了

工作使用Cadence多年&#xff0c;很多时候麻烦的就是整理BOM&#xff0c;因为设计原理图的时候图省事&#xff0c;可能只修改value值和封装。 但是厂家&#xff0c;规格型号&#xff0c;物料描述等属性需要在最后的时候一行一行的修改&#xff0c;繁琐又容易出错&#xff0c;过…

app专项测试(网络测试流程)

一、网络测试的一般流程 step1&#xff1a;首先要考虑网络正常的情况 ① 各个模块的功能正常可用 ② 页面元素/数据显示正常 step2&#xff1a;其次要考虑无网络的情况 ① APP各个功能在无网络情况下是否可用 ② APP各个页面之间切换是否正常 ③ 发送网络请求时是…

RFID隧道机:提升生产流水线效率与精准度

在当今制造业飞速发展的时代&#xff0c;生产流水线的效率与精准度成为企业竞争力的关键。传统的货物管理往往依赖于人工扫描和记录&#xff0c;效率低下且易出错&#xff0c;而RFID 隧道机的出现&#xff0c;为企业带来了智能化的管理体验&#xff0c;为生产流水线带来了从人工…

NSS-DAY2

Crypto [HNCTF 2022 Week1]A dictator 题目&#xff1a; from random import randint from secret import flagoffset randint(1,100) % 26 # print(offset)assert flag.startswith(NSSCTF{) assert all([ord(c) not in range(ord(A),ord(Z)) for c in flag[7:-1]])for cha…

systemctl配置httpd服务

一、环境介绍&#xff1a; Operating SystemopenEuler 22.03 (LTS-SP2)Kernel Linux 5.10.0-153.56.0.134.oe2203sp2.x86_64httpd versionhttpd-2.4.59ip address192.168.240.12/24 二、下载需要的软件包 yum install -y gcc gcc-c make apr apr-devel apr-util-devel pcre …

Redis bitmap应用

Redis bitmap应用 需求&#xff1a;存储用户今年已签到的天数&#xff0c;如在1月3日签到&#xff0c;则存 3 。。。以此类推 每秒300次请求压力测试 1、使用数据库存储 查询代码与时间 public List<Integer> selectSignRecord(long userId, Integer year) {if (year nu…