Lyra学习笔记2 GFA_AddComponents与ULyraPlayerSpawningManagerComponent

目录

  • 前言
  • GameFeatureAction_AddComponents
  • ULyraPlayerSpawningManagerComponent
    • 缓存所有PlayerStart位置
    • 选择位置

前言

1.以control模式为例
2.比较散,想单独拿出一篇梳理下Experience的流程

GameFeatureAction_AddComponents

这部分建议看
《InsideUE5》GameFeatures架构(五)AddComponents
这里写的内容相当于是我跟着走了一遍

Lyra中角色基本类ALyraCharacter类似于一个框架,负责转发事件给其组件,组件实现相关功能,所以ALyraCharacter甚至只有几百行(在这个不算小的项目里这真的算短了(我觉得))。

在研究生成角色流程之前,我想先研究一下GameFeatureAction中的AddComponents,帮助之后的理解。

在加载Experience的过程中,执行到ULyraExperienceManagerComponent::OnExperienceLoadComplete时会激活GameFeature,以AddComponents为例,一直到OnGameFeatureActivating的调用栈如图:
在这里插入图片描述
而在OnGameFeatureActivating中都会调用到AddToWorld
前面经过一些World,客户端服务端之类的判断后,执行逻辑在如下的一行:

void UGameFeatureAction_AddComponents::AddToWorld(const FWorldContext& WorldContext, FContextHandles& Handles) {... 
Handles.ComponentRequestHandles.Add(GFCM->AddComponentRequest(Entry.ActorClass, ComponentClass, static_cast<EGameFrameworkAddComponentFlags>(Entry.AdditionFlags))); 
... 
}

GFCM::AddComponentRequest

TSharedPtr<FComponentRequestHandle> UGameFrameworkComponentManager::AddComponentRequest(const TSoftClassPtr<AActor>& ReceiverClass, TSubclassOf<UActorComponent> ComponentClass, const EGameFrameworkAddComponentFlags AdditionFlags)
{// You must have a receiver and component class. The receiver cannot be AActor, that is too broad and would be bad for performance.if (!ensure(!ReceiverClass.IsNull()) || !ensure(ComponentClass) || !ensure(ReceiverClass.ToString() != TEXT("/Script/Engine.Actor"))){return nullptr;}//一些检查FComponentRequestReceiverClassPath ReceiverClassPath(ReceiverClass);UClass* ComponentClassPtr = ComponentClass.Get();FComponentRequest NewRequest;NewRequest.ReceiverClassPath = ReceiverClassPath;NewRequest.ComponentClass = ComponentClassPtr;// Add a request if there is not an already existing one. Note that it will only uses the receiver and component class to check for uniqueness, not the addition flags.int32& RequestCount = RequestTrackingMap.FindOrAdd(NewRequest);RequestCount++;if (RequestCount == 1)//第一次匹配{EGameFrameworkAddComponentResult Result = EGameFrameworkAddComponentResult::Failed;auto& RequestInfoSet = ReceiverClassToComponentClassMap.FindOrAdd(ReceiverClassPath);RequestInfoSet.Add({ ComponentClassPtr, AdditionFlags } );if (UClass* ReceiverClassPtr = ReceiverClass.Get()){UGameInstance* LocalGameInstance = GetGameInstance();if (ensure(LocalGameInstance)){UWorld* LocalWorld = LocalGameInstance->GetWorld();if (ensure(LocalWorld)){for (TActorIterator<AActor> ActorIt(LocalWorld, ReceiverClassPtr); ActorIt; ++ActorIt)//遍历场景中的Actor{if (ActorIt->IsActorInitialized())//调用过BeginPlay{
#if WITH_EDITORif (!ReceiverClassPtr->HasAllClassFlags(CLASS_Abstract)){ensureMsgf(AllReceivers.Contains(*ActorIt), TEXT("You may not add a component request for an actor class that does not call AddReceiver/RemoveReceiver in code! Class:%s"), *GetPathNameSafe(ReceiverClassPtr));}
#endifResult = CreateComponentOnInstance(*ActorIt, ComponentClass, AdditionFlags);//创建组件}}}}}else{// Actor class is not in memory, there will be no actor instances}return MakeShared<FComponentRequestHandle>(this, ReceiverClass, ComponentClass);}return nullptr;
}
EGameFrameworkAddComponentResult UGameFrameworkComponentManager::CreateComponentOnInstance(AActor* ActorInstance, TSubclassOf<UActorComponent> ComponentClass, const EGameFrameworkAddComponentFlags AdditionFlags)
{...UActorComponent* NewComp = NewObject<UActorComponent>(ActorInstance, ComponentClass, NewComponentName);...
}

一些细节原文写的很好《InsideUE5》GameFeatures架构(五)AddComponents

ULyraPlayerSpawningManagerComponent

总结一下目前为止的流程:

读取WordSetting中的Experience->
GameState中的ULyraExperienceManagerComponent加载Experience->
激活Experience中配置的GameFeature->
执行Actions

Control关卡中的B_LyraShooterGame_ControlPoints(Experience)的Actions中,
有添加组件的Action,其中配置了在LyraGameState中添加ULyraPlayerSpawningManagerComponent,这个组件负责了管理生成位置。

缓存所有PlayerStart位置

void ULyraPlayerSpawningManagerComponent::InitializeComponent()
{Super::InitializeComponent();UE_LOG(LogTemp,Warning,TEXT("LAPI: ULyraPlayerSpawningManagerComponent::InitializeComponent"));FWorldDelegates::LevelAddedToWorld.AddUObject(this, &ThisClass::OnLevelAdded);UWorld* World = GetWorld();World->AddOnActorSpawnedHandler(FOnActorSpawned::FDelegate::CreateUObject(this, &ThisClass::HandleOnActorSpawned));for (TActorIterator<ALyraPlayerStart> It(World); It; ++It){if (ALyraPlayerStart* PlayerStart = *It){CachedPlayerStarts.Add(PlayerStart);}}
}

直接看后半部分可知缓存了场景中所有的PlayerStart。
再来看OnLevelAdded这个函数:

void ULyraPlayerSpawningManagerComponent::OnLevelAdded(ULevel* InLevel, UWorld* InWorld)
{if (InWorld == GetWorld()){for (AActor* Actor : InLevel->Actors){if (ALyraPlayerStart* PlayerStart = Cast<ALyraPlayerStart>(Actor)){ensure(!CachedPlayerStarts.Contains(PlayerStart));CachedPlayerStarts.Add(PlayerStart);}}}
}

这里是新的Level被AddToWorld的时候调用的,以实现更新PlayerStart,从L_DefaultEditorOverview到L_Convolution_Blockout并不会触发,因为是加载组件之后才绑定的。
同理HandleOnActorSpawned是负责处理动态生成的PlayerStart的。

选择位置

加载完地图资源后,GameMode会将ChoosePlayerStart转到SpawningManagerComponent的ChoosePlayerStart函数:
在这里插入图片描述
Choose函数比较长

AActor* ULyraPlayerSpawningManagerComponent::ChoosePlayerStart(AController* Player)
{if (Player){
#if WITH_EDITORif (APlayerStart* PlayerStart = FindPlayFromHereStart(Player)){return PlayerStart;}
#endif//这部分处理编辑器中PlayFromHere的PlayerStartPIE的特殊情况TArray<ALyraPlayerStart*> StarterPoints;for (auto StartIt = CachedPlayerStarts.CreateIterator(); StartIt; ++StartIt){if (ALyraPlayerStart* Start = (*StartIt).Get()){StarterPoints.Add(Start);}else{StartIt.RemoveCurrent();}}//处理完后StarterPoints存的是安全的强引用if (APlayerState* PlayerState = Player->GetPlayerState<APlayerState>()){// start dedicated spectators at any random starting location, but they do not claim itif (PlayerState->IsOnlyASpectator()){if (!StarterPoints.IsEmpty()){return StarterPoints[FMath::RandRange(0, StarterPoints.Num() - 1)];}return nullptr;}}//若是Spectators在数组内随机一个位置返回AActor* PlayerStart = OnChoosePlayerStart(Player, StarterPoints);//返回nullptrif (!PlayerStart)//若为nullptr,暂时必然为nullptr{PlayerStart = GetFirstRandomUnoccupiedPlayerStart(Player, StarterPoints);//若有未占用,则在其中随机一个,若没有就在已经占用的随机一个}if (ALyraPlayerStart* LyraStart = Cast<ALyraPlayerStart>(PlayerStart)){LyraStart->TryClaim(Player);//尝试占用}return PlayerStart;}return nullptr;
}

待续…

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

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

相关文章

进程生命周期

进程生命周期 Linux是多任务操作系统&#xff0c;系统中的每个进程能够分时复用CPU时间片&#xff0c;通过有效的进程调度策略实现多任务并行执行。进程在被CPU调度运行&#xff0c;等待CPU资源分配以及等待外部事件时会处于不同的状态。进程状态如下&#xff1a; 创建状态&a…

文字转图片的字符画生成工具

软件介绍 今天要介绍的这款软件可以将文字转换成图片的排列形式&#xff0c;非常适合需要将文字图形化的场景&#xff0c;建议有需要的朋友收藏。 软件名称与用途 这款软件名为《字符画大师》&#xff0c;是一款在网吧等场所非常流行的聊天辅助工具&#xff0c;其主要功能就…

历年南京大学计算机保研上机真题

2025南京大学计算机保研上机真题 2024南京大学计算机保研上机真题 2023南京大学计算机保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/school Count Number of Binary Strings 题目描述 Given a positive integer n n n ( 3 ≤ n ≤ 90 3 \leq n \leq 90 3≤n≤…

王树森推荐系统公开课 排序06:粗排模型

shared bottom 表示神经网络被所有特征共享。精排模型主要开销在神经网络&#xff0c;神经网络很大且很复杂。 每做一次推荐&#xff0c;用户塔只做一次推理。物品塔存放入向量数据库。 后期融合模型常用于召回&#xff0c;前期融合模型常用于精排。 物品塔短时间内比较稳…

VSCode的下载与安装(2025亲测有效)

目录 0 前言1 下载2 安装3 后记 0 前言 丫的&#xff0c;谁懂啊&#xff0c;尝试了各种办法不行的话&#xff0c;我就不得不拿出我的最后绝招了&#xff0c;卸载&#xff0c;重新安装&#xff0c;我经常要重新安装&#xff0c;所以自己写了一个博客&#xff0c;给自己&#xf…

端午节互动网站

端午节互动网站 项目介绍 这是一个基于 Vue 3 Vite 开发的端午节主题互动网站&#xff0c;旨在通过有趣的交互方式展示中国传统端午节文化。网站包含三个主要功能模块&#xff1a;端午节介绍、互动包粽子游戏和龙舟竞赛游戏。 预览网站&#xff1a;https://duanwujiekuaile…

Python+requests+pytest接口自动化测试框架的搭建(全)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 框架的设计思路 首先要明确进行接口自动化需要的步骤&#xff0c;如下图所示&#xff1a; 然后逐步拆解需要完成的工作&#xff1a; 1&#xff09;了解分析需求&…

OpenCV视觉图片调整:从基础到实战的技术指南

引言:数字图像处理的现代意义与OpenCV深度应用 在人工智能与计算机视觉蓬勃发展的今天,图像处理技术已成为多个高科技领域的核心支撑。根据市场研究机构Grand View Research的数据,全球计算机视觉市场规模预计将从2022年的125亿美元增长到2030年的253亿美元,年复合增长率达…

JS手写代码篇---手写节流函数

8、节流函数 什么是节流函数&#xff1f; 指规定一个单位时间&#xff0c;在这个单位时间内&#xff0c;只能有一次触发事件的回调函数执行&#xff0c;如果在同一个单位时间内某事件被触发多次&#xff0c;只有一次能生效。 与防抖函数有什么区别&#xff1f; 防抖函数是延…

2025年05月30日Github流行趋势

项目名称&#xff1a;agenticSeek 项目地址url&#xff1a;https://github.com/Fosowl/agenticSeek项目语言&#xff1a;Python历史star数&#xff1a;13040今日star数&#xff1a;1864项目维护者&#xff1a;Fosowl, steveh8758, klimentij, ganeshnikhil, apps/copilot-pull-…

node_modules包下载不下来

如果项目里面的package-lock.json有resolved &#xff0c;就指向了包的下载来源&#xff0c;如果这个网址挂了&#xff0c;那npm i 就会一直卡着。而且&#xff0c;在终端去修改 npm的镜像是没有用的 解决办法是:把项目里面的 lock文件 .npmrc都删了 然后重新下载就可以了

OramaCore 是您 AI 项目、答案引擎、副驾驶和搜索所需的 AI 运行时。它包括一个成熟的全文搜索引擎、矢量数据库、LLM界面和更多实用程序

一、软件介绍 文末提供程序和源码下载 OramaCore 是您的项目、答案引擎、副驾驶和搜索所需的 AI 运行时。 它包括一个成熟的全文搜索引擎、矢量数据库、LLM具有行动计划和推理功能的接口、用于根据数据编写和运行您自己的自定义代理的 JavaScript 运行时&#xff0c;以及更多…

小白成长之路-计算机网络(四)

文章目录 前言一、网络连接查看1.netstat2.ss3.bond绑定3.1准备好这三个文件3.2添加bond配置文件3.3关闭网络图形化服务3.4重启 4.Linux下的抓包工具Wireshark 5、web压力测试工具6、路由追踪命令 二、[练习题](https://blog.csdn.net/m0_70730767/article/details/148262716?…

CppCon 2014 学习:Lock-Free Programming

你这段文字讲的是“为什么要使用无锁&#xff08;Lock-Free&#xff09;代码”&#xff0c;我帮你总结并解释一下&#xff1a; 为什么选择无锁代码&#xff1f; 并发性和可扩展性&#xff08;Concurrency and scalability&#xff09; 无锁算法允许多个线程同时操作共享数据&a…

Proteus寻找元器件(常见)

汇总&#xff1a; 1 主控芯片 STM32系列&#xff08;32位&#xff09; AT89C51&#xff08;51系列&#xff09; 2显示模块 OLED 3 按键 Button 4 电阻电容 Res&#xff08;电阻&#xff09; Cap&#xff08;电容&#xff09; 5 驱动模块 L298N&#xff08;电机驱动芯片&am…

vue+threeJs 绘制3D圆形

嗨&#xff0c;我是小路。今天主要和大家分享的主题是“vuethreeJs 绘制圆形”。 今天找到一个用three.js绘制图形的项目&#xff0c;主要是用来绘制各种形状。 项目案例示意图 1.THREE.ShapeGeometry 定义&#xff1a;是 Three.js 中用于从 2D 路径形状&#xff08…

macOS烧录stm32程序初步成功

完整总结&#xff1a;STM32H7 项目编译与烧录流程&#xff08;macOS OpenOCD/GDB&#xff09; 1️⃣ 编译工程 在项目目录下执行 make&#xff0c;生成 ELF 文件&#xff08;如 Blink.elf&#xff09;&#xff1a; cd /Users/code/Stm32code/Blink/build make clean # 可选…

正则表达式的修饰符

修饰符 修饰符不写在正则表达式里&#xff0c;标记位于表达式之外 /正则表达式/修饰符gglobal - 全局匹配 查找所有的匹配项。 i i (ignore case) - 忽略大小写 示例&#xff1a;/abc/i 可以匹配 "abc", "Abc", "ABC" 等

JS浮点数精度问题

在JavaScript开发中&#xff0c;浮点数精度问题是一个常见的陷阱。本文将深入探讨JavaScript中浮点数精度问题的原因、影响以及解决方案。 一、浮点数精度常见问题 &#xff08;一&#xff09;加法运算 console.log(0.1 0.2); // 0.30000000000000004 console.log(0.7 0.1…

本地Markdown开源知识库选型指南

本地Markdown开源知识库选型指南 以下是几款优秀的本地Markdown开源知识库解决方案&#xff0c;适合不同需求场景&#xff1a; 1. Obsidian (非完全开源但免费) 特点&#xff1a;基于Markdown的本地优先知识管理&#xff0c;丰富的插件生态优势&#xff1a;双向链接、图形视…