《UE5_C++多人TPS完整教程》学习笔记40 ——《P41 装备(武器)姿势(Equipped Pose)》


本文为B站系列教学视频 《UE5_C++多人TPS完整教程》 —— 《P41 装备(武器)姿势(Equipped Pose)》 的学习笔记,该系列教学视频为计算机工程师、程序员、游戏开发者、作家(Engineer, Programmer, Game Developer, Author) Stephen Ulibarri 发布在 Udemy 上的课程 《Unreal Engine 5 C++ Multiplayer Shooter》 的中文字幕翻译版,UP主(也是译者)为 游戏引擎能吃么。
在这里插入图片描述


文章目录

  • P41 装备(武器)姿势(Equipped Pose)
  • 41.1 在动画实例类中检测装备武器
  • 41.2 在动画蓝图中添加装备武器姿势
  • 41.3 Summary


P41 装备(武器)姿势(Equipped Pose)

本节课我们将在装备武器时更改动画姿势,我们将学习动画蓝图在多人游戏中的运用。
在这里插入图片描述


41.1 在动画实例类中检测装备武器

  1. 在人物角色动画实例类头文件 “BlasterAnimInstance.h” 中新建一个布尔值 “bWeaponEquipped”,用以记录人物角色是否装备武器。接着,在 “BlasterCharacter.h” 和 “BlasterCharacter.cpp” 中声明和定义函数 “IsWeaponEquipped()”,通过枪战功能组件类 “UCombatComponent” 的 “EquippedWeapon” 变量来改变 “bWeaponEquipped” 这个布尔值。然后,在 “BlasterAnimInstance.cpp” 的 “NativeUpdateAnimation()” 函数中通过调用 “BlasterCharacter” 的 “IsWeaponEquipped()” 函数更新 “bWeaponEquipped” 的值。

    /*** BlasterAnimInstance.h ***/...UCLASS()
    class BLASTER_API UBlasterAnimInstance : public UAnimInstance
    {GENERATED_BODY()...private:// UPROPERTY:https://dev.epicgames.com/documentation/zh-cn/unreal-engine/unreal-engine-uproperties?application_version=5.4UPROPERTY(BlueprintReadOnly, Category = Character, meta = (AllowPrivateAccess = "true"))	// 属性说明符:仅在蓝图中可读,类别为 “Character”;// 元数据说明符:由于变量为私有变量,需要设置 AllowPrivateAccess 为 true 才能在蓝图中可读class ABlasterCharacter* BlasterCharacter;	// 使用动画实例的角色类							UPROPERTY(BlueprintReadOnly, Category = Movement, meta = (AllowPrivateAccess = "true"))		// 属性说明符:仅在蓝图中可读,类别为 “Movemonet”;float Speed;								// 运动速度UPROPERTY(BlueprintReadOnly, Category = Movement, meta = (AllowPrivateAccess = "true"))		// 属性说明符:仅在蓝图中可读,类别为 “Movemonet”;bool bIsInAir;								// 是否在空中UPROPERTY(BlueprintReadOnly, Category = Movement, meta = (AllowPrivateAccess = "true"))		// 属性说明符:仅在蓝图中可读,类别为 “Movemonet”;bool bIsAccelerating;						// 是否在加速/* P41 装备(武器)姿势(Equipped Pose)*/UPROPERTY(BlueprintReadOnly, Category = Movement, meta = (AllowPrivateAccess = "true"))		// 属性说明符:仅在蓝图中可读,类别为 “Movemonet”;bool bWeaponEquipped;						// 是否装备了武器/* P41 装备(武器)姿势(Equipped Pose)*/
    };...
    
    /*** BlasterCharacter.h ***/...UCLASS()
    class BLASTER_API ABlasterCharacter : public ACharacter
    {GENERATED_BODY()...public:	// 设置重叠的武器实例,以便在武器类 Weapon 的 OnSphereOverlap() 函数中调用 // FORCEINLINE void SetOverlappingWeapon(AWeapon* Weapon) { OverlappingWeapon = Weapon; }void SetOverlappingWeapon(AWeapon* Weapon);/* ‌forceinline 是编程中用于强制内联函数的关键字或注解‌,主要用于减少函数调用开销,但需谨慎使用以避免代码膨胀或性能下降。/* P41 装备(武器)姿势(Equipped Pose)*/bool IsWeaponEquipped();	// 判断是否装备了武器/* P41 装备(武器)姿势(Equipped Pose)*/
    };
    
    /*** BlasterCharacter.cpp ***/.../* P41 装备(武器)姿势(Equipped Pose)*/
    bool ABlasterCharacter::IsWeaponEquipped()
    {return (Combat && Combat->EquippedWeapon);	// 返回值为是否装备了武器
    }
    /* P41 装备(武器)姿势(Equipped Pose)*/...
    
    /*** BlasterAnimInstance.cpp ***/...void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaTime)		// 原生(Native)类更新函数 NativeUpdateAnimation() 覆写,用于在每一帧调用以更新动画
    {Super::NativeUpdateAnimation(DeltaTime);							// 调用父类 AnimInstance 的 NativeUpdateAnimation() 函数if (BlasterCharacter == nullptr) {									// 检查 BlasterCharacter 是否声明BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner());	// 获取动画蓝图实例所属,并向下强制转换(Cast)为 ABlasterCharacter 类}if (BlasterCharacter == nullptr) return;FVector Velocity = BlasterCharacter->GetVelocity();					// 获取人物角色速度向量Velocity.Z = 0.f;													// 不关心 Z 轴速度,设置为 0Speed = Velocity.Size();											// 获取人物角色速度向量的模(大小),少了这一行代码在人物角色从怠速到走路到跑步的动画将无法实现转化bIsInAir = BlasterCharacter->GetCharacterMovement()->IsFalling();	// 调用 GetCharacterMovement()->IsFalling() 函数判断人物角色是否掉落从而判断人物角色是否在空中,// 需要添加头文件 "GameFramework/CharacterMovementComponent.h"bIsAccelerating = BlasterCharacter->GetCharacterMovement()->GetCurrentAcceleration().Size() > 0 ? true : false;	// 调用 GetCharacterMovement()->GetCurrentAcceleration() 获取人物角色加速度// 判断加速度是否的维度是否大于 0 ,大于 0 说明某个方向上有加速度/* P41 装备(武器)姿势(Equipped Pose)*/bWeaponEquipped = BlasterCharacter->IsWeaponEquipped();				// 调用 IsWeaponEquipped() 函数判断人物角色是否装备了武器/* P41 装备(武器)姿势(Equipped Pose)*/
    }...
    
  2. 现在需要解决的问题是我们的动画实例与变量复制没有太大的关系:所有机器上的每个人物角色都存在动画实例和动画蓝图,并且动画实例只能访问该机器上的变量。当我们操控的当前人物角色装备武器时,人物角色的动画姿势将发生改变,此时就需要一个方式来让其他玩家(如对手)实例来知道我们的人物角色是否装备了武器,以便在他们的机器上可以看到我们的人物角色处于正确的装备了武器的动画姿势。

  3. 通过查看我们在 “BlasterCharacter” 中定义的装备武器动作映射的回调函数 “EquipButtonPressed()” 以及上节课创建的 RPC 函数 “ServerEquipButtonPressed()” 的定义可知,我们只在服务器上设置了要装备的武器,枪战功能组件类 “UCombatComponent” 的 “EquippedWeapon” 变量并没有很好地被复制。因此,我们只要将 “EquippedWeapon” 重新定义为可复制的变量,重写 “GetLifetimeReplicatedProps” 函数、注册 “EquippedWeapon” 属性,然后编译即可。

    /*** CombatComponent.h ***/...UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
    class BLASTER_API UCombatComponent : public UActorComponent
    {GENERATED_BODY()public:	// Sets default values for this component's propertiesUCombatComponent();friend class ABlasterCharacter;					// 将人物角色类 ABlasterCharcter 设置为枪战功能组件类 UCombatComponent 的友元类// void EquipWeapon(AWeapon* WeaponToEquip);void EquipWeapon(class AWeapon* WeaponToEquip);	// 指定要装备的武器// Called every framevirtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;/* P41 装备(武器)姿势(Equipped Pose)*/// 重写复制属性函数virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;/* P41 装备(武器)姿势(Equipped Pose)*/protected:// Called when the game startsvirtual void BeginPlay() override;private:class ABlasterCharacter* Character;	// 声明人物角色类,避免反复 casting 到 ABlasterCharacter/* P41 装备(武器)姿势(Equipped Pose)*/UPROPERTY(Replicated)class AWeapon* EquippedWeapon;		// 保存当前装备的武器/* P41 装备(武器)姿势(Equipped Pose)*/
    };
    
    /*** CombatComponent.cpp ***/...// Fill out your copyright notice in the Description page of Project Settings.#include "CombatComponent.h"	// 原来自动生成的代码是 #include "BlasterComponents/CombatComponent.h",这里需要把 "BlasterComponents/" 去掉,否则找不到文件 "CombatComponent.h"
    #include "Blaster/Weapon/Weapon.h"
    #include "Blaster/Character/BlasterCharacter.h"
    #include "Engine/SkeletalMeshSocket.h"/* P41 装备(武器)姿势(Equipped Pose)*/
    #include <Net/UnrealNetwork.h>
    /* P41 装备(武器)姿势(Equipped Pose)*/.../* P41 装备(武器)姿势(Equipped Pose)*/
    // 重写复制属性函数
    void UCombatComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
    {// 调用SuperSuper::GetLifetimeReplicatedProps(OutLifetimeProps);// 添加要为派生的类 AUCombatComponent 复制的属性,需要添加头文件 "Net/UnrealNetwork.h"// DOREPLIFETIME 宏用于指定 UCombatComponent 哪些属性需要被复制,以及复制的条件。DOREPLIFETIME(UCombatComponent, EquippedWeapon);
    }
    /* P41 装备(武器)姿势(Equipped Pose)*/
    

41.2 在动画蓝图中添加装备武器姿势

  1. 在虚幻引擎中打开动画蓝图 “BlasterAnimBP”,然后在 “AnimGraph” 面板中修改蓝图,断开原先蓝图节点间的引脚连接,新增节点 “按布尔混合姿势”(Blend Poses by bool),添加变量 “Weapon Equipped”,并连接到 “按布尔混合姿势” 节点的 “Active Value” 引脚;接着新增状态机()节点,重命名为 “Equipped”,将 “Equipped” 节点的输出引脚连接到 “按布尔混合姿势” 节点的 “真 姿势”(True Pose)引脚,将原先的 “Unequipped” 节点的输出引脚连接到 “按布尔混合姿势” 节点的 “False 姿势”(False Pose)引脚,最后将 “按布尔混合姿势” 的输出引脚连接到 “OutputPose” 节点的 “Result” 输入引脚。
    这段蓝图表示通过 “Weapon Equipped” 的布尔值来判断输出的动画姿势,如果 “Weapon Equipped” 为真,则最终的输出姿势为 “Equipped” 状态机中的动画姿势,即人物角色已装备武器的动画姿势,如果 “Weapon Equipped” 为假,则最终的输出姿势为 “Unequipped” 状态机中的动画姿势(我们在《UE5_C++多人TPS完整教程》学习笔记32 ——《P33 动画蓝图(Animation Blueprint)》 中已为 “Unequipped” 状态机构建了状态节点转换蓝图),即人物角色未装备武器的动画姿势。
    在这里插入图片描述
  2. 双击 “Equipped” 状态机节点,进入状态机编辑界面,在右侧内容浏览器中将动画资产 “Idle_Rifle_Hip” 拖拽至面板中,将生成的节点重命名为 “Idle”,并与 “Entry” 节点进行连接。
    在这里插入图片描述
    在这里插入图片描述
  3. 编译保存后进行测试,可以看到我们成功实现了人物角色装备武器的动画姿势,且无论我们操控客户端还是服务器上的人物角色去装备武器,在其他机器上都能同步看到我们机器上的人物角色的动画姿势,达成预期目标。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

41.3 Summary

本节课实现人物角色装备武器时的动画状态切换,通过在动画实例 C++ 类上进行网络变量复制以及动画蓝图的协同工作,确保了多人游戏中角色姿势的准确同步。首先,我们在动画实例类 “BlasterAnimInstance” 中添加了标识武器装备状态的布尔变量 “bWeaponEquipped”,并在角色类 “BlasterCharacter”中 创建了 “IsWeaponEquipped()” 方法,通过检查枪战功能组件的 “EquippedWeapon” 变量来动态更新装备状态。为保障多人游戏中的动画同步,我们将枪战功能组件的 “EquippedWeapon” 变量设为复制属性,重写 “GetLifetimeReplicatedProps” 函数实现变量注册,确保所有客户端都能准确获取武器装备状态。接着,在动画蓝图 “BlasterAnimBP” 中我们重构了输出姿势的逻辑,通过引入“按布尔混合姿势” 节点,实现以蓝图变量 “Weapon Equipped” 的布尔值作为 “Active Value” 来控制最终的输出姿势,当 “Weapon Equipped” 的值为真时输出的 “Equipped” 状态机对应的动画姿势(在状态机编辑面板中添加、连接由持枪动画 “Idle_Rifle_Hip” 生成的节点),为假时则维持原有的 “Unequipped” 状态机对于的动画姿势。最终测试的测试结果验证了无论我们操控客户端还是服务器上的人物角色去装备武器,在其他机器上都能同步看到本地人物角色的动画姿势。
在这里插入图片描述


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

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

相关文章

【HarmonyOS】鸿蒙使用仓颉编程入门

【HarmonyOS】鸿蒙使用仓颉编程入门 一、前言 仓颉&#xff0c;是华为自研的一款面向全场景智能的新一代编程语言&#xff0c;是为鸿蒙量身打造的全场景智能应用编程语言&#xff0c;作为鸿蒙生态中的重要组成部分&#xff0c;旨在支持鸿蒙系统下的全场景应用开发 &#xff0…

2.3.1 Nginx Web服务器安全加固

文章目录 一、试题及考试说明二、操作步骤1. 启动Nginx服务2. 隐藏站点 Response Header 里的Web服务版本信息&#xff08;见下总图&#xff09;3. 隐藏站点 Response Header 里的X-Powered-By 字段&#xff08;见下总图&#xff09;4. Nginx访问日志存放位置修改为/opt/bak/ac…

红色背景政府当讲PPT模版

政府党建PPT模版&#xff0c;庆国庆PPT模版&#xff0c;国庆节PPT模版 红色背景政府当讲PPT模版&#xff1a;https://pan.quark.cn/s/a6f484905430

JavaScript对象(Object)常用操作

创建对象 //使用对象字面量、构造函数或者Object.create()方法来创建对象// 对象字面量 const person {name: John,age: 30,hobbies: [reading, swimming] };// 构造函数 function Car(make, model) {this.make make;this.model model; } const myCar new Car(Toyota, Cor…

Java面试宝典:基础一

⚙️ 1. Java跨平台原理&#xff08;字节码文件与JVM&#xff09; 核心机制&#xff1a; Java源程序&#xff08;.java&#xff09;编译为与平台无关的字节码文件&#xff08;.class&#xff09;&#xff0c;而非直接生成机器码。字节码由**Java虚拟机&#xff08;JVM&#xf…

uniapp微信小程序:editor组件placeholder字体样式修改

一、问题描述 微信小程序editor组件的placeholder字体默认为斜体字&#xff0c;官方对此没有属性可以设置它的样式&#xff0c;并且直接在组件上设置样式也是无效的。 二、解决方案 通过审查节点&#xff1a; 可以看到editor的placeholder其实是在一个伪元素上。 在页面或者…

PhoneRescue 4.3绿色版!解决iPhone数据丢失、系统崩溃等场景

目录 一、引言二、软件介绍1. 研发背景与定位2. 兼容性与技术优势 三、功能介绍1. 数据恢复功能&#xff08;核心痛点解决方案&#xff09;2. 系统修复功能3. 数据管理辅助 四、软件特色1. 操作极简&#xff0c;零技术门槛2. 安全可靠&#xff0c;零数据风险3. 高效精准&#x…

Vue 快速入门

一、Vue是什么 Vue是一款用于构建用户界面的渐进式的JavaScript框架。 官网&#xff1a;Vue.js - 渐进式 JavaScript 框架 | Vue.js 其核心特性包括&#xff1a; 响应式数据绑定&#xff1a;通过 Vue 的响应式系统&#xff0c;数据变化会自动反映到视图&#xff0c;减少手动 D…

JAVA-JWT

JWT简介 JSON Web Token&#xff08;JWT&#xff09;是一个非常轻巧的规范&#xff0c;这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。一个 JWT 实际上就是一个字符串&#xff0c;它由三部分组成&#xff0c;头部、载荷与签名。前两部分需要经过 Base64 编…

UI前端大数据处理挑战与对策:保障数据安全与隐私

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 一、引言&#xff1a;大数据时代的前端安全新挑战 在数字化转型的浪潮中&#xff0c;前端已从…

DTO、VO、POJO与实体类使用方案(结合Mapper.xml)

结合MyBatis的Mapper.xml文件&#xff0c;展示完整的层级数据流转和数据库操作。 1. 实体类优化&#xff08;Entity&#xff09; // User.java Data NoArgsConstructor AllArgsConstructor TableName("sys_user") public class User {TableId(type IdType.AUTO)pr…

开源|VDBBench 1.0正式官宣,完全复刻业务场景,支持用户自定义数据集

宣布个好消息&#xff0c;大家期待已久的VDBBench 1.0更新啦。 尝鲜链接&#xff1a; https://github.com/zilliztech/VectorDBBench/releases/tag/v1.0.0 对于这个功能的更新&#xff0c;我们准备了很久&#xff0c;也思考了很多。 因为对我们来说&#xff0c;VDBBench 从来不…

7,FreeRTOS列表与列表项的插入删除

一、实验目标 创建三个动态任务&#xff0c;栈空间大小均为128字。startTask、Task1、Task2。startTask仅运行一次&#xff0c;负责task1、task2任务的创建&#xff0c;startTask任务的删除。Task1负责初始化列表、列表项123&#xff0c;并进行列表项的插入实验与删除实验。Tas…

两款支持3D地图的WebGIS框架对比

前言 在当前的WebGIS技术发展中&#xff0c;3D地形图的可视化已经成为一个非常重要的功能&#xff0c;尤其是在城市规划、环境监测和虚拟旅游等领域中的应用。对于开发者而言&#xff0c;选择一个强大且适合的WebGIS框架是实现这些功能的关键。目前市场上较为流行的支持3D地形…

Github 2025-06-26 Go开源项目日报Top10

根据Github Trendings的统计,今日(2025-06-26统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目10PureBasic项目1使用Gitleaks保护和发现机密信息 创建周期:2203 天开发语言:Go协议类型:MIT LicenseStar数量:14645 个Fork数量:13…

C++实现鱿鱼、羊了个羊、扫雷、原神模拟

C++ 鱿鱼游戏模拟实现 鱿鱼游戏中的经典场景可以通过C++模拟实现,例如“红绿灯”游戏。以下是一个简化版本的核心代码框架: #include <iostream> #include <thread> #include <chrono> #include <cstdlib> #include <ctime> #include <ve…

从用户到权限:解密 AWS IAM Identity Center 的授权之道

大家好&#xff0c;今天我们来解决一个非常具体的实战问题&#xff1a;如何让 IAM Identity Center 中创建的用户真正获得 AWS 账户的操作权限&#xff0c;从而取代老旧的 IAM 用户管理模式&#xff1f; 如果我们盯着用户详情页&#xff0c;想找一个“附加角色”的按钮&#x…

在 Spring Boot 中使用 MyBatis-Plus 的详细教程

前言 在现代的 Java Web 开发中&#xff0c;Spring Boot 和 MyBatis 已经成为主流框架组合。为了提升开发效率和简化数据库操作&#xff0c;MyBatis-Plus&#xff08;简称 MP&#xff09;应运而生。它是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改…

AI生成内容泛滥时代:从“袋鼠登机“视频看AI鉴伪与游戏智能的未来

近年来&#xff0c;AI生成内容的质量突飞猛进&#xff0c;从文本到图像再到视频&#xff0c;几乎达到了以假乱真的程度。近期一段"人类在飞机上吵架看呆袋鼠"的视频在社交网络疯传&#xff0c;获得数千万次观看后&#xff0c;才被证实是AI生成内容&#xff0c;这一事…

为什么在linux中不能直接使用pip进行安装

您好&#xff0c;这是一个非常深刻且关键的问题&#xff0c;触及了 Linux 系统管理与 Python 开发实践的核心原则。理解了这一点&#xff0c;您就真正开始像一位经验丰富的开发者那样思考了。 简单来说&#xff0c;答案是&#xff1a;为了保护操作系统自身的稳定和完整性。 让…