网站建设lhempire,做一个游戏需要什么技术,电子商务系统有哪些,wordpress运营本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P23 记录加入的玩家#xff08;Couting Incoming Players#xff09;》 的学习笔记#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版#xff0c;UP主#xff…
本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P23 记录加入的玩家Couting Incoming Players》 的学习笔记该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版UP主也是译者为 游戏引擎能吃么。 文章目录 P23 记录加入的玩家23.1 游戏模式和游戏状态23.2 追踪加入或离开游戏的玩家23.3 使用 Lobby 游戏模式23.4 进行测试23.5 Summary P23 记录加入的玩家
本节课将创建一个游戏模式以便追踪Track加入游戏会话的玩家、打印游戏人数之后我们就可以利用统计的人数来决定是否要从关卡 “Lobby” 过渡Transition到实际的匹配中。 23.1 游戏模式和游戏状态
在多人游戏中两个重要的类分别是游戏模式类和游戏状态类
游戏模式规定了游戏规则这涉及了很多方面如何时将玩家移动至关卡中、选择出生位等。游戏模式有几个继承的虚拟函数可以在玩家加入或离开会话时进行追踪例如每当玩家加入游戏时都会调用 “PostLogin()” 访问玩家的控制器当玩家离开时调用 “Logout()” 函数。客户端可以监控游戏状态游戏状态将保存游戏的状态信息而非特定的单个玩家的信息。游戏状态包含玩家状态数组玩家状态类中保存了特定的单个玩家的信息比如得分和胜利次数等。游戏模式类可以访问游戏状态类的玩家状态数组通过查看该数组的大小可以得出玩家的个数。 两个主要类负责处理进行中游戏的相关信息Game Mode 和 Game State。 即使最开放的游戏也拥有基础规则而这些规则构成了 Game Mode。在最基础的层面上这些规则包括 出现的玩家和观众数量以及允许的玩家和观众最大数量。玩家进入游戏的方式可包含选择生成地点和其他生成/重生成行为的规则。游戏是否可以暂停以及如何处理游戏暂停。关卡之间的过渡包括游戏是否以动画模式开场。 基于规则的事件在游戏中发生需要进行追踪并和所有玩家共享时信息将通过 Game State 进行存储和同步。这些信息包括 游戏已运行的时间包括本地玩家加入前的运行时间。每个个体玩家加入游戏的时间和玩家的当前状态。当前 Game Mode 的基类。游戏是否已开始。 Game Modes 特定的基础如进行游戏所需要的玩家数量或玩家加入游戏的方法在多种类型的游戏中具有共通性。可根据开发的特定游戏进行无穷无尽的规则变化。无论规则如何Game Modes 的任务都是定义和实现规则。Game Modes 当前常用的基类有两个。 4.14 版本中加入了 AGameModeBase这是所有 Game Mode 的基类是经典的 AGameMode 简化版本。AGameMode 是 4.14 版本之前的基类仍然保留功能 如旧但现在是 AGameModeBase 的子类。由于其比赛状态概念的实现AGameMode 更适用于标准游戏类型如多人射击游戏。AGameModeBase 简洁高效是新代码项目中包含的全新默认游戏模式。 Game State Game State 负责启用客户端监控游戏状态。从概念上而言Game State 应该管理所有已连接客户端已知的信息特定于 Game Mode 但不特定于任何个体玩家。它能够追踪游戏层面的属性如已连接玩家的列表、夺旗游戏中的团队得分、开放世界游戏中已完成的任务等等。 Game State 并非追踪玩家特有内容如夺旗比赛中特定玩家为团队获得的分数的最佳之处因为它们由 Player State 更清晰地处理。整体而言Game State 应该追踪游戏进程中变化的属性。这些属性与所有人皆相关且所有人可见。Game Mode 只存在于服务器上而 Game State 存在于服务器上且会被复制到所有客户端保持所有已连接机器的游戏进程更新。 —— 虚幻引擎官方文档《Game Mode 和 Game State》
打开虚幻引擎在内容浏览器中展开 “C类/MenuSystem”添加游戏模式基础Game mode baseC 类命名为 “LobbyGameMode”选择模块为我们上节课新建的插件 “MenuSystem (Runtime)”。 点击 “创建类” 按钮VS 中出现弹窗选择 “全部重新加载(A)”。
23.2 追踪加入或离开游戏的玩家 在 “LobbyGameMode.h” 中添加头文件 “GameFramework/GameStateBase.h” 和 “GameFramework/PlayerState.h”避免出现错误 “使用了未定义类型 AGameStateBase” 和 “使用了未定义类型 APlayerState”。接着声明重写 “virtual void PostLogin()” 和 “virtual void Logout()”。 // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include CoreMinimal.h
#include GameFramework/GameModeBase.h/* P23 记录加入的玩家Couting Incoming Players*/
#include GameFramework/GameStateBase.h
#include GameFramework/PlayerState.h
/* P23 记录加入的玩家Couting Incoming Players*/#include LobbyGameMode.generated.h/*** */
UCLASS()
class MENUSYSTEM_API ALobbyGameMode : public AGameModeBase
{GENERATED_BODY()/* P23 记录加入的玩家Couting Incoming Players*/
public:// 成功登录后调用。这是首个在 PlayerController 上安全调用复制函数之处。// OnPostLogin 可在蓝图中实现以添加额外的逻辑。virtual void PostLogin(APlayerController* NewPlayer) override; // 重写 virtual void PostLogin()// 玩家离开游戏或被摧毁时调用。可实现 OnLogout 执行蓝图逻辑。virtual void Logout(AController* Exiting) override; // virtual void Logout()
/* P23 记录加入的玩家Couting Incoming Players*/
};在 “LobbyGameMode.cpp” 中实现“virtual void PostLogin()” 和 “virtual void Logout()” 的覆写。如果 “GameState” 和 “PlayerState” 标红且错误提示为 “不允许指针指向不完整的类类型 AGameStateBase” 和 “不允许指针指向不完整的类类型 APlayerState”则添加头文件 “GameFramework/GameStateBase.h” 和 “GameFramework/PlayerState.h”。 // Fill out your copyright notice in the Description page of Project Settings.#include LobbyGameMode.h/* P23 记录加入的玩家Couting Incoming Players*/
void ALobbyGameMode::PostLogin(APlayerController* NewPlayer)
{Super::PostLogin(NewPlayer);if (GameState) {int32 NumberOfPlayers GameState.Get()-PlayerArray.Num();if (GEngine) {GEngine-AddOnScreenDebugMessage( // 添加调试信息到屏幕上1, // Key 不是 -1 时则更新现有消息60.f, // 调试信息的显示时间FColor::Red, // 字体颜色黄色FString::Printf(TEXT(Players in game: %d!), NumberOfPlayers) // 打印玩家人数);APlayerState* PlayerState NewPlayer-GetPlayerStateAPlayerState();if (PlayerState) {FString PlayerName PlayerState-GetPlayerName();GEngine-AddOnScreenDebugMessage( // 添加调试信息到屏幕上2, // Key 不是 -1 时则更新现有消息60.f, // 调试信息的显示时间FColor::Cyan, // 字体颜色蓝绿色FString::Printf(TEXT(%s has joined the game!), *PlayerName) // 打印进入游戏的玩家昵称);} }}
}void ALobbyGameMode::Logout(AController* Exiting)
{Super::Logout(Exiting);APlayerState* PlayerState Exiting-GetPlayerStateAPlayerState();if (PlayerState) {int32 NumberOfPlayers GameState.Get()-PlayerArray.Num();GEngine-AddOnScreenDebugMessage( // 添加调试信息到屏幕上1, // Key 不是 -1 时则更新现有消息60.f, // 调试信息的显示时间FColor::Red, // 字体颜色红色FString::Printf(TEXT(Players in game: %d!), NumberOfPlayers - 1) // 打印玩家人数// 此时 PlayerArray.Num() 还未更新这里进行减 1 操作只是为了方便测试时显示正确的人数在实际项目中不会如此操作);FString PlayerName PlayerState-GetPlayerName();GEngine-AddOnScreenDebugMessage( // 添加调试信息到屏幕上2, // Key 不是 -1 时则更新现有消息60.f, // 调试信息的显示时间FColor::Cyan, // 字体颜色蓝绿色FString::Printf(TEXT(%s has exited the game!), *PlayerName) // 打印进入游戏的玩家昵称);}}
/* P23 记录加入的玩家Couting Incoming Players*/这里可以复习一下函数 “AddOnScreenDebugMessage()” 第一个入参 “int32 Key” 取不同值的含义。这里 打印玩家人数 和 打印进入或退出游戏的玩家昵称 设置了不同的 “Key” 是为了都能在屏幕上显示如果设置为 -1 则 玩家人数消息 会被 进入或退出游戏的玩家昵称消息 覆盖。 调用全局变量 GEngine 指针调用函数 AddOnScreenDebugMessage节点进行屏幕输出。 void AddOnScreenDebugMessage {int32 Key,float TimeToDisplay,FColor Di splayColor,const FString DebugMessage,bool bNewerOnTop,const FVector2D TextScale
}Key -1 时则添加新的消息不会覆盖旧有消息当 Key -1 时bNewerOnTop 有效直接添加到队列最上层Key ! -1 时则更新现有消息效率更高。 —— 《虚幻引擎基础入门(C) — 【日志输出篇 03】》 在 “MultiplayerSessionsSubsystem.cpp” 的 “CreateSession()” 函数中加入一条会话设置的代码行用来设置唯一构建标识防止不同的构建在搜索过程中可以互相搜索到。 void UMultiplayerSessionsSubsystem::CreateSession(int32 NumpublicConnections, FString MatchType)
{...// FOnlineSessionSettings 在头文件 OnlineSessionSettings.h 中LastSessionSettings MakeShareable(new FOnlineSessionSettings()); // 创建会话设置利用函数 MakeShareable 初始化// 会话设置成员变量参阅及含义https://docs.unrealengine.com/5.0/en-US/API/Plugins/OnlineSubsystem/FOnlineSessionSettings/LastSessionSettings-bIsLANMatch IOnlineSubsystem::Get()-GetSubsystemName() NULL ? true : false; // 会话设置如果找到的子系统名称为 “NULL”则使用 LAN 连接否则不使用LastSessionSettings-NumPublicConnections NumpublicConnections; // 会话设置设置最大公共连接数为函数输入变量 NumpublicConnections.../* P23 记录加入的玩家Couting Incoming Players*/LastSessionSettings-BuildUniqueId 1; // 会话设置设置唯一构建标识防止不同的构建在搜索过程中可以互相搜索到。/* P23 记录加入的玩家Couting Incoming Players*/...}在 “MenuSystem\Config” 目录下打开 “DefaultGame.ini”设置最大玩家数为 100。创建会话中设置最大公共连接数 “NumPublicConnections”区别开设置最大公共连接数是指定加入会话的最大连接数而设置最大玩家数是指定连接到游戏项目最大人数。 [/Script/EngineSettings.GeneralProjectSettings]
ProjectID6A5F83AB4DEB75FB9BB586AC8DE40CDA
ProjectNameThird Person Game Template[StartupActions]
bAddPacksTrue
InsertPack(PackSourceStarterContent.upack,PackNameStarterContent)[/Script/Engine.GameSession]
MaxPlayers100 选做注释掉 “MenuSystemCharacter.cpp” 获取在线子系统并打印在线子系统名称到屏幕上的代码并删除 “BP_ThirdPersonCharacter” 角色蓝图中按下数字键 “1” 和 “2” 对应的事件。 // AMenuSystemCharacterAMenuSystemCharacter::AMenuSystemCharacter() : // 为委托绑定回调函数CreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this, ThisClass::OnCreateSessionComplete)),FindSessionsCompleteDelegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, ThisClass::OnFindSessionsComplete)),JoinSessionCompleteDelegate(FOnJoinSessionCompleteDelegate::CreateUObject(this, ThisClass::OnJoinSessionComplete))
{.../* P23 记录加入的玩家Couting Incoming Players*///IOnlineSubsystem* OnlineSubsystem IOnlineSubsystem::Get(); // 获取当前的在线子系统指针//if (OnlineSubsystem) { // 如果当前在线子系统有效// OnlineSessionInterface OnlineSubsystem-GetSessionInterface(); // 获取会话接口智能指针// if (GEngine) {// GEngine-AddOnScreenDebugMessage( // 添加调试信息到屏幕上// -1, // 使用 -1 不会覆盖前面的调试信息// 15.f, // 调试信息的显示时间// FColor::Blue, // 字体颜色// FString::Printf(TEXT(Found subsystem %s!),// *OnlineSubsystem-GetSubsystemName().ToString()) // 打印在线子系统的名称// );// }//}/* P23 记录加入的玩家Couting Incoming Players*/}23.3 使用 Lobby 游戏模式
打开虚幻引擎在内容浏览器中目录 “/内容/ThirdPerson/Blueprints/” 下新建 “LobbyGameMode” 蓝图类命名为 “BP_LobbyGameMode”。 双击 “BP_LobbyGameMode”进入蓝图编辑器在右侧 “细节” 面板 “类” 选项卡下设置 “默认 pawn 类” 为 “BP_ThirdPersonCharacter”编译、保存。 在目录 “/内容/ThirdPerson/Maps/” 下打开地图 “Lobby”在右下方 “世界场景设置” 面板设置 “游戏模式” 为“BP_LobbyGameMode”保存。 如果没有看到右下方的 “世界场景设置” 面板可以点击工具栏右侧 “项目和编辑器设置” 按钮虚幻引擎窗口右上方在下拉菜单栏中选中 “世界场景设置”。 23.4 进行测试 将项目打包之后发送到另一台设备上。在设备 1 上运行游戏保证 Steam 已经运行点击 “Host” 按钮当前关卡跳转至 “Lobby”且左上角显示会话创建成功消息。 在设备 2 上运行游戏保证 Steam 已经运行且登录的账户与设备1 上登录的账号不同点击 “Join” 按钮当前关卡跳转至 “Lobby”并且可以看到有两个玩家存在说明设备 2 成功找到并加入到了设备 1 创建的会话中但是设备 2 屏幕左上角没有显示玩家人数和加入游戏信息而创建会话的设备 1 上有显示。 在设备 2 上退出游戏可以看到设备 1 屏幕左上角显示了设备 2 上的玩家离开游戏的消息玩家人数也发生了变化。 23.5 Summary
本节课了解了游戏模式和游戏状态的基本概念并在虚幻引擎创建了游戏模式基础Game mode baseC 类 “LobbyGameMode”。接着我们在 “LobbyGameMode.cpp” 中实现“virtual void PostLogin()” 和 “virtual void Logout()” 的覆写以便能够打印在线玩家人数以及玩家加入或退出游戏的消息。为了能够使用这个游戏模式我们以 “LobbyGameMode” 为父类新建了蓝图类 “BP_LobbyGameMode”设置蓝图类的 “默认 pawn 类” 为 “BP_ThirdPersonCharacter”并将地图 “Lobby” 的 “游戏模式” 设置为“BP_LobbyGameMode”。最后我们在两台设备上以玩家加入和退出游戏的方式进行来了测试玩家人数以及玩家加入和退出游戏的消息都能正常显示。 在 23.2 追踪加入或离开游戏的玩家 的 步骤 2 中使用函数 AddOnScreenDebugMessage() 进行屏幕消息输出时若函数第一个入参 “int32 Key” 为 -1 则添加新的消息不会覆盖旧有消息当 Key 为 -1 时bNewerOnTop 有效直接添加到队列最上层若 Key 不为 -1 则更新现有消息。这里打印 玩家人数 和 打印进入或退出游戏的玩家昵称 设置了不同的 “Key” 是为了都能在屏幕上显示如果设置为 -1 则 玩家人数消息 会被 进入或退出游戏的玩家昵称消息 覆盖。