当前位置: 首页 > news >正文

UE5官方文档(第一人称射击游戏教程)解读 第七章

好了今天来到我们的第七章今天将承上启下延伸输入部分的工作。配置角色移动Coder 03 Configure Character Movement with C in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include CoreMinimal.h #include GameFramework/Character.h #include EnhancedInputComponent.h #include EnhancedInputSubsystems.h #include InputActionValue.h #include AdventureCharacter.generated.h class UInputMappingContext; class UInputAction; class UInputComponent;如图所示我们在上一节对蓝图有了一些认知并且学会了引入模块使用接着学会了如何在特定代码里引入我们想要的功能。如上图所示那么在引入后我们就要正式开始写输入相关功能。声明InputMappingContext指针请先跟着官方文档来一遍。可以看见我们本小节写了下面两行东西。这是什么意思呢请回忆我们正常c开发的时候不管是在栈上开辟内存储存变量数据还是在堆上进行它似乎都不需要前面带个宏之类的。但是我们这两行代码前面是一个UPROPERTY宏然后里面有参数下面则是创建一个输入映射上下文的指针。我们之前说过UE5类内成员多使用指针是为了优化和管理也与垃圾回收内存回收的引用链有关那UPROPERTY宏是什么它的参数有什么用呢这个就和我们说过的运行时知晓类信息直接相关了。这个概念很难理解我们举一个毫不相关的代码例子。class A { public: int a10; float b20; }; A a1; float ca1.aa1.b;在类A里面我们有两个变量一个int一个float然后我们在栈上开辟内存A的大小然后我们在栈上面开辟了内存float大小存储c。运行的时候我们的程序只知道在栈上开辟内存大小是intfloat然后前半截int大小存储了对应二进制数据然后后半截float大小存储了对应二进制数据。然后栈上开辟内存float大小提取前面那块内存的前半截后后半截进行运算指令结果存入开辟的内存。运行过程中程序根本不知道这个类叫做A不知道这个类的实例叫a1不知道有个float变量叫做c不知道类内成员变量叫做a和b也不知道它们是什么int或者float或者A类型它们只知道按多少多少字节或者位去读取对应地址的输入然后进行指令c是静态语言编译的时候就决定好了一切运行时就按我前面说的那样动态语言我则不在这里赘述这是一个作业。为什么UE5需要在运行时知晓变量信息请试想一下c是静态语言编译后不会有所谓的类型信息而运行则是在编译后。我们如果想要在运行时增加变量比如生成敌人类实例生成角色类实例当然不限于这个功能还有编辑器实时显示修改都需要运行时知晓类信息这里作为一个作业拓展那我们就要以某种手段存储类的信息然后运行时可以读取这个信息去开辟内存存储数据。那么UPROPERTY宏就担任了这个功能我说过静态语言是编译期决定好一切那么被UPROPERTY宏标记的变量会在编译时把类信息传递给某些文件存着有需要的时候实时读取。那说白了就是相当于一个变量出生登记。但是不限于UPROPERY宏进行标记我们还有UCLASS宏USTRUCT宏……其实你看名字也知道是对谁用的。那么说完UPROPERTY宏的作用了UPROPERTY宏参数是什么意思呢下面是我编译后角色类蓝图的配置。首先我们知道我们的角色蓝图类继承了我们的c角色类所以我们在这里改了c角色类代码并编译作为它的子类的角色蓝图类肯定会有变化这下看懂了吧我们声明了一个IMC指针变量然后放在目录category的输入input下面EditAnywhere顾名思义就是可以在编辑器任何地方编辑然后是BlueprintReadOnly的意思是蓝图只能读取我们设定的这个数据不能进行覆写操作就像我们设置了一个int a10;a就不准再修改了。其实我们还可以看见我们之前写的IMC指针变量本质上是一个数据填充位可以填充IMC数据后面IA也是一样。这个参数其实还有很多个和instance相关的也有大家可以去了解一下作为一个不太重要的作业。那好了我们本小节的学习就完美完成了。声明跳跃和移动InputAction指针还是跟着官方文档做一遍。这部分的原理和前面一样不多赘述。为什么输入需要IMC和IA请回顾前面学习声明Move()函数还是跟着官方文档做一遍。那么在我们对于玩家输入做完一系列处理后我们终于可以写输入后的反馈了。不过还记得我们前面手动引发bug吗写完声明一定要加上实现哦哪怕实现是空的都行没有实现会在链接阶段发生问题。在这里我们漏掉了一个东西那就是函数前也要进行宏标记登记变量信息函数前面用UFUNCTION为啥函数也要用呢函数的本质可以理解为指令集你放指令也需要一块内存调用的时候也需要知道指令集开始的地址然后才能一条一条读取处理。说着就想到了函数指针这种东西拓展作业可以去完成一下这个在UE5中特指类的实例中函数是以函数指针还是纯函数成员存在如果是前者有什么好处原生c对于类实例和UE5对于类实例的处理差异非常大所以我在这里只提UE5此外我们可以看到这里函数里面获取了一个参数const FInputActionValue Value是引用类型说明不希望我们会误修改顺带希望快速传递不经过拷贝。那我们看英文顾名思义这是一个输入值那多半就是我们设备交互发出的信号经过处理后的数据比如我按着A想让角色往左走。实现移动函数设置Move()函数还是先跟着官方文档做一遍。void AAdventureCharacter::Move(const FInputActionValue Value) { // 2D Vector of movement values returned from the input action const FVector2D MovementValue Value.GetFVector2D(); // Check if the controller possessing this Actor is valid if (Controller) { } }在前面那个小节我们可以看出来FInputActionValue对数据做了一定的处理可是为什么是2D向量呢欸我们在打游戏的时候方向键其实只能走前后左右范围也就是所谓的只能在平面移动高度变化是通过跳跃等行为完成你看我们这里写的是Move函数对吧。所以使用的是2D向量。我们翻回前面IMC对应的部分看一下。这就对应上了。我们输入的原始数据是Axis2D然后经过转换成为FVector2D.使用Move()添加2D移动输入还是先根据官方文档做一遍。void AAdventureCharacter::Move(const FInputActionValue Value) { // 2D Vector of movement values returned from the input action const FVector2D MovementValue Value.GetFVector2D(); // Check if the controller posessing this Actor is valid if (Controller) { // Add left and right movement const FVector Right GetActorRightVector(); AddMovementInput(Right, MovementValue.X); // Add forward and back movement const FVector Forward GetActorForwardVector(); AddMovementInput(Forward, MovementValue.Y); } }可以看见我们这次是在Controller的if判断里面加东西。之前我们说过Pawn和Character类比起父类Actor多的就是获取Controller输入可以有很多种嘛AI操控或者玩家操控而Controller是封装成指针的。而我们知道如果Controller是空指针但使用了的话就会崩溃报错。拓展作业在哪些情况下Controller是空指针接着看下来Right和Forward可以理解为是左右方向和前后方向的值引用然后把增量加上传递回去。可以这样理解假设我的初始平面坐标是11我向前走两步是02向右走三步是30然后我们总得加出来最终坐标是43最后我们需要把坐标数据重新写回角色信息。好了今天的学习到此为止。
http://www.zskr.cn/news/1360780.html

相关文章:

  • agent-skills 完整使用教程(2026最新版)
  • TCP可靠传输机制——“不丢包“背后的技术秘密
  • MLX框架深度优化指南:解锁苹果芯片的机器学习潜能
  • 03华夏之光永存:28nm工艺发展趋势|成熟制程长期黄金期+国产自主超车主线
  • 合肥租厂房该找谁 - GrowthUME
  • 学术写作效率飞跃!2026一站式AI论文写作工具精选指南
  • 谁是性价比之王?8款AI论文写作软件榜单,毕业护航!
  • 别再只用脚本了!用MATLAB OOP重构你的数据处理流程(附日期类实战代码)
  • 微信小程序逆向工程深度解析:wxappUnpacker实用指南
  • OpenClaw底层揭秘:打造私有化AI Agent团队的核心原理与实战解析!
  • 85%企业将淘汰纯业务程序员!2026年前,大模型才是你的职业救命稻草!
  • 广州GEO搜索优化机构实测评测:四大服务商能力对比 - 奔跑123
  • 避开ArcGIS Pro二次开发的那些坑:UI控件条件显示(Condition)配置详解与常见错误排查
  • 非结构化数据处理有没有更高效的办法?2026智能体端到端方案彻底终结数据孤岛
  • 别再傻傻分不清了!DCDC和LDO到底怎么选?从原理到实战,一次讲透电源选型
  • 用Python的SciPy和Matplotlib玩转二项分布:从理论公式到可视化实战(附完整代码)
  • 从HDLBits到FPGA实战:手把手教你用Verilog搭建一个12小时数字时钟
  • 终极入门指南:如何用100行PyTorch代码实现扩散模型生成图像?
  • 保姆级教程:在ESP32-C3上用SPI点亮ST7789屏幕(附完整源码与引脚图)
  • Continuous Batching:把 GPU 空闲时间填满
  • SAM模型实战:如何用点、框、文本提示精准控制图像分割结果(附调参技巧)
  • 【AI Agent数据分析实战指南】:20年专家亲授5大落地场景、3类避坑红线与实时决策增效方案
  • 德鲁科A2防火板就是山东德鲁克新材料有限公司——别再搞错了 - 新闻快传
  • 从‘BadNL’到‘ONION’:一份给NLP工程师的模型供应链安全自查清单
  • RTMDet设计精要:大核深度卷积、缓存式数据增强如何成就高性价比检测器?
  • Cursor Free VIP:告别试用限制,解锁AI编程助手永久Pro权限的技术方案
  • 2026北京大兴律师事务所哪家正规?严选北京百富律师事务所,资质齐全合规执业 - 新闻快传
  • 告别‘searching’!从RouterOS切回OpenWrt,一次搞定IPv6拨号上网(附immortalWrt配置)
  • 从公众号到后台:一次真实的EDUSRC弱口令挖掘复盘(附完整信息收集清单)
  • 抖音无水印下载器:5分钟掌握高效批量下载的完整指南