【UE5 刺客信条动态地面复刻】实现无界地面01:动态生成

2024.6.4更新

昨天半夜意识到生成Cube的方案不合适,又开始到处找动态地面的方法,发现了我想要的效果直接可以用nigara实现!!!!

于是这个部分就暂时告一段落,今季开始新的方向的学习。


为了快速上手UE5,开启了《复刻刺客信条动态地面》的技术篇章,最终希望复刻刺客信条等待界面的效果,这个效果大体上包括:

基础的地面随着任务走动消失和出现的基础效果+地板的Bloom和竖起的面片辉光效果

既然是新手,,必然是先抄再学再举一反三!(不是),实现基础无界地面参考教程:【永昼UE】【技の屋】无界地面_哔哩哔哩_bilibili

特别说明:由于本人的学习习惯------遇到什么问题/甚至是简单的知识点都会在过程中记录下来,因此这一系列博客仅仅是学习笔记,并不是严格意义上的实现教程。

UE版本:5.0.3


主要逻辑都在PlayerController写:

1 获取玩家Tiling后的位置 GetPlayerTilingCoord()

1.1 蓝图实现逻辑

干的事情很简单:获取当前玩家位置,并跟地板做对应的Tiling处理(创建了TilingXY变量,跟地面大小保持同步,事实上做任何跟WorldPos有关的效果都离不开一个必要的值),最终输出一个整数的二维向量(剔除掉了z轴方向)

封装成函数后,最终的函数节点内容如下:

(但是,这里的Round四舍五入掉了人物位置的变化,也就是说,远处的地面消失和出现是很突兀的,这一点后续可以优化,因为最终希望达到的是模块上下浮动的效果,是一个过渡)

1.2 学习记录

接下来一些细节记录:

UE里的Actor Pawn和Character类

Actor------UE里的Actor我认为就可以当作Unity里的GameObject去理解,"游戏对象",也就是游戏场景中的桌子、山、石头等等,都是Actor

Pawn------单词里Pawn是"棋子""兵"的意思,可以理解为游戏场景中每个可以被控制的Actor(玩家角色&AI或非AI控制的NPC )都需要具备的基础类,访问它可以得到Actor当前的位置、朝向等,例如接下来我们需要获取Actor的位置,就是通过GetControlledPawn -> GetActorLocation来实现的;当然,除了位置啥的,还可以获取当前对象的一些其他信息,总之就是一个基础大类,包含很多其他的细节

Character------一种特定的,针对玩家的Pawn,可以有特定的走路、跳跃等动作

GetControlledPawn

获取当前受控的Pawn,类似Unity的GetComponent

GetActorLocation

获取Actor位置

UE5和UE4对于Math计算检索的不同

获取人物位置的时候,up这里调用了vector/float我不是特别理解:

而且UE5里似乎没有/float这个部分,通过搜索,于是找到了答案:CAN`T FIND MULTIPLY (VECTOR * FLOAT) NODES IN UE5

也就是说,UE5不分数据的类型了,做math计算时统一都是一个divide(/):

Round 节点

四舍五入节点,材质里面也有这个。

Pure 纯函数

这里Up勾上了GetPlayerTilingCoord是个纯函数,勾上前和后在蓝图里使用该函数的区别是:

2 判断前后位置是否一致

2.1 蓝图实现逻辑

在Event Tick事件下跟前一帧的玩家位置进行一个equal比较,再用Branch分支节点去判断 -> False将当前帧的玩家位置赋予给Prev Player Coord,具体节点:

2.2 学习记录

Event Tick事件

每帧执行!

Branch节点

就是一个if else判断,分支节点,估计是蓝图很常用,B+鼠标左键直接快速get一个Branch节点

3 生成:计算生成地板个数及位置

3.1 蓝图实现逻辑

首先,创建一个changeTiling事件,事件触发SpawnTiles函数,接下来计算生成地板生成个数的逻辑都写在SpawnTiles函数内:

并将ChangeTiling事件做为第2步中False分支的结尾:

(比较好奇的是,这里明明new的是一个事件,为什么这个调用ChangeTiling的时候显示的Call Function栏)解释放在了后面的学习记录里。

接下来就是在SpawnTiles函数里进行操作,最终使用SpawnTransformClass节点去生成地板,意味着首先要创建简单的地板------Plane:

蓝图创建一个Actor,

然后Actor内创建个平面:

alt+J换个视角,看看面的大小,初始创建的是1m,也就是100cm(顺便提一下UE默认长度单位是厘米cm),也就是初始长度是100个单位长度,就浅跟着教程里的Up把长度修改为500,scale给个5就行:

一切就绪后,开始实现生成的逻辑,我给简化了一下,因为暂时不是很清楚Up用一个初始值为1的spawnXY变量去做-1 0 1三个值去loop的意义(往后看!!已解决!!是为了一次性生成更多的地面让生成更加的丝滑),简化后节点如下:

3.2 学习记录

Event和Function的关系与区别

这里直接贴解释的很好的博客:

【UE4笔记】Event&Function事件和函数的区别_ue5 event function-CSDN博客

For Loop节点

就是实现循环!For Loop对应for循环:

蓝图里还有While Loop节点,跟while语句一个道理。

SpawnActor From Class节点

这个节点应该是用于生成Actor并定义位置 & 销毁已生成的Actor

------Class就是用来指定Actor

------Transform就是指定变换

实现到这里之后,现在运行,已经有这样不断生成地面的效果了(我把地面变小了,每帧刷新的地面是初始单位长度大小100,同样的计算中的TilingXY也需要改成100),仅仅是原地奔跑生成地面"

写到这里突然就发现了教程中loop出-1 0 1三个方向上生成地面的用处:

会发现生成更加连贯:

我们多连一组print节点,把每一帧会出现的x y情况展示出来:

怪不得这么连贯。。。因为移动一次,就会四面八方生成9个面!

4 生成优化------避免重复生成,节省开销

第3步实现的效果是每次移动都生成9个地面。。。这样绝对不行

加入一个判断,很简单,就是每次生成地面后,把已生成地面的WordPos存入一个数组 ,每次生成前判断一下当前计算得到的地面坐标是否在这个Array里,如果不在,再创建新的地面,

先加个local变量,存一下每次偏移后得到的新地面的WorldPos:

把每次的坐标存入数组TileCoords(这里暂时也不是很清楚为什么要把每次生成的BP Tiling也存到Array里去):

每次生成BP Tilling前判断一下当前地面坐标是否包含在TileCoords数组库中(用了个CONTAINS,在不苛求性能的前提下,蓝图里用起来也太方便了):

这样改动就算完成了,为了使优化可视化,每次生成后我输出一下当前创建的每个BP Tiling的信息:

观察右上角输出的坐标个数:

优化目的达到了!


01暂时就做到这,后面会去做初始地面+销毁功能,以及更加细节的部分。

相关推荐
汇能感知3 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun4 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao4 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾4 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT5 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
ST.J5 小时前
前端笔记2025
前端·javascript·css·vue.js·笔记
Suckerbin5 小时前
LAMPSecurity: CTF5靶场渗透
笔记·安全·web安全·网络安全
小憩-6 小时前
【机器学习】吴恩达机器学习笔记
人工智能·笔记·机器学习
UQI-LIUWJ6 小时前
unsloth笔记:运行&微调 gemma
人工智能·笔记·深度学习
googleccsdn7 小时前
ESNP LAB 笔记:配置MPLS(Part4)
网络·笔记·网络协议