UE5 c++笔记 01. 使用C++进行LAN连接笔记
//作用:创建一个新的游戏大厅,并且成为主机
void AMPTestingCharacter::OpenLobby()
{
//创建一个UWorld类型的指针
UWorld* World = GetWorld();
//GetWorld()作用:获取当前对象所在的World。若World不存在,将返回NULL
//这个World是指当前游戏所在的世界。
if (World)
{
//调用ServerTravel
// ServerTraval 是一个服务器函数。
// serverTravel函数的作用:将玩家从一个虚拟世界(当前关卡)传到另一个虚拟世界(另一个关卡或子关卡)
//SeverTravel传参:
//CONST FString MapName:关卡地图地址 ,填入关卡地图URL地址
//bool bAbsolute :是否将MapName设为绝对路径,默认false,表示为相对路径。True则是绝对路径
//SpecificPlayer:只想特定玩家控制器对象的指针。如果指定了此参数,则只有这个玩家被传送到新的虚拟世界,若未指定,则所有人都会被传到新世界
FString lobbyAddress = "/GAME/ThirdPerson/Maps/Lobby?listen";
//地址处理:截止至CONTENT前的地址,都可以用/GAME/来代替
//.文件类型不用处理,需要改成“?Listen". 这样会打开lobby关卡,并且使该关卡作为listen server
//?listen 用来告诉服务器创建一个新的游戏绘画,并将该玩家设置为主机(服务器)。这意味着其他玩家可以加入该游戏,并且该玩家可以控制开始或结束的游戏
//?listen通常用于单人游戏或创建主机托管的多人游戏
World->ServerTravel(lobbyAddress);
//补充:Fstrign
//在UE5中,FString是一个字符串类型,它是一个可变大小的Unicode字符串,它提供了许多方便的方法来处理字符串
//FString 还支持字符串格式化,可以使用一些占位符,将变量嵌入到字符中。
//FString是一个非常重要的类型,用来处理大量的文本和消息
}
}
//连接至目标服务器方法1
传入值:IP地址
void AMPTestingCharacter::CallOpenLevel(const FString& Address)
{
//OpenLevel是一个游戏开发函数
//OpenLevel的作用:在当前游戏世界,打开一个新的关卡
//Openlevel传参:
//UObject* WorldContextObject :当前上下文的UObject对象指针,通常情况下,这里传递的是当前运行游戏的GameMode或PlayerController对象
//FName levelName:要打开的关卡名称,可以使用FName类型或字符串字面量传递
//bool bAbsolute:表示是否根据绝对路径来加载关卡。默认为False:按照相对路径加载
//FString Options:一个可选的字符串参数,用来指定加载关卡时的一些额外选项,例如GameInstace类型,难度级别等等等等
//为什么参数是 const FString& Address 却可以为FNname LevelName赋值?
//因为FStirng和FName之间存在隐式转换。
//在本例中,由于FString 类型可以转换为 const char*类型,而FName类型可以从const char*类型构造出来,因此在调用OpenLevel时,会将FSring类型的参数转化为FName型的参数
//具体来说,在这段代码中共进行了以下的转换
//1. 使用Address表示获取FString类型参数Adddress底层C字符串指针类型(const char类型)
//2. 通过FNanme构造函数,将其转换为了FName类型
//3. 将其传给OpenLevel函数
//通过this,在当前世界中,打开对应路径的关卡地图
//这里的Address是IP地址
//值得注意的是:官方给出的第二个值,应该是给的关卡地址,意思是:打开一个新的关卡
//下面进行测试:
//问题:为什么我不能直接声明一个FString 类型的newwAddress,来匹配LevelName?
//回答:因为即使FString类型可以隐式的转换为 const char*,也不能直接当做OpenLevel的参数传递,需要转换后使用
//可以调用FName构造函数,将FString类型的字符串作为参数传递给FName构造函数,得到一个FName对象 Fname 新对象(*FString对象)
//测试内容:将一个新地图的地址给到LevelName
//FString LevelName = "/Game/ThirdPerson/Maps/Map_test01";
//UGameplayStatics::OpenLevel(this, FName(*LevelName), true);
//测试完毕,当LevelName是一个关卡的路径时,会打开对应的关卡地图
UGameplayStatics::OpenLevel(this, *Address);
//当一个LevelName是一串IP时,会连接到该IP
//补充 this
//在C++中,this是一个指向当前对象的指针
//当前对象:可以理解为,调用这个类的函数的类的对象
//补充:Fname
//在UE5.1中,FName是一个用于储存名称的结构体。
//它通过使用哈希表优化字符串的查找速度。它通常用于将字符串作为键来访问哈希表中的值,以便在内存中高效的储存大量名称。
//在代码中,使用FName而不是字符串,可以提高性能和效率
}
//连接至目标服务器方法2
//传入值:IP地址
void AMPTestingCharacter::CallClientTravel(const FString& Address)
{
//检测是否存在玩家控制器
APlayerController* PlayerController= GetGameInstance()->GetFirstLocalPlayerController();
//APlayerController:代表玩家控制器的类,继承自AController类,并添加了管理玩家输入、处理网络同步。控制视图声音等功能
//每个玩家在游戏中,都拥有一个对应的玩家控制器实例。
//玩家控制器与玩家角色一起协同工作,接受玩家输入,并将其传递给游戏世界,来影响游戏的状态行为
//玩家控制器还负责处理玩家离开游戏、游戏结束、进行网络同步等操作
//GetGameInstance():用于获取当前正在运行的游戏实例
// 返回值:与当前世界关联的游戏实例的指针
// 如果当前场景没有附加到任何游戏实例,则该函数将返回空值
// 导致该指针返回空值的几种情况:
// 1. 当前场景中不存在游戏实例
// 如果游戏尚未初始化或已经结束,则可能没有游戏实例存在
// 2. 调用该函数的对象不是控制器或游戏实例
// GetGameInstance()函数与控制器或游戏实例相互关联
// 3. 游戏实例已经被销毁
// 在某些情况下,流入切换关卡、退出游戏时,游戏实例可能会被销毁。
//当前游戏实例(Current Game Instance)是一个在整个游戏生命中存在的单例对象,它负责管理游戏实例相关的一些操作和数据。
//每个项目只有一个游戏实例,并且,它存储在引擎中
//游戏实例通常用于存储全局游戏状态和玩家数据,例如玩家分数、关卡列表、游戏设置德国
//可以通过在游戏实例类中定义这些变量和函数,并且从任何继承自UObject的蓝图或C++中访问它们
//除了存储全局的游戏状态之外,游戏实例还管理引擎级别的事件,例如启动游戏的初始化、处理游戏暂停/回复以及程序退出的清理工作等
//游戏实例的创建顺序
//1. 在游戏开始时,引擎自动创建一个GameMode对象,并用它来管理游戏。
// GameMode负责初始化游戏世界、处理玩家输入和协调系统,确定了默认的Pawn类和PlayerController类,这些类用于表示玩家角色并处理他们的输入
//2.在GameMode 对象创建后,引擎会使用它创建GameState对象
// GameState对象与GameMode对象存在一对一关系,用来储存有关的游戏状态
//3. 创建PlayerState对象,改对象代表单个玩家并跟踪其状态
//4. 当玩家启动游戏时,会实时的创建一个LocalPlayer对象,该对象代表本地玩家。
//5. 创建PlayerController对象,处理玩家输入以及相应游戏事件
// PlayerController与PlayerState之间,存在一对一的关系
//6. 创建Pawn对象,改对象用于表示玩家角色
// Pawn对象与PlayerController对象之间存在一对一的关系
//游戏实例 GameInstance对象是如何被创建的?
//当打开一个UE项目并且开始游戏运行时,UE会自动创建一个GameInstance对象,并将其作为第一个对象加载。
//GetFirstLocalPlayerController():获取与游戏实例关联的第一个本地玩家控制器(Local Player Controller)的指针。
//如何定义第一个?
//在一个游戏实例中,可以有多个本地玩家控制器。其中,“第一个”指的是与游戏实例关联的序号 最小 的 本地玩家控制器。
//当玩家进入游戏后,系统为其创建一个本地玩家的控制器,如果有多个玩家加入游戏,则会为每个玩家创建一个本地玩家控制器。
//这些控制器不存在固定的先后顺序,因此,在获取第一个本地玩家控制器时,引擎会返回序号最小的本地玩家控制器
//需要注意到是:不同平台或不同设置可能导致本地玩家控制器的创建顺序发生边缘化,因此,不能假设序号最小的本地玩家控制器始终与某个特定玩家关联
if (PlayerController)//判定当前玩家控制器是否存在,容错
{
PlayerController->ClientTravel(Address,ETravelType::TRAVEL_Absolute);
//ClintTravel:PlayerController类中的一个成员函数,用于让客户端连接到指定地址
//参数:
// 1.const Fstring& URL:要连接的目标地址,这个地址可以是任意有效的URL,比如,一个IP地址,或者是一个文本路径
// 2.ETravelType TravelType:连接类型,包括以下枚举值
// TRAVEL_Absolute:绝对地址
// TRAVEL_Relative:相对地址
// TRAVEL_Partial:部分地址(通常是相同关卡中的某个位置)
// TRAVEL_Preload:预加载地图以后使用
// 3.bSeamless:是否无缝过渡到新地图
// 4.MapPackageGuid:新地图的package GUID(如果不为None)
//可以使用ClientTravle()函数来实现多种功能,比如:
//· 切换到另一个关卡or地图
//· 加入其它游戏服务器
//· 打开一个网页或视频连接
//· 连接到自定义网络服务器
//需要注意的是:ClientTravel()仅适用于客户端,不能在服务器调用此函数
}
}