-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
使用C++在虚幻引擎5中创建多人射击游戏 Unreal Engine 5 C++ Multiplayer Shooter[进行中] #215
Comments
1. 引言1. 引言欢迎来到虚幻引擎5 C++ 多人射击游戏课程。在本课程中,我们将从头开始创建这个多人射击游戏。如你所见,在这次测试环节中,我有来自全球各地的19名玩家与我一起游戏。在本课程中,我们将创建一个完全功能的多人游戏,具有完整的网络功能,优化流畅的游戏体验,能够容纳许多不同的玩家通过在线会话连接。 我们将从创建一个可以添加到任何虚幻引擎项目中的多人插件开始,以启用多人功能。这使得创建多人游戏变得简单,因为我们的插件将处理创建会话、查找和加入会话以及销毁会话,提供一个易于使用的界面,可以根据你的特定游戏进行定制。我们将学习虚幻引擎在线子系统,管理与各种服务(如Steam)连接的代码库。我们的插件代码将适用于虚幻引擎代码库支持的任何服务,我们将使用Steam快速让我们的会话运作并与其他玩家连接。 你将加入一个活跃的Discord社区,在这里你可以找到其他学生并在互联网上测试彼此的游戏,确保你的游戏项目能够正常工作,而不必单独进行测试。我们将确保你有测试伙伴。课程中的插件部分独立于实际游戏项目,因此如果你想直接开始多人游戏编程,只需下载插件,我会教你如何将其添加到你的项目中,以立即启用Steam会话。 接下来,我们将创建一个新的虚幻引擎5项目,并启用我们的插件,进行一些快速的多人测试以验证网络功能。我们将创建一个新的角色类,添加一个网格并实现基本的移动功能,包括蹲伏、跳跃、瞄准和瞄准行走,所有这些都将针对多人进行编程。当然,我们随后将创建武器类和装备武器的功能,所有与战斗相关的行为都将通过战斗组件来处理,以保持角色和战斗功能的有序。 我们将学习游戏在服务器和客户端上的工作原理,了解网络角色和权限,以及如何编程以确保游戏逻辑在多人模式下正常运作。在每个步骤中,我们将确保服务器对所有重要的游戏逻辑(如生命值、伤害和弹药)保持控制,以防止玩家作弊。我们将创建多个武器类,实施头部扫描武器和投射物武器。我们将创建突击步枪、手枪、冲锋枪、狙击步枪、火箭发射器、榴弹发射器、霰弹枪和投掷手榴弹。 我们将使用投射物运动组件,利用虚幻引擎内置的复制行为来处理投射物,直接通过击中事件施加伤害,并通过范围伤害处理爆炸武器。我们将实现随机武器弹散,看看这如何适用于所有武器类型,包括霰弹枪。我们还将确保所有机器之间的随机散布是一致的,以便你在应该命中的时候始终准确命中。我们将实现动态十字准星,它会在瞄准另一个玩家时扩散、收缩并变红,我们将使用瞄准偏移和逆向运动学,使我们的手始终正确放置在武器上,确保武器始终朝向子弹发射的正确方向,并让我们的武器以物理效果和声音弹出弹壳。 接下来,我们将讨论虚幻引擎的类框架,以及引擎类如何与多人模式相关,讨论每个类的角色以及数据和功能应在多人游戏中如何编程。我们将讨论游戏模式与游戏模式基类之间的区别,以及游戏模式为匹配设计的更多功能,包括匹配状态的概念。我们将利用匹配状态,甚至创建我们自己的自定义匹配状态,以便在比赛的不同阶段中使用,包括热身阶段,在此阶段玩家可以在等待热身计时器时飞行穿越关卡,以及冷却状态,在此状态下我们将显示获胜玩家的名称和得分。 我们将创建一个由游戏模式管理的工作倒计时器,并学习如何将客户端的运行时间与服务器的时间同步,以便所有玩家在同一时间看到完全相同的数字。我们将实施玩家淘汰和重生机制,并在玩家得分时分配积分,将玩家的得分存储在玩家状态类中。我们将创建一个游戏状态类,用于跟踪得分最高的玩家以及团队得分和得分最高的团队。游戏中的淘汰机制将会非常出色。 我们将创建一个警报板,在玩家被淘汰时生成,并将玩家传送,使用我们从零开始创建并在运行时动态改变的溶解材质来溶解角色。我们将创建拾取物来增强玩家的能力,包括生命值、护盾、跳跃和速度增强,并通过增强组件处理所有这些行为。我们将创建一个拾取生成器类,能够在随机时间段后生成拾取物,并在HUD上显示所有相关的游戏数据,包括生命条、护盾条、得分和淘汰、武器弹药和携带弹药,并将这些值从C++中通过一个高效的事件驱动系统进行更新,仅在变量更改时更新HUD,而不是在每帧中检查。 接下来,我们将讨论延迟,并回顾AAA射击游戏使用的各种延迟补偿技术,然后实现它们。我们将使用客户端预测,使体验在极高延迟的情况下迅速响应。我们将学习如何在引擎和打包构建中模拟延迟,以便在最严酷的延迟条件下测试游戏。然后,我们将创建一个服务器端回滚算法,这是大多数你喜欢的AAA射击游戏使用的一种高级技术,确保玩家在高延迟情况下始终获得命中反馈。通过存储玩家信息的历史记录,并在服务器上回滚时间以验证命中,确保玩家在他们的机器上每次有效命中时都能获得积分。我们将对头部扫描武器和投射物进行此操作。 接下来,我们讨论服务器端回滚的优缺点,以及始终给予射击反馈可能带来的著名的“拐角死亡”问题,即延迟玩家命中时,另一名玩家在到达掩体之前就已经被击中。我们将学习如何根据玩家的延迟限制服务器端回滚,以消除这个问题。我们的延迟补偿算法将封装在自己的延迟补偿组件中,以保持它们的组织性。 然后,我们将讨论作弊,学习玩家如何作弊以及如何防止作弊,并认识到我们在整个过程中构建的游戏架构能够有效防止作弊,同时学习如何验证发送到服务器的数据,甚至踢出试图发送错误数据的玩家。我们将实施团队游戏模式,并最终实现“夺旗”模式。在课程结束前,我们将打包并测试我们的游戏。 在整个课程中,我们将频繁与真实玩家进行测试,以确保每一步都能在多人模式下正常运作。你将拥有一个完整的多人游戏,充分利用虚幻引擎的多人代码库,与其他玩家在互联网上连接和游戏。你将学习到制作快速、竞争激烈的射击游戏的可靠和高效的方法。我们优化低带宽和最大网络性能,课程结束时,你将拥有足够的技能来实现你想要的任何类型的多人游戏。如果你能够制作射击游戏,那么你就能够制作任何类型的游戏,因为射击游戏在性能上是最具挑战性的,快速竞争的游戏至关重要。 每个讲座都有自己的GitHub提交,我将向你展示如何查看每个讲座的代码更改,这样你可以在遇到问题时随时查看代码。你将与一个活跃的Discord社区连接,以便与其他学生和我讨论你的问题,我们将确保你的项目正常运作,即使你遇到困难。你不需要是专家才能参加本课程。基本的C++知识或对类似语言(如C#或Java)的理解即可。如果你已经参加了我的《游戏开发的C++学习》课程,你就可以顺利进行。如果你至少参加过我的其他一门虚幻引擎C++课程(无论是《虚幻引擎C++终极游戏开发课程》还是《虚幻引擎C++终极射击课程》),那么你就已经准备好深入学习了。如果你没有参加过这两门课程,只要你了解一些基本的C++变量、函数、指针和类等内容,你也能顺利进行这门课程。 我甚至还没有告诉你我们在本课程中涵盖的所有功能。你所学习的技能将极大提升你的游戏职业能力,如果你试图在游戏行业找工作,这将为你带来巨大的优势。在面试中提到服务器端回滚,大家会对你产生浓厚的兴趣。因此,如果你准备好在虚幻引擎中制作多人游戏,并创建迄今为止最令人印象深刻的游戏项目,准备好投入进来,创建这款虚幻引擎5 C++ 多人射击游戏吧。 2. 关于本课程在本次讲座中,我们将讨论课程结构,具体来说,这门课程是如何构建的,以及它的两个主要部分以及我们将在这两个部分中创建的内容。我们还将讨论资源以及如何充分利用这些资源,使您的学习旅程更加轻松。在创建这个多人项目的过程中,我们还将讨论如果您遇到困难或有问题,获取帮助的主要途径。最后,我们会讨论在这门课程中您将面临的挑战和任务。 首先,让我们来谈谈课程结构。这门课程由两个主要部分组成。第一部分是多人插件。我们将为虚幻引擎创建一个实际的插件,您将能够将此插件添加到任何项目中。这个插件包含创建在线会话的功能,并允许玩家通过互联网在您的游戏中连接。这将是一个有价值的工具,您可能会在之后创建的多人项目中使用。 课程的第二部分是实际的游戏项目。在这一部分中,我们将创建我们的角色、武器以及与我们的多人射击游戏相关的所有内容。这两个项目部分是独立的。如果您想了解如何创建插件、如何在虚幻引擎中工作以及如何连接到互联网玩家,您可以从头开始创建插件。但如果您想进入游戏编程,开始制作角色、武器和游戏项目中的所有游戏类,您可以首先开始游戏项目部分,然后将插件添加到其中。这样,您的游戏项目就会自动工作并为您创建多人会话。 在游戏项目部分的第一节课中,资源标签中会有一个可下载的压缩文件,您可以下载插件并开始创建游戏,直接实施多人游戏编程。因此,您可以选择先做插件,或先开始制作游戏项目,然后再回到插件部分。如果您首先开始游戏项目,在该部分的第一节课中,您将下载插件的压缩文件,该讲座将向您展示如何设置您的游戏并添加插件以及配置多人设置。 如果您想首先学习如何创建和管理在线会话,您将从头开始课程并创建多人插件,然后您将理解在线会话的工作原理。这一切与游戏项目部分的实际游戏编程是非常独立的。在游戏项目部分,我们将首先添加多人插件,然后开始创建实际的游戏,在其中实施多人游戏玩法,学习诸如复制、游戏优化、游戏中的战斗、比赛游戏状态等所有相关内容。 这里的要点是,如果您想开始制作实际的游戏并编程游戏机制,您将从游戏项目开始,并添加插件,使您的游戏能够创建在线会话,您可以与其他玩家进行测试。但如果您想先制作插件,您可以从课程的开头开始。如果您是虚幻引擎的新手,我建议您最后再做插件。 现在,让我们来谈谈本课程的资源。我们在这门课程中编程的所有源代码都在GitHub上。每一节课中,我们添加代码更改都有源代码,并且有指向GitHub提交的链接。接下来,我将在本视频中向您展示如何查看源代码,以便您可以看到在任何给定讲座中更改的每一行代码。 在您上课期间,您将在右侧看到讲座。虽然我的显示为未发布,但您看到的不是这样。因为到您上课时,这门课程将会发布,大多数讲座都有一个资源标签,您可以展开该标签以获取本讲座的资源。这里是项目创建讲座,它在“项目创建”部分,您会看到它位于创建多人插件之后。如果您决定跳过插件并最后再做,您将开始项目创建和资源。这里是插件,称为“plugins.zip”。这个讲座将向您展示如何使用它。 要查看本讲座中所做的代码更改,您将选择本讲座的GitHub提交,您会看到每一节讲座中我们做代码更改都有GitHub提交链接。如果您点击这个链接,您将被带到GitHub页面,您不需要登录或拥有GitHub账户即可访问该页面。该页面展示了一些信息,如果您向下滚动,您将看到在此讲座中特定的更改。 我们可以看到更改的单个文件,如果您想查看其他讲座,您可以在顶部点击包含所有讲座的库或仓库。如果您点击那个,您会看到该仓库中存在的所有文件。这里的条形图上有一个数字,这是对该仓库进行的提交次数。如果您点击这个数字,您可以查看每一节课所做的代码更改。 假设您想查看某一讲座中所做的代码更改,您只需点击与您的讲座同名的提交,您将看到在该讲座中所做的所有更改,按照文件显示更改,您可以点击小点图标来最小化这些文件。阅读这些内容的方法是,这些称为diff,diff展示了更改的内容。红色的行表示此行在本次提交中被删除,绿色的行表示添加了某些内容。 例如,在本讲座中,我删除了这行空白,并添加了这一行。页面底部您会看到我删除了这一行并添加了这一行。实际上我没有删除这一行并将相同的行重新添加,我只是通过在这一多行注释的末尾添加内容改变了这一行,而GitHub将其视为更改了整行代码。通过查看这个diff,您可以看到我在这里唯一更改的是删除了一行空白并通过开始一个多行注释和结束多行注释来注释掉这段代码。您可以看到该字符的额外高亮显示,以表明这是实际的更改。 在这里,我们不是查看整个projectile bullet.cpp文件,但我们可以查看此讲座的内容。右上角有三个点,您可以点击查看文件,这样我们将看到在课程这个阶段的整个文件。如果您在编译代码时遇到问题,您可以来到此GitHub仓库,查看此讲座中的项目,并将其与您的代码进行比较。 有一种方法可以复制此文件中的所有内容。就是这个图标,它说“复制原始内容”。如果我点击它,它将复制该文件中的所有文本。如果我想回到我的项目中找到那个文件,然后使用Ctrl+A全选,再使用Ctrl+V粘贴,那么它将粘贴所有的代码。但我强烈建议您不要这样做,因为复制和粘贴大块代码很容易导致编译错误。您可能将类命名为不同的名称,可能将某些变量命名为不同的名称,您的项目本身也可能有不同的名称,如果这些名称有任何不同,您的代码将无法编译。因此,我建议您查看代码本身,确保了解哪些内容不同。如果您的代码与我所做的不同,您可以分析它,但我不建议复制整个文件并将其粘贴到您的项目中,因为这几乎总是导致编译错误。如果您确实想这样做,您可以这么做。 如果您返回到整体库,通过点击它,这就是当前版本的库,换句话说,就是完成后的项目。因此,如果您点击“源代码”,您可以查看最终源代码在课程结束时的样子。 有两种方法可以查看代码。您可以查看完成项目的整体代码,或者您可以查看提交记录,点击特定讲座的提交,查看在该讲座中所做的更改,这些更改以绿色表示添加的代码,以红色表示删除的代码。您还可以点击三个点,查看该阶段课程的完整文件。 这是您可以使用GitHub仓库的方法,每一节讲座中做的更改都会有指向该讲座的GitHub提交的链接。GitHub是您在整个课程中可以使用的一个非常有用的资源。 下一个资源是Druid Mechanics Discord社区。这是一个Discord服务器。在这个Discord服务器中,我们有我发布的所有课程的社区,很多人在服务器中积极交流,互相请求帮助。因此,在这个Discord服务器中,您可以结识其他学生,与他们交谈,您可以更快地得到回复,进行更为轻松的互动讨论。您可以展示您的代码并请求他人的查看,包括我自己。我也在其中非常积极地回答问题,讨论课程中的问题、未来课程的想法等。此外,如果您在Discord中,您将可以获得更多课程的优惠券,因此您总是能够以最低价格获取课程。 加入Discord很简单。我在所有的资源标签中都有链接。第一个是“学生Discord”,点击此链接,您将有机会加入Discord服务器。如果您没有Discord账户,注册是免费的,Discord账户非常有用,因为您可以加入多个Discord服务器,与其他人聊天。Discord也有桌面应用程序可供下载,您还可以在移动设备上下载。我使用Discord的移动版,能及时接收学生在上面提问的通知,您也可以通过浏览器打开它。 一旦您加入Druid Mechanics Discord社区,您将访问这些频道。您首先要去规则频道,阅读规则,确保您理解它们。我们有一个用于一般讨论的频道和公告频道,您可以了解我未来课程的进展情况以及我在什么阶段。我还设有一个直播频道,因为我偶尔会进行直播,您可以在这里获取相关信息。这里还有课程优惠券,我每个月都会发布课程优惠券,您可以在这里获取课程的折 扣,查看您想参加的其他课程。此外,还有一个名为“寻找帮助”的频道,您可以在这里请求其他学生的帮助。若您需要帮助,寻找其他学生并与他们联系是一个很好的方式。 因此,这是您在此课程中的主要资源。我们有GitHub作为主要的代码资源,您可以在课程中跟踪每一节课所做的代码更改。同时我们有Druid Mechanics Discord社区,您可以与其他学生和我进行互动,交流问题、想法,随时获取您需要的帮助。 让我们再谈谈您在这门课程中将面临的挑战。您将创建一个完整的多人项目,您将通过第一部分学习插件的开发,而在第二部分将创建完整的游戏。虽然许多课程仅涵盖项目的某个部分,但在本课程中,您将全面了解制作完整多人游戏的过程,了解该过程的所有要素。这可能是一个相当大的挑战,特别是如果您是编程新手或没有游戏开发背景的话。您需要花费时间理解代码的每一部分,确保您知道每个特性的工作原理以及为什么使用它。确保在您开始时,您完全理解每一节课的代码,这对确保您能顺利继续课程是非常重要的。 作为课程的一部分,我建议您定期检查代码,进行复习,确保您了解每个功能。只有这样,您才能确保课程的顺利进行,并获得您想要的知识和能力。随着课程的进行,您可能会遇到困难,这都是正常的。我鼓励您不要害怕请求帮助,这就是为什么我们在Discord上有社区,您可以在这里获得支持。 在课程的每个阶段,我将提供我建议的最佳实践,这些最佳实践将帮助您在课程中顺利完成。请注意,有时在编程中,您可能会在某个部分停滞不前,无法理解某个概念,但如果您仔细阅读每一节课中的所有内容并积极参与与其他学生的交流,您将能够逐步克服这些障碍。 我期待着在接下来的课程中与您一起探讨这些内容,带您进入多人游戏开发的世界。在接下来的课中,我们将深入探讨每个部分,帮助您掌握所需的知识和技能。希望您能在这门课程中获得丰硕的成果! |
2. 创建多人插件1. 多人游戏概念欢迎。在本视频中,我们将讨论多人游戏的一些基本概念。首先,我们将定义什么是多人游戏。接着,介绍在不同计算机上运行的游戏之间通过网络传输信息的各种方法。我们会讨论点对点模型、客户端-服务器模型,最后谈谈虚幻引擎使用哪种模型,以便更好地理解在创建虚幻引擎中的多人游戏时发生的情况。 首先,让我们讨论一下多人游戏。与单人游戏相比,多人游戏本质上更复杂。在单人游戏中,游戏只在一台计算机上运行一个游戏会话。虽然您可以配置一个分屏游戏,通过同一台机器上的多个设备输入来进行游戏,但这种类型的游戏不需要互联网,也不需要在不同机器上运行的游戏之间传输信息。这也被称为本地多人游戏。因此,当我们在本课程中使用“多人”一词时,我们指的是真正的多人游戏,即两个或多个游戏实例在不同的机器上运行。在多人游戏中,至少有两个游戏实例在各自的机器上运行,两个玩家都在控制角色。因此,关于游戏变化的信息需要传送到其他游戏实例。例如,如果玩家一移动了他们的角色,玩家二需要看到这个动作,那么关于玩家一角色移动的信息必须发送到玩家二的计算机。同样,玩家二也会移动他们的角色,所以关于玩家二角色移动的信息必须返回到玩家一的机器。那么,问题是我们如何传输这些信息? 有几种方法可以构建一个系统,以便在游戏会话之间共享信息。我们首先讨论的是点对点连接。这是一种最简单的信息传输方式。当玩家一移动他们的角色时,移动信息会直接发送到玩家二的计算机。同样,当玩家二移动他们的角色时,移动信息会发送回玩家一的机器。对于简单的两人游戏来说,这是一种容易实现的系统,并且效果不错。然而,它也存在一些问题。 想象一下,如果我们有第三个玩家,每当玩家一移动他们的角色时,他们必须将该信息不仅发送给玩家二,还要发送给玩家三。同样,当玩家二移动他们的角色时,他们必须现在将该信息发送给玩家一和三。而当玩家三移动他们的角色时,他们又必须将信息发送给玩家一和二。这导致了大量的数据在网络中传输,而这种模式在玩家数量较多的游戏中无法很好地扩展。 另一个点对点连接的问题是没有权威版本的游戏。每个游戏实例都是不同的。当玩家移动他们的角色时,他们的本地游戏版本已经偏离了其他机器上运行的版本,需要一定时间将这些信息传输到其他机器上的游戏实例进行更新。至于哪个游戏实例是正确的,这个问题是没有答案的。所有的游戏实例都是不同的,没有哪个是所谓的“正确版本”。 另一种制作多人游戏的方法是使用客户端-服务器模型。在客户端-服务器模型中,指定一台机器作为服务器,而所有其他机器则作为客户端。每个客户端只与服务器进行通信,永远不会直接向其他客户端发送信息。这意味着每个客户端只需满足与服务器发送和接收信息的带宽要求,而不是与其他运行游戏的机器通信。因此,当玩家一移动他们的角色时,他们将该移动信息发送到服务器,服务器然后将信息发送到每个其他客户端,使玩家一的角色能够在其他屏幕上更新。 服务器通常是权威的,尽管这并不是唯一的实现方式。这意味着服务器运行一个被认为是正确版本的游戏。当玩家想要移动他们的角色时,他们实际上是向服务器发送请求,服务器会检查该移动是否合适,然后移动角色并将该移动更新信息分发给所有客户端。服务器向客户端分发数据的过程被称为复制。 实现客户端-服务器模型有不同的方式。一种方法是使用监听服务器。在这种情况下,一个玩家的机器充当服务器,因此人类玩家实际上在玩游戏,该机器负责渲染服务器版本的游戏画面。另一种方法是使用专用服务器,在这种情况下,机器被指定为游戏的服务器,但没有人实际上在这台机器上玩游戏,因此没有必要将图形渲染到屏幕上,因为没有人能看到它们。专用服务器允许服务器机器仅处理模拟权威版本的游戏,并将数据复制到客户端。大规模的多人游戏(如MMO)通常使用专用服务器,特别是在高风险的竞技游戏中,涉及资金的比赛。 监听服务器确实为主机玩家提供了一些优势,因为移动角色不需要向服务器发送请求。由于主机玩家就是服务器,他们没有等待数据传输的延迟。然而,每个客户端必须向服务器发送请求,并等待数据通过网络复制回去。对于大多数小型游戏而言,这种方式是可以的,并且在良好的互联网连接下,差异通常是微不足道的。随着玩家数量的增加,对专用服务器的需求变得更加必要。 现在,让我们谈谈虚幻引擎使用的是什么。虚幻引擎使用权威客户端-服务器模型。这意味着一台机器始终充当服务器,其他机器作为客户端连接到它。服务器版本是权威版本,并始终被视为正确的游戏版本。在运行虚幻引擎的单人游戏时,您仍然在使用客户端-服务器模型,只不过客户端和服务器是同一台机器。在整个课程中,我们将深入学习这个系统的工作原理,以及如何处理游戏代码,以保持服务器对正确游戏机制的控制。 总结一下,我们了解了什么是多人游戏,以及当我们提到多人游戏时的确切含义。我们讨论了在机器之间实现信息共享的各种方法,包括点对点模型和客户端-服务器模型。我们提到服务器可以是监听服务器,其中一个玩家实际上在该机器上玩游戏,或者是专用服务器,其中机器专门用于模拟权威版本的游戏并向所有客户端复制信息。我们提到虚幻引擎使用权威客户端-服务器模型。服务器是作为专用服务器还是监听服务器取决于您如何配置项目。 现在我们了解了一些基本概念,准备深入研究虚幻引擎中的多人游戏。期待很快见到您! 2. 测试多人游戏欢迎。在本讲中,我们将讨论如何在编辑器中测试多人游戏,以及如何通过局域网(LAN)连接到游戏。首先,让我们看看如何在编辑器中测试游戏。 在编辑器中测试游戏我将首先创建一个新项目,启动 Unreal Engine 5。点击“游戏”,创建一个基于第三人称模板的新项目,这样我们就能拥有一个已经设置好的第三人称角色,可以进行奔跑和跳跃。我将把这个项目设置为 C++ 项目,并选择一个位置,我在 C 盘上有一个名为 Multiplayer Course 的文件夹。选择这个文件夹,并将项目命名为 MP Testing(多人测试),然后点击“创建”。 在这个项目中,你可能已经熟悉第三人称模板。我们有这个角色可以使用,进行基本的运行和跳跃功能。Unreal Engine 具有内置的多人测试功能。在编辑器中,播放按钮旁边有三个点,允许我们更改播放模式。在下拉菜单的底部,我们看到“多人选项”,可以将其更改为1到4之间的值。如果我们将其更改为2,当我们启动游戏时,将会有两个游戏实例运行。 网络模式在“玩家人数”下方,我们有网络模式。如果我们将鼠标悬停在选项上,工具提示会提供一些信息。选择“以独立模式播放”将启动一个独立游戏,这不会创建专用服务器,也不会自动连接到一个。但选择“以监听服务器播放”时,工具提示说编辑器将同时充当服务器和客户端。选择这个选项并按下播放,我们会看到两个游戏实例在运行。编辑器中的实例是监听服务器。我们可以在不同的窗口中看到我们的角色在移动。 当我按 Shift + F1 以获取鼠标光标并点击第二个窗口时,我们现在在这个游戏的第二个实例中进行游戏,它是连接到监听服务器的客户端。我们可以看到顶部的标签显示为客户端1。让我们停止游戏,再次点击三个点,将玩家数量更改为3。点击播放后,我们会看到两个额外的窗口,编辑器中的游戏实例仍然是监听服务器。 使用专用服务器接下来,我将更改网络模式为“以客户端模式播放”。工具提示显示编辑器将充当客户端,同时在后台启动一个服务器。这样会创建一个专用服务器,而在编辑器中运行的游戏实例将是连接到该服务器的客户端。点击播放后,我们会看到三个角色,这三个游戏实例都是连接到专用服务器的客户端。我们在场景中看到的第四个角色是因为场景中存在一个角色。当编辑器启动专用服务器时,它不会拥有这个角色,而是会生成三个额外的角色,由连接到专用服务器的客户端控制。 Unreal Engine 允许我们测试专用服务器和监听服务器的游戏,这使得测试多人代码非常方便,因为我们不必打包项目并发送到另一台机器上,只需确保多人代码正常工作。 设置局域网连接有时,我们希望连接到另一台机器,以确保在两台机器连接在一起时能够正常工作。局域网(LAN)连接是指通过本地网络连接的两台或多台计算机。假设你有一个单一的路由器,多个机器连接到该路由器,每台机器都有自己的本地 IP 地址。这些计算机通过同一网络的本地 IP 地址互相访问。 许多游戏提供了通过局域网连接的选项。我们将看到如何通过局域网连接到 Unreal Engine 游戏。我们将连接逻辑放在角色蓝图中。打开角色蓝图类,在顶部打开完整的蓝图编辑器。删除这三个未使用的节点。 设置蓝图逻辑我希望能够按下一个键以开始新的游戏会话。因此,我将右键点击并输入“键盘”,选择数字 1 键。这样我们可以将一些蓝图逻辑映射到数字 1 键被按下时的行为。我将同样地为数字 2 和数字 3 键做相同的事情。当我按下数字 1 键时,我希望切换到一个可以等待其他玩家加入的关卡。 为此,我们需要另一个关卡。在第三人称项目的“地图”中创建一个新关卡。点击文件,选择新建关卡,然后选择默认。保存当前关卡为“lobby”,这是其他玩家连接后将前往的关卡。 我将选择这个地面,并在细节面板中将其放大,以便有更多空间供角色移动。保存后,我们有了一个可以前往的关卡。回到第三人称角色中,为数字 1 键映射逻辑。 当我按下数字 1 键时,我希望简单地打开一个关卡。拖动“按下”执行引脚,输入“打开关卡”,选择“按名称打开关卡”。第一个输入是关卡名称,我将输入“lobby”。记住,这是区分大小写的。这样就能打开“lobby”关卡。如果我们在后面添加“?listen”,我们指定应以监听服务器的方式打开这个关卡,以接收来自多个玩家的连接。 当我运行游戏实例并按下数字 1 键时,将前往这个关卡并以监听服务器的方式打开它。接下来,我将在另一台计算机上运行这个游戏实例,以便连接到该关卡。 连接到指定 IP 地址对于数字 2 键,我将拖动“按下”执行引脚,输入“执行控制台命令”。这个节点允许我们执行控制台命令,有一个命令可以让我们连接到特定的 IP 地址。我将使用当前计算机的 IP 地址。运行另一台连接到同一 Wi-Fi 的计算机,以便连接到这个游戏的 IP 地址。 如果你不知道自己的 IP 地址,可以打开命令提示符,输入命令“ipconfig”。找到 IPv4 地址,这是我的本地 IP。记住,这个地址无法从我的本地网络之外访问,但我将运行另一台连接到同一 Wi-Fi 的机器,能够通过这个地址连接到游戏。 在“执行控制台命令”节点中,输入“open”命令,后面跟上 IP 地址并留一个空格。这样执行控制台命令时,将连接到这个 IP 地址。一旦连接成功,当前游戏实例将加入在这个 IP 地址上运行的实例,并加入该开放的关卡。 打包和测试我将编译并保存,然后回到“lobby”关卡,打包这个游戏。点击平台并选择要打包的项目平台。我在 Windows 上,因此选择 Windows,点击“打包项目”。选择打包到的文件夹,创建一个名为 build 的新文件夹,并将新打包的项目放在这个文件夹中。 打包完成后,我可以打开包含我项目的文件夹,找到 build 文件夹。在 Windows 文件夹中,我看到 MP testing.exe,这是独立游戏的可执行文件。要将其发送到另一台机器,我必须将整个 Windows 文件夹发送过去,因为可执行文件依赖于其他文件和文件夹。 我将这个文件夹放在 Google Drive 上,然后在另一台机器上下载。完成下载后,打开下载文件夹,找到这个 Windows 文件夹(以 zip 格式)。右键单击并选择“全部提取”,提取后将其重命名为“LAN Connection”,然后打开。 现在我可以双击 MP testing.exe 启动游戏,或右键选择打开。如果弹出警告,选择“更多信息”并点击“仍要运行”。启动游戏后,如果按下数字 1 键,将打开“lobby”关卡并设置为监听服务器。等待另一位玩家启动游戏并按下数字 2 键,他们就可以加入游戏,并与我一起玩。 总结我们学习了如何在 Unreal Engine 编辑器中测试多人游戏,以及如何设置局域网连接,打包游戏并在连接到同一本地网络的两台计算机上进行游戏。在下一节视频中,我们将学习如何使用 C++ 函数设置局域网连接。下次见! 3. 局域网连接欢迎大家。在本次讲座中,我们将设置一个局域网连接。这次我们将使用C++函数,而不是蓝图节点。我们已经通过蓝图建立了局域网连接,但了解如何通过C++实现这些功能也很有用。接下来,让我们开始。 这是我们在创建C++项目时生成的Visual Studio项目。在解决方案资源管理器中,我将打开源文件夹,接着打开MPTesting,并进入MPTestingCharacter.h。在这里,我想创建几个简单的可调用蓝图函数。所以,我将滚动到公共部分的底部,创建几个函数。第一个是一个返回类型为void的函数,我将其命名为OpenLobby,并给它一个UFunction宏,使其可被蓝图调用。如果你不熟悉如何创建函数并使其可被蓝图调用,我建议你参加我的其他关于虚幻引擎C++基础的课程。 现在我们可以为OpenLobby创建函数定义。顺便说一下,我还将创建另外几个函数。第一个,我将简单地命名为CallOpenLevel。在这个函数中,我们基本上将做和蓝图中相同的事情。现在,我将为这个函数添加一个类型为const FString的输入参数,并将其定义为常量引用,我将其命名为Address,这将用于IP地址。接下来,我将复制函数宏并将其粘贴到CallOpenLevel的上方,以使其成为可调用的蓝图函数。 通常在虚幻引擎中,有多种方法可以实现相同的功能。我将展示两种不同的方法来打开一个关卡。因此,我们将为此创建两个不同的函数。下一个函数将命名为CallClientTravel,我们也将使用const FString引用作为输入参数的类型。与其他函数一样,我们将使其可调用蓝图。接下来,让我们为这两个函数实现定义。我们将为CallOpenLevel和CallClientTravel创建定义。 接下来,让我们打开MPTestingCharacter.cpp,看看这三个函数。第一个是OpenLobby。在这个函数中,我们将调用新世界类中的一个函数。首先,我们需要获取世界的访问权限,我们可以说: 现在,回到编辑器,我可以通过查找大厅关卡,右键单击并选择“复制文件路径”来确定该路径。在Visual Studio的下一行,我将简单粘贴我复制的内容,你会看到它显示了大厅关卡的文件路径。需要注意的是,当我们传递关卡路径时,我们不需要传递完整路径。到内容文件夹的所有内容可以用“Game”来替代。所以我们输入 接下来,我们需要实现CallOpenLevel。对于CallOpenLevel,我们将使用一个游戏静态函数,称为OpenLevel。这里是关于该函数的虚幻引擎文档,它位于GameplayStatics中,函数签名的描述并不太详细,但我们可以获取GameplayStatics的包含内容。所以我们将复制这个包含内容,然后回到MPTestingCharacter.cpp,粘贴包含GameplayStatics的代码。现在我们可以使用GameplayStatics函数并调用OpenLevel。 我们将使用新的GameplayStatics函数OpenLevel。第一个输入参数是一个世界上下文对象,我们可以传入 接下来,另一种旅行到关卡的方法是使用一个称为ClientTravel的函数。这里是关于ClientTravel的虚幻引擎文档。你可以看到它是一个在PlayerController类中的函数。因此,我们需要PlayerController来调用这个函数,它表示旅行到一个不同的地图或IP地址。为了调用ClientTravel,我们需要PlayerController,可以通过游戏实例获取。如果我们调用GetGameInstance,这个函数返回一个UGameInstance,并且在UGameInstance中,有一个获取第一个本地PlayerController的函数,称为GetFirstLocalPlayerController。这个函数返回一个APlayerController,我们可以将其存储在一个类型为APlayerController指针的局部变量中。我们将其命名为PlayerController,并将GetFirstLocalPlayerController返回的值赋给我们的PlayerController变量。 一旦我们获取了PlayerController,我们可以添加一个效果来确保它不是空值。所以我们可以检查 你会看到我们有更多的输入参数,下一个没有默认值,所以我们需要提供一个。它是类型ETravelType,一个特定的枚举,用于指定我们旅行到新关卡的方式。稍后我们会讨论这些旅行类型。现在,我们只需传入ETravelType枚举常量中的N。我们在这里选择 接下来,让我们编译我们的代码。如果你忘了如何编译,可以去“构建”并选择“构建解决方案”,我简单地使用Control + Shift + B。一旦我们编译完成,我们可以回到编辑器,现在我们可以使用这些可调用的蓝图函数。 我将回到蓝图文件夹,打开第三人称角色蓝图。现在,我希望使用我的可调用蓝图函数。对于按键1,我想调用我们的新可调用蓝图函数OpenLobby。这是我们的C++函数,在其中我们硬编码了大厅关卡的路径并调用了ServerTravel。对于按键2,我希望调用我们创建的可调用蓝图函数CallOpenLevel。这将需要一个IP地址,我将使用我的本地IP地址,所以我将填写这个地址。如果你使用的是本地IP地址,你必须确保传入的是你的IP地址,而不是我的,否则将无法连接。 对于按键3,我希望使用我们创建的第三个可调用蓝图函数CallClientTravel。与上一个函数一样,它也需要地址。我将把我的IP地址粘贴在这里。现在我可以编译并保存,这样我们就准备好测试了。我将返回大厅,并打包这个游戏。 这是我的构建文件夹,其中包含之前打包的游戏。我将删除它。现在,在编辑器中,我将转到“平台”,“Windows”,并选择“打包项目”,然后选择构建文件夹。因此,我会点击选择文件夹。现在打包完成后,我可以将这个打包项目发送到另一台计算机上。这里是我的Google Drive,我之前上传了打包项目。我将右键单击Windows文件夹并删除它,以免造成对我正在使用的项目版本的混淆。现在,这是我新打包的项目在Windows文件夹中。将整个Windows文件夹拖到我的Google Drive上。一旦上传完成,我将在另一台计算机上下载并提取,就像之前那样。 一旦我在另一台机器上下载了我的项目,并准备好测试者来启动游戏并加入我的游戏,我将启动我的打包可执行文件。这里是它,我将双击启动,并按下1键以打开指定为监听服务器的关卡,等待另一台机器上的测试者按下2键。好了,他们来了,现在我们可以玩了。通过局域网连接,就像我们之前所做的那样。只不过现在我们是通过C++函数连接的。 接下来,我将再次启动游戏。这次,我的另一台机器上的测试者将通过3键加入。因此,我将打开关卡并 等待他们加入。好了,他们来了,我们准备好玩游戏了。完美。在本视频中,我们使用C++函数而不是之前视频中的蓝图节点设置了局域网连接。设置局域网连接相对简单。困难的部分是连接不同网络上的机器。接下来的课程将专注于创建可以通过网络连接的游戏,而不仅仅是通过局域网连接。在接下来的视频中,我们将学习如何设置这样的连接。下次见。 4. 在线子系统欢迎大家。在本视频中,我们将详细讨论IP地址,具体是什么,以及本地IP地址和公共IP地址之间的区别。接着,我们会讨论游戏如何能够在互联网上彼此连接,而无需知道对方的IP地址,这涉及到虚幻引擎的在线子系统。让我们先花点时间了解IP地址。 到目前为止,我们已经能够连接到同一局域网中计算机上的游戏实例。但我们希望与不在我们本地网络上的玩家连接。在继续之前,让我们讨论一下这究竟意味着什么。你的本地IP地址,也称为内部IP地址,是由本地网络路由器分配给你的计算机的地址。它通常以192.168开头,后面跟着更多数字。大多数网络路由器会为不同设备分配内部IP地址,这些地址可能会根据设备连接的顺序而变化。这些地址仅在你的本地网络内可见,外部网络无法通过本地IP地址连接到你的计算机。 你的计算机通过以太网电缆或Wi-Fi信号与路由器相连,而路由器则与你的互联网服务提供商(ISP)相连。为了让你的计算机连接到互联网,互联网服务提供商会将一个外部或公共IP地址分配给你的路由器。这个外部IP地址是互联网上其他人看到的。来自互联网的信息首先会发送到公共IP地址,然后再转发到你的本地IP地址。 我们已经看到在局域网连接中连接游戏是多么简单。因为两台计算机在同一局域网中,所以一台计算机可以使用其本地IP地址连接到另一台。但如果你想与在国家另一端甚至世界另一端的人一起玩游戏呢?这个人很可能连接到不同的局域网,因此连接到他们的本地IP地址是不可行的。如果你知道对方机器的公共IP地址,你可以连接到它。但这并不是理想的选择,因为你永远无法知道别人的IP地址,除非他们告诉你。 你有没有想过,多少次你登录你最喜欢的视频游戏时,需要输入你朋友的IP地址?如果你没有玩这个游戏的朋友呢?难道你只能孤单地玩?当然不是。你通常登录游戏,游戏本身会为你找到其他玩家。无论他们身在何处,你只想玩你的游戏。那么,你的视频游戏是如何知道如何找到其他在线玩家的IP地址的呢? 答案有很多种。有时游戏有自己的专用服务器,当你登录时,你连接到其中一个服务器,该服务器有一份可以连接的IP地址列表。服务器选择一个,并向你显示已登录的朋友的名字,并将你连接到该玩家。但设置专用服务器需要时间和金钱。玩家越多,你的游戏需要的服务器、存储和处理能力就越多。你可以通过使用“监听”服务器来规避这个问题。一名玩家启动游戏并设置为监听服务器,其他玩家作为客户端加入。但问题仍然存在:客户端如何知道要连接哪个IP地址,以便将你的游戏连接到在线的其他人? 这必然需要一个中间环节。你的游戏在登录时会发送信号到某个服务器,该服务器将你连接到其他正在登录的玩家。游戏通常会通过一个服务来托管这些服务器,因为这比创建自己的服务器更省时,而且通常提供附加功能,如安全性和好友系统。要设计一个系统来托管游戏、维护玩家安全并扩展到处理大量用户,需要超越单纯编写游戏逻辑的专业知识。如果你希望将游戏发布到一些流行的服务,如Xbox或PlayStation,你必须重写你的游戏系统,以便与他们的代码库兼容。 如果我们能够只学习一个代码库,然后让我们的游戏连接到任何我们选择的服务,那将多好。而这正是我们要做的,这将涉及虚幻引擎的在线子系统。 我们的目标是创建一个游戏,能够在不需要知道对方IP地址的情况下,加入其他已登录的玩家。为此,虚幻引擎为我们提供了一个在线子系统。当你在虚幻引擎中制作一个多人游戏时,通常会连接到一个管理游戏会话并将来自世界各地的玩家连接在一起的服务。这些服务包括Steam、Xbox Live、Facebook游戏等等。你的游戏连接到其中一个服务,该服务有自己的代码来处理玩家之间的连接。例如,Steam有自己用于连接玩家、设置好友列表等的代码。 那么,这是否意味着你需要学习所有Steam的代码库?如果你想将游戏移植到Xbox,又该怎么办?你需要学习Xbox Live服务的所有代码吗?这将非常不方便。虚幻引擎为我们提供了一种方式,仅使用一个代码库,即虚幻引擎的代码库。虚幻引擎有我们可以用来连接服务的函数,具体取决于我们游戏配置使用的服务。虚幻引擎将在幕后处理所有平台特定的细节,当一个程序或游戏引擎允许我们仅与单一代码库交互时,这被称为抽象层。我们只处理虚幻引擎的代码,其他平台特定的代码被抽象掉,因此我们无需担心它。 虚幻引擎的网络抽象层旨在连接各种在线服务,称为在线子系统。虚幻引擎的在线子系统包含我们可以用来连接服务、托管我们的游戏会话并将我们连接到其他玩家的函数。我们指定使用哪个服务,虚幻引擎在幕后处理该服务的特定内容。这使得创建多人游戏变得非常强大。我们可以使用虚幻引擎的在线子系统编程我们的游戏,而无需更改代码以将游戏发布到不同的服务。我们只需为新服务配置项目。 因此,由于我们只需处理抽象层,所以选择哪个服务实际上并不重要。在本课程中,我们选择Steam,因为它是托管多人会话的最受欢迎的服务之一,而且很容易入门,学习如何使用,而无需申请开发者许可证或支付费用。当然,一旦你有了想要出售的游戏,并希望在Steam商店中上架,可能需要做所有这些事情。但在你学习的过程中,你仍然可以使用Steam来托管你的会话,以确保游戏在你迈出下一步之前正常运行。 我们这一部分的目标是创建一个系统,允许我们启动游戏并简单按下一个按钮,然后我们的游戏将搜索任何在线并已登录的玩家,并与其中一名玩家连接。我们不想输入某人的IP地址,只想点击播放。因此,在这一部分中,我们将设计并创建这个系统,同时将其打包成一个精美的小插件,以便我们可以将其添加到新的虚幻引擎项目中并重复使用。 一旦我们创建了这个系统,就不必在我们计划制作的新多人游戏中再次创建它。稍后,我们将把我们的代码打包成一个紧凑的模块,可以插入任何项目并使用。听起来很棒,对吧?确实如此。一旦我们创建了一种通过互联网连接游戏与其他玩家的方法,我们就可以专注于为我们的多人游戏创建游戏逻辑,然后可以在其他虚幻引擎项目中重用我们的代码,制作全新的多人游戏。这是你游戏开发和虚幻引擎学习的下一个层次。当你与其他玩家一起游戏时,一切都会变得更加有趣。 在下一个视频中,我们将讨论虚幻引擎的在线子系统,它如何工作,并制定一个简单菜单系统的游戏计划,以便与我们将创建的小插件连接。总结一下,我们学习了IP地址及其本地IP地址仅在本地网络中使用,而路由器的公共或外部IP地址则是其他互联网连接到的地址。我们了解到,为了在不知道另一台计算机IP的情况下连接到它,我们需要一个中间步骤,无论是我们的专用服务器还是专业服务如Steam或Xbox Live托管的服务器。我们学习到虚幻引擎有自己管理连接在线服务的代码库,称为虚幻引擎在线子系统。我们了解到这个在线子系统为我们提供了一个抽象层,这样我们就不需要学习每个服务的代码库,只需学习虚幻引擎的代码,我们将学习如何使用这个在线子系统,以便只需编写一次代码连接到其他已登录的玩家,然后将其打包成可以在多个虚幻引擎项目中使用的插件。我们将深入讨论这些概念,同时创建旨在连接到其他互联网玩家的菜单系统。我们很快再见。 5. 在线会话欢迎。在本讲中,我们将讨论虚幻引擎在线子系统类的作用,以及它包含的与多人游戏会话相关的多个接口。我们将深入探讨会话接口,这是一个旨在处理设置和加入游戏会话的接口,并制定一个使用该接口将我们的游戏连接并与其他玩家一起游戏的计划。 首先,让我们谈谈在线子系统。在线子系统提供了一种访问在线平台服务功能的方法。这里的在线平台指的是像Steam和Xbox Live等服务。每个平台都有其支持的服务集,包括好友、成就、设置匹配会话等功能。在线子系统包含了一组接口,用于处理每个平台的不同服务。通过在线子系统,我们可以处理这些接口,无论我们选择哪个服务,只需在项目的配置文件中进行相应的配置即可。我们将在即将到来的课程中一起学习这个过程。 在线子系统是一个类型为 IOnlineSubsystem 的类,可以通过该类的静态函数 Get 访问。这个函数返回一个指向类型为 IOnlineSubsystem 的在线子系统的指针。一旦我们获得了在线子系统,就可以访问之前提到的不同接口。当前我们最关心的接口是会话接口。会话接口负责创建、管理和销毁游戏会话,并处理搜索会话和其他匹配功能。可以将会话视为在服务器上运行的游戏实例,具有一组属性。会话可以被公开,便于其他玩家找到并加入,或者是私密的,只有被邀请的人才能加入。 典型的游戏会话的基本生命周期如下:
目前我们只需关注几个关键的功能,具体为:CreateSession(创建会话)、FindSessions(查找会话)、JoinSession(加入会话)、StartSession(开始会话)和 DestroySession(销毁会话)。通过使用这些功能,我们可以建立一个可工作的游戏。 接下来,我们将讨论如何实现这一点。我们的目标是能够在游戏菜单中点击一个按钮。现在,我们假设有两个菜单按钮:“主持”和“加入”。当玩家点击“主持”时,我们的代码将配置会话设置,然后调用会话接口的 CreateSession 函数。完成后,我们可以打开大厅级别,等待其他玩家加入。当有人开始游戏并点击“加入”时,我们将配置一些搜索设置,以帮助过滤出不想加入的游戏会话。然后我们将调用接口函数 FindSessions。这将返回一些搜索结果,我们将遍历这些结果并选择一个有效的会话,接着调用会话接口的 JoinSession 函数。完成后,我们将能够获取正确的IP地址,并使用 ClientTravel 函数加入其他玩家的监听服务器,与他们一起进入大厅级别。 我们将把所有这些功能放入一个专门处理这些会话相关特性的整洁类中。但我们不想一开始就创建太多新类。现在,我们将从角色类中访问在线子系统,并调用这些函数,看看一切是如何工作的。一旦我们理解了如何使用在线子系统及其会话接口函数,我们将创建自己的类来处理这些功能,并将其设计为可以在我们想要的任何游戏中使用。 在下一个视频中,我们将创建一个新项目,并将其配置为Steam平台。这样,我们在会话接口中调用的任何函数都将自动连接到Steam平台并访问其在线会话服务。随后我们将在角色类中访问在线子系统,并在屏幕上打印一些文本,以确保我们成功连接到Steam。 总结一下,我们了解了更多关于在线子系统的信息,以及它包含的接口,这些接口具有连接到我们选择的在线平台服务所需的所有功能。我们目前最感兴趣的是会话接口,它包含了设置和管理游戏会话所需的所有功能。然后,我们为游戏制定了一个计划,将作为设置会话代码时的指导。我们将开始使用这些会话相关函数,并在角色类中了解它们的工作原理,随后再创建一个专门处理游戏会话相关功能的类。再见,期待与您再次相见。 6. 为Steam配置欢迎。在本讲中,我们将创建一个新项目,并将其配置为使用Steam平台。之后,我们将访问在线子系统,并在屏幕上打印一些文本,以验证我们是否已成功连接到Steam。让我们开始创建新项目。 我已经打开了Epic Games启动器,现在要启动虚幻引擎5。接下来,我选择“游戏”,并选择第三人称模板,这样我们可以有一些能够四处奔跑的角色。确保这是一个C++项目,我的项目位置设置为C:\multiplayer。现在,我们将为该项目创建一个菜单系统,项目名称定为“菜单系统”,然后点击“创建”。 现在新项目已打开。首先,为了将此项目配置为Steam,我们需要启用Steam插件。我们可以在菜单中选择“编辑”,然后选择“插件”,打开插件菜单。在插件菜单中,我可以使用搜索栏,搜索“在线子系统Steam”,你会看到一个名为“在线子系统Steam”的插件,它提供了对Steam平台的访问。我们需要启用它,所以我会点击“启用”,现在编辑器告诉我必须重启虚幻编辑器才能使插件更改生效。让我们点击“立即重启”。 编辑器已经重启,我可以关闭插件窗口。接下来,我们需要实际启用Steam模块。我将缩小这个窗口,进入我的Visual Studio项目。模块是引擎中的代码包。如果我点击EUI 5旁边的下拉菜单,我们会看到一个名为“插件”的文件夹,展开后可以看到构成引擎各个部分的不同插件。每个插件都是一个模块,包含特定功能的代码。 为了访问特定模块,我们需要将其添加到构建文件中。如果我点击“源”旁边的下拉菜单,再点击“菜单系统”旁边的下拉菜单,我会看到一个名为“menu_system.Build.cs”的文件。点击它,这个文件包含了“PublicDependencyModuleNames”,任何列在这里的模块将在项目中可用。我们将通过添加逗号和模块名称(用双引号括起来)来向此列表添加一个模块,这个模块将是“OnlineSubsystemSteam”。添加完“OnlineSubsystemSteam”后,我们还需要添加“OnlineSubsystem”。这两个模块是不同的,在线子系统是与Steam进行交互的整体子系统,而在线子系统Steam是我们将用于连接Steam的特定子系统。 现在让我们编译一下。编译成功后,我们需要将项目配置为使用Steam作为在线子系统。为此,我将打开包含项目的文件夹。在该文件夹中,有一个名为“Config”的文件夹,打开后我们可以看到一些以.ini为扩展名的配置文件。我们可以使用文本编辑器打开“DefaultEngine.ini”,我将使用Notepad++。 这是“DefaultEngine.ini”文件。我们只需在此文件中添加一些内容,以便我们的项目配置为使用Steam。下面是虚幻引擎在线子系统Steam的文档。如果你想进一步了解,可以阅读这篇文章。向下滚动,我们会看到关于需要添加到“DefaultEngine.ini”的设置的信息。 首先,我们需要在“DefaultEngine.ini”文件中包含一个名为“[/Script/Engine.GameEngine]”的部分,并包含“[OnlineSubsystem]”的定义。网络驱动程序是用于将计算机连接到网络的程序。我们需要将网络驱动程序设置为Steam网络驱动程序,以便使用Steam网络。 我们还将定义一个在线子系统部分,将默认平台服务设置为Steam。这样,我们配置了游戏以使用Steam网络服务。接着,我们需要添加“[OnlineSubsystemSteam]”部分,启用Steam并设置我们的Steam开发应用ID。我们使用开发者ID 480,因为我们没有自己的Steam开发应用ID。你可以去Steam网站申请自己的开发应用ID,但在这之前,你可以使用开发应用ID 480,这是Steam的示例项目“Space War”的ID。许多人使用此开发应用ID,以便在没有自己开发应用ID的情况下学习如何使用Steam服务。 我们还需要这个附加部分“[OnlineSubsystemSteam.SteamNetDriver]”,以便将“NetConnectionClassName”设置为“OnlineSubsystemSteam.SteamNetConnection”。这些是我们需要配置项目以使用Steam的设置。现在,我们将复制这些内容并添加到“DefaultEngine.ini”中,然后保存。 我们已在“DefaultEngine.ini”中添加了一些设置。接下来,我将返回到包含项目的文件夹,并重新生成Visual Studio项目文件,以确保所有内容都已更新。在此之前,我将关闭Visual Studio项目,并关闭虚幻引擎项目。 在重新生成Visual Studio项目文件之前,我将删除一些自动生成的文件夹:Saved、Intermediate和Binaries。然后我可以右键点击“.uproject”文件,选择“生成Visual Studio项目文件”。由于我使用的是虚幻引擎5,所以选择该版本,然后点击“确定”。 你会看到Saved和Intermediate文件夹已恢复。让我们双击新项目以重新打开它,并会提示我们重建缺失的模块。这是因为我们删除了一些文件夹。我将点击“是”,现在你会看到Binaries文件夹又回来了。 项目已再次打开,我将缩小它并再次打开“.sln”文件,这是我的项目。关闭Builder.cs文件。现在我们的项目已配置为将Steam作为其子系统,我们可以在代码中访问在线子系统。在下一个视频中,我们将通过代码访问在线子系统,并添加一些屏幕调试消息,以显示该子系统的名称,以便我们能看到是否成功连接到Steam。 总结一下,我们创建了一个新项目,并将其配置为使用Steam作为在线子系统。我们已将“OnlineSubsystem”和“OnlineSubsystemSteam”模块添加到项目的构建文件中的公共依赖模块名称中。现在我们可以访问在线子系统,并准备在代码中开始使用它。再见,期待下次见面。 7. 访问在线子系统欢迎大家。在本次讲座中,我们将通过代码访问在线子系统,并将子系统名称打印到屏幕上。这样我们就能看到我们连接的是哪个子系统。首先,我们需要在代码中访问在线子系统。正如我之前提到的,我们将创建一个类来处理所有与会话相关的代码,但在深入学习这些函数如何工作之前,我们将暂时将一些代码添加到我们的角色类中。模板创建了一个菜单系统角色类,所以我们现在打开 首先,我想滚动到文件底部并创建一个公共部分,以便将与会话相关的代码集中在一起,这样就不会与其他代码混淆。我们添加一个公共部分,并在这里放置所有与在线会话相关的变量和函数。 接下来,我们进入 这是 现在我们可以检查这个指针是否有效。如果指针有效,我们就可以使用 这个指针是一个特定类型的智能指针,不能前向声明。我们可以看到其类型,通过悬停可以看到它是 我们接下来尝试编译代码,看看是否有错误。出现了一些错误,因为 为了避免在头文件中包含 接下来,我们希望验证是否找到了在线子系统,并查看我们正在使用哪个子系统。我们可以使用引擎提供的 参数包括 运行游戏时,我们应该能访问在线会话接口,并打印出我们连接的在线子系统的名称,预期是 Steam。现在让我们尝试编译。 如果您看到“无法删除热重载文件”的消息,这通常是延迟问题。处理此问题的方法是关闭 Visual Studio 和 Unreal Engine 编辑器,然后删除 确保您有一个 Steam 帐户。如果没有,请创建一个并安装 Steam 应用。启动 Steam 应用并登录后,再运行 Unreal Engine 游戏连接 Steam。 现在返回编辑器,您应该看到“找到子系统:NULL”。这并不是指指针为空,而是 Unreal Engine 实际上有一个名为 NULL 的在线子系统,旨在进行局域网连接。我们在连接 Steam 在线子系统时遇到了一些问题。您可以尝试以下方法:首先,在 PC 上测试游戏,或使用“在编辑器中播放”。然后更改网络模式为专用服务器或监听服务器。查看调试消息,然后打包游戏并测试打包后的构建,看看是否连接到了 Steam。 暂停视频,尝试一下这些步骤。我们发现如果仅在编辑器中播放,会显示“找到子系统:NULL”。当我们更改网络模式为监听服务器并播放时,仍然看到 NULL。最后,当我们更改网络模式为客户端并播放时,仍然看到“找到子系统:NULL”。 下一步是打包构建。我将选择平台,Windows,然后选择“打包项目”。在项目文件夹中创建一个名为 Build 的新文件夹,并将打包后的项目存放在其中。打包完成后,返回项目文件夹并打开 Build 文件夹,双击可执行文件启动它。此时,您应该在左上角看到“找到子系统:Steam”,并且右下角会弹出 Steam 通知,确认我们已连接。 通过这些步骤,我们验证了在打包的项目中,我们能够连接到 Steam 在线子系统。接下来的视频中,我们将使用存储的会话接口指针,调用 总结一下,我们创建了一个新项目,并配置它使用 Steam 作为在线子系统。我们还在角色类中访问了在线子系统,并创建了指向在线会话接口的指针。在下一节课中,我们将使用这个指针。期待与大家再次见面! 8. 创建会话在线会话接口与 C++ 中的指针检查在线会话接口应持有会话接口。但在 C++ 中,正如你所知,使用指针之前检查其有效性是很好的习惯。我们将使用一个 F 检查,并利用我们的在线会话接口指针。作为类型 T 的智能指针共享指针,我们检查其有效性的方法是使用 如果我们通过了这个 if 检查,那么会话接口确实有效。一旦我们开始创建会话,我们会迅速发现如果我们已经创建了一个会话,就不能在不先销毁现有会话的情况下创建另一个会话。这意味着我们要做的第一件事是检查会话是否已经存在。我们将使用我们的在线会话接口指针,并调用函数 获取命名会话返回一个类型为 F 命名在线会话的对象。我们将把它存储在一个叫做 创建新会话与会话设置现在我们准备创建一个新会话,这将涉及设置一些会话设置。这里是 F 在线会话设置的文档页面。这是创建新会话时会话设置的类型。我们将包括 这是一个非正式化指针。为了创建此类型的新对象,我们需要构造一个。初始化新共享指针的方法是使用 F 在线会话设置类有几个变量可以用于我们的会话设置。我们不会立即讨论这些变量。我们将简单地使用它来调用 首先,我们需要这个 F 唯一网络 ID。获取它的方法是通过获取世界的第一个本地玩家。我们将创建一个联系本地玩家的指针,称为 创建会话的参数与委托我们需要在返回值前使用解除引用运算符。接下来是会话名称,我们将再次使用 现在我们调用 验证会话的创建与反馈现在我们调用 我们将使用 测试与配置会话设置我们将在成功情况下复制这个消息,并将其颜色改为蓝色。对于字符串,我想使用 接下来,我们将设置一些会话设置。在线会话设置类有几个变量。我们将使用其中一些来配置即将创建的会话。我们将说 会话设置还有一个连接数的设置,决定多少玩家可以连接到游戏。它叫做 下一个会话设置是 我们的最后一个设置是 测试游戏与解决常见问题现在我们已经设置了传入 现在我们准备测试我们的游戏。我将首先保存所有内容,然后转到平台,选择 Windows,并打包项目。这里还有上次打包的构建,我将简单删除它。在我的构建文件夹中,我将选择文件夹。现在我们正在打包游戏。 现在打包完成,我可以在我的项目中打开该构建文件夹。在构建文件夹中,这是 Windows 文件夹,其中有我的菜单系统 .xy。我将双击它以启动游戏。现在我看到左上角找到子系统 Steam。因此我们连接到 Steam,并准备尝试创建会话。我将按下数字键 1,看到创建的会话,名称 为 接下来的步骤是实现从另一台机器加入会话的功能。在下一个视频中,我们将继续创建一个大堂级别。创建会话后,我们将前往此级别,在那里我们可以等待其他玩家加入。我们还将设置一个加入会话的功能。这样我们可以打包项目,并将其发送到另一台机器,后者可以启动项目并通过互联网加入我们的运行游戏会话。 总结与常见错误解决总结一下,我们回顾了委托以及它们在管理虚幻引擎中的在线会话中扮演的重要角色。我们创建了一个 F on create session complete 委托以及一个回调函数,然后将其绑定到这个委托,并将这个委托添加到会话接口的委托列表中。最后我们调用了 如果你在创建会话时遇到任何问题,特别是在使用 Unreal Engine Preview 2 或 Unreal Engine 5.0(最新正式发布)时。我有一些学生在没有以下代码的情况下无法创建会话, 另外,有人遇到问题,即创建 C++ 项目时出现崩溃,使用第三人称模板或第三人称角色。这是虚幻引擎 5 中的一个已知错误,仍需修复,与第三人称角色的动画蓝图相关。有几种方法可以解决这个问题。首先,你可以找到第三人称蓝图,打开第三人称角色,选择网格,然后在动画类中将其设置为 none。这意味着角色将处于 T 姿势,但如果你只是想检查连接,这就没问题。 如果你想测试具有复制角色的多人游戏,另一种选择是简单地使用旧的第三人称人偶,因此你可以从其他项目中获取人偶,或者创建一个旧的 Unreal 4 项目,使用第三人称角色。不管你如何获得,你可以将该人偶的角色蓝图迁移到你的项目中。对于此类不稳定性,抱歉。这是 Unreal Engine 5 仍需修复的一个问题。 有些学生遇到此错误消息,表示 Windows SDK 未正确初始化,无法生成数据。如果你在打包时收到此消息,解决方案很简单。你需要确保拥有最新的 SDK 以及 .NET Core 3.1 运行时 ELTs,可以通过更新 Visual Studio 的 Visual Studio 安装程序来确保这一点。因此,打开你的 Visual Studio 安装程序,并在你使用的版本中,修改并转到单个组件,确保安装 .NET Core 3.1 运行时 ELTs。这些是一些并不明显的事情,但使用虚幻引擎的新版本,我们正在使用更新的技术,需要确保拥有所有必要的组件。更新你的 Visual Studio 并确保安装该组件是个好主意。 9. 设置加入游戏会话创建加入游戏会话的蓝图可调用函数欢迎回来。在本讲中,我们将创建一个可以从角色类调用的加入游戏会话蓝图可调用函数,并开始设置查找和加入游戏会话的功能。这将涉及为“查找会话完成”创建一个委托,该委托将在调用会话接口函数 创建加入游戏会话函数首先,我们需要创建我们的蓝图可调用函数 在这个函数中,我们将首先查找会话,因此我会在这里添加一个注释,说明我们将在这里“查找游戏会话”。我们将调用会话接口函数 创建委托和回调函数为了查找会话,我们需要为查找游戏会话创建一个委托和回调函数。因此,这将是我们的下一步。与会话接口函数 我也可以为这个回调创建一个定义,这个函数将在会话接口广播查找会话完成的操作时被调用。现在我们有了委托和回调,是时候将回调绑定到我们的委托上了。 我们已经将一个函数绑定到委托上,我们将在构造函数中执行相同的操作,正如我们为
设置会话搜索设置现在我们已经构造了委托并将回调函数绑定到它,是时候开始设置一些会话搜索设置了,这将在调用会话接口函数 在我们的 我们将设置一些会话搜索的设置。我们将说 我们的会话搜索还有一个变量叫做 现在,在函数的底部,我准备调用 接下来输入的是类型为 现在我们在调用 处理查找会话完成的回调最后,我想确保我们实际上找到了某些会话。我们将转到 我们将拥有一个类型为 接下来,我们可以使用 一旦我们找到一些会话,我们可以遍历找到的会话并将其打印到屏幕上。我们将使用 处理搜索会话设置与编译在找到会话后,我们可以打印 出从每个找到的会话中获取的数据。现在,在测试之前,我们需要在会话搜索上设置另一个选项。因为我们使用了 presence,我们必须在搜索设置中指定这一点。因此,我们将说 当我们调用 处理常见问题与打包项目如果你使用的是 Unreal Engine Preview 2 或 Unreal Engine 5.0(最新正式版本),我发现一些学生在查找会话时遇到问题,解决这个问题的方法是将会话设置中的布尔值 在保存整个项目后,我将打包它,以便可以在另一台机器上进行测试。因此,我将转到平台,选择 Windows,并打包项目。现在,这是我之前的构建,我将删除它并在我的构建文件夹中简单点击选择文件夹。现在我正在打包这个项目。 一旦我完成了这个项目的打包,我可以将其压缩并放在我的 Google Drive 上,以便可以从我的另一台机器下载。现在这是我的项目文件夹。我将打开构建文件夹并简单地将其压缩。因此,我将右键单击,选择发送到压缩文件夹,一旦我完成压缩,就可以将其放在我的 Google Drive 上。 现在我在这里有我之前的构建。我将简单地右键单击并选择移除,以便不会混淆打包项目在哪里,并且我将上传它。现在,我已经上传了压缩的项目,并且我已经到达另一台机器并下载了它,我在该机器上提取了项目并从那里启动了游戏,按下数字键 1。请记住,当我们按下数字键 1 时,我们正在创建一个游戏会话。因此,我在另一台机器上创建了一个游戏会话,现在我将从这台机器加入。 我将打开我的构建文件夹,打开 Windows 文件夹并启动 总结与下一个步骤在下一个视频中,我们将获取要加入的 IP 地址,并根据找到的搜索结果加入游戏会话,这样我们就可以在两台不同的机器上在同一个关卡中一起玩游戏。在本讲中,我们创建了一个名为 10. Steam区域Steam 区域概述欢迎回来!在本视频中,我们将快速回顾 Steam 用于连接玩家的区域设置。你会注意到我的游戏列表中有一个“Space War”。这是因为我正在使用开发应用程序 ID 80,这是 Space War 的开发应用程序 ID。当你连接到 Steam 在线子系统并进行游戏测试时,这会显示你正在玩这个游戏。 一旦你创建了一个会话,并从另一个游戏中加入,Steam 会使用 presence,这意味着它只会将你连接到同一区域的其他玩家。 设置 Steam 区域要查看或更改区域设置,你可以进入 Steam 的“设置”菜单。在“下载”选项中,有一个“下载区域”。这里显示 Steam 会自动选择最近的下载服务器位置,但可以被覆盖。如果你在进行两台相对接近的机器的测试,这个设置可能会自动设置为相同的区域。但是,如果你与在国家另一端或全球另一端的人进行测试,确保你们的区域设置相同是非常重要的。 例如,我的区域被自动设置为美国凤凰城,这是离我最近的区域。只要两台机器的 Steam 账户设置在相同的区域,就应该能够找到并加入会话。因此,如果你与其他人或另一台机器进行测试,请确保两台机器的 Steam 账户都设置为覆盖该区域,以便你们连接到同一 Steam 区域的服务器。 关键要点
这样做可以确保你们能够顺利连接并进行游戏测试。下次见! 11. 加入会话创建游戏大厅关卡欢迎回来!在本讲中,我们将创建一个大厅关卡,以便在创建游戏会话后可以前往该关卡并等待其他玩家加入。我们还将指定会话设置中的匹配类型,以确保在找到会话后能够检查该会话是否配置为正确的匹配类型。 创建大厅关卡首先,让我们创建大厅关卡。在我们的菜单系统项目中,我将进入 然后,我将保存当前关卡,命名为 连接大厅关卡在 Visual Studio 项目中,我将找到 要指定路径,我可以通过右键单击大厅关卡资产并选择“复制文件路径”来轻松获得路径。在 Visual Studio 中,我将粘贴这个路径。我们不需要完整路径,一切到内容文件夹的部分可以用 指定匹配类型现在我们已经有了大厅关卡,并将在创建会话后打开它。接下来,我们需要在会话设置中指定匹配类型。我们的游戏可能有不同的匹配类型,例如自由对战或团队对战。我们将使用会话设置的 我将使用 检查匹配类型在我们的 加入游戏会话为了加入游戏会话,我们需要设置一个新的委托和回调。委托的类型为 在构造函数中,我们将构建并绑定这个委托。接下来,我们将在找到匹配类型后调用 获取 IP 地址并旅行到大厅获取 IP 地址时,我们将使用 打包和测试在代码编写完成后,我们将编译代码并在编辑器中保存所有内容,打包项目以进行测试。我们删除之前的构建并重新打包。上传新的构建到 Google Drive 后,在另一台机器上下载并解压。 测试时,我的测试者在其机器上创建了会话并等待我加入。之后,我能够顺利加入他们的游戏会话。我们可以相互主机和加入游戏会话,这证明了我们的系统可以通过 Steam 无缝连接。 小结在本讲中,我们创建了大厅关卡并为会话指定了匹配类型,同时实现了加入游戏会话的功能。接下来,我们将开始创建插件,使这个系统可以在任何项目中重复使用,无需每次创建新的多人游戏时都重新实现。我们将设置新的类来处理所有会话相关的功能。期待在下一个讲座中再见! 12. 创建插件创建多玩家会话插件欢迎回来!在本讲中,我们将创建一个新插件来处理我们的多人会话相关功能,并配置我们的插件以使用在线子系统,从而可以访问管理会话所需的所有在线子系统功能。 插件概述Unreal Engine 插件是为特定目的设计的代码和数据集合。开发者可以在每个项目的基础上轻松启用或禁用这些插件。它们可以添加运行时游戏功能,甚至在我们创建游戏时添加编辑器功能。插件可以通过引擎中的插件编辑器启用。 在 Unreal Engine 中,插件由一个或多个模块组成。模块可以视为 Unreal Engine 的构建块。引擎本身实现为大量模块的集合,每个模块都是自己独立的 C++ 代码单元,具有自己的构建文件。模块仅包含代码,因此不包含其他资产,如网格或纹理。这有助于将特定任务封装在一起,确保模块只负责其设计的内容,同时也保持引擎的组织结构。 我们的项目实际上也是一个模块。我们可以在项目的构建文件中查看项目依赖的模块。每当我们启用一个插件时,它会被添加到项目的 创建插件创建我们自己的插件实际上很简单。我们只需打开插件编辑器,通过“编辑”菜单选择“插件”。在插件编辑器中,有一个“新建插件”按钮。点击它后,我们会看到多个插件类型选项。我们将选择“空白插件”。接下来,我们可以为插件命名,由于我们的插件与多人游戏会话相关,因此我们将其命名为 我们还可以提供一些描述数据,例如插件的作者和简短描述,例如“用于处理在线多人会话的插件”。点击“创建插件”后,插件将成功创建。 检查和配置插件创建插件后,我们可以在内容浏览器中点击设置,启用“显示插件内容”。如果未勾选,请点击以启用它。接着打开 Visual Studio 项目,查看项目文件已被修改并包含新插件。我们可以看到新插件文件夹中包含 在源代码文件夹中,我们可以看到 配置插件依赖在新插件的 构建和验证插件在设置好依赖关系后,我们的 完成后,我们可以编译项目,以确保插件正常工作。编译成功后,我们将在项目文件夹中看到新插件的编译文件和中间文件夹。 总结在本讲中,我们创建了一个新插件,设置了插件依赖关系,使其依赖于在线子系统插件。我们还向插件的公共依赖模块名称中添加了几个模块。接下来,我们将开始添加类,以处理多人在线会话的功能。期待在下一节课中见到你! 13. 创建我们自己的子系统创建多人会话子系统欢迎回来!在本讲中,我们将创建一个类来处理所有的多人会话功能,并将实现一个自己的子系统。这将是一个游戏实例子系统,我们将讨论其含义以及如何运作。 选择父类创建处理多人游戏会话的新类时,首要问题是选择哪个父类。处理游戏会话时,一个不错的选择是游戏实例类。创建游戏实例类后,我们知道游戏实例将在游戏创建时生成,并且在游戏关闭之前不会被销毁。游戏实例在不同关卡之间持久存在,因此在切换关卡时,游戏实例仍然保持不变。这使得游戏实例成为包含多人会话功能的理想父类。 不过,游戏实例类可能会包含很多功能,不仅限于多人会话。因此,我们可以通过创建一种称为游戏实例子系统的类,使其与游戏实例共存,独立处理多人会话功能。 游戏实例子系统根据 Unreal Engine 的文档,子系统是自动实例化的类,具有管理生命周期的功能。子系统为程序员提供了易于使用的扩展点,可以立即获得蓝图和 Python 的支持,同时避免修改或重写引擎类的复杂性。这意味着我们无需将所有多人功能添加到游戏实例类中,而是可以创建自己的子系统。 游戏实例子系统将在游戏实例创建后自动生成,并在游戏实例关闭时被销毁和垃圾收集。使用子系统的优点包括节省编程时间,避免覆盖引擎类,并避免向忙碌的类添加 API。 创建多人会话子系统现在,让我们创建自己的游戏实例子系统。我们希望将子系统放在我们的 在选择父类时,我们会搜索 给我们的子系统命名为 编译与访问子系统关闭 Unreal Engine 和 Visual Studio 后,生成 Visual Studio 项目文件。生成后,双击新项目,确认缺少模块并点击“是”以构建这些模块。 在 Visual Studio 中,我们现在可以看到 添加在线子系统接口我们将在公共部分、保护部分和私有部分中添加基本内容。我们将定义构造函数并包含在线子系统的头文件,以便使用 在构造函数中,我们将访问在线子系统。通过 编译并准备下一步完成后,我们将编译项目,确保没有错误。接下来,在下一个视频中,我们将开始添加会话接口委托,并创建相应的回调函数,为使用会话接口功能做好准备。 小结在本讲中,我们创建了一个名为 14. 会话界面代理添加多人会话子系统功能欢迎回来!在本讲中,我们将向我们的多人会话子系统添加一些功能,包括可以从任何使用此子系统的类(例如菜单)调用的函数。我们还将设置子系统以使用在线会话接口,这将涉及添加一些委托和回调,以及一些委托句柄,以便在不再需要它们时可以从会话接口的委托列表中移除这些委托。 委托和回调概述管理在线会话涉及使用多个会话接口函数,例如创建会话、查找会话、加入会话、开始会话和销毁会话。这些函数都存在于会话接口中,但我们将在创建的子系统中处理所有这些,以便可以从其他类(如菜单)访问它。因此,我们的子系统需要一些公用函数。 在每个会话操作中,我们需要创建相应的委托,并为这些委托创建回调函数。完成特定委托后,我们应从会话接口的委托列表中移除它,并可以使用委托句柄来实现这一点。 添加功能到子系统现在,让我们开始向我们的 首先,我们创建一个 创建函数体在声明这些函数后,我们将使用 Visual Studio 的快捷键为它们生成函数体。我们将添加函数体的基础结构,以便可以在其中实现会话相关功能。 接下来,我们需要添加委托变量,以便将其添加到在线会话接口的委托列表中。我们将为每个会话操作创建相应的委托,包括:
创建回调函数对于每个委托,我们将创建相应的回调函数,放在受保护的部分。这些回调函数包括:
每个回调将根据功能需求接收不同的参数。 初始化委托和回调现在,我们将在构造函数中初始化这些委托并绑定回调。我们将使用成员初始化列表来完成这一点,确保每个委托都绑定到正确的回调函数。 每次添加委托到列表时,函数会返回一个 编译与下一步完成这些步骤后,我们将编译代码,以确保没有错误。我们的子系统现在已设置为使用在线会话接口的功能,并准备开始实现会话管理功能。 小结在本讲中,我们向 15. 菜单类创建菜单类与用户界面欢迎回来!在本讲中,我们将创建一个菜单类,并制作一个小部件蓝图,将我们的菜单 C++ 类设置为该蓝图的父类。我们还会在菜单中添加“主机”和“加入”按钮,以便通过点击按钮轻松创建或加入会话。 创建菜单类首先,在我们的菜单系统项目中,我们将创建一个新类,作为菜单小部件的父类。我们希望将此菜单类添加到我们的插件中,这样一来,当我们将插件插入到另一个项目时,菜单将已构建好,方便配置设置,例如连接数量和匹配类型。 在 选择 实现菜单类功能在 在 设置输入模式在设置输入模式时,我们需要获取世界,并从中获取第一个本地玩家控制器。我们将创建一个 同时,我们将获取玩家控制器并调用 创建菜单蓝图接下来,我们将创建一个小部件蓝图,命名为 在蓝图的图形视图中,我们将设置按钮的文本,分别命名为“Host”和“Join”。确保按钮大小一致,并根据屏幕大小调整锚点。 重新生成 Visual Studio 项目文件创建完蓝图后,我们将重新生成 Visual Studio 项目文件,以确保新的菜单类能在项目中正确显示。完成后,打开蓝图并设置其父类为刚刚创建的菜单类。 测试菜单功能为了测试我们的蓝图可调用的 当我们运行游戏时,应该能看到菜单并能够与按钮交互。虽然目前按钮还未编写功能,但我们已为后续的实现打下了基础。 小结在本讲中,我们创建了一个名为 16. 访问我们的子系统添加按钮回调和访问子系统欢迎回来!在本讲中,我们将为菜单小部件中的按钮添加回调,以便可以通过 C++ 函数响应按钮点击事件。同时,我们会从菜单 C++ 类中访问我们的多人会话子系统,以调用相关的功能。 创建按钮回调首先,我们需要创建按钮回调函数,这些函数将在点击按钮时被调用。在我们的 在 接着,我们将定义两个无输入参数的回调函数,分别为 绑定按钮点击事件接下来,我们需要将这些回调函数绑定到按钮的点击事件。为此,我们将在 在 编译和测试完成这些步骤后,我们将编译代码,确保没有错误。然后,我们将在 Unreal Editor 中测试菜单,以确保点击按钮时可以显示调试消息并触发对应的回调。 访问多人会话子系统在 在回调函数 小结在本讲中,我们为菜单小部件的按钮添加了回调函数,并将这些回调与按钮的点击事件绑定。我们还访问了自定义的多人会话子系统,并确保可以从菜单类调用其函数。期待在下一节课中继续实现子系统的功能! 17. 创建会话实现创建会话功能欢迎回来!在本讲中,我们将实现我们多人会话子系统中的 实现
|
3. 项目创建1. 项目创建创建全新的虚幻引擎项目你好,欢迎来到本讲。在这一讲中,我们将创建一个全新的虚幻引擎项目,并添加我们的多人会话插件,以便我们的项目能够开箱即用地与在线Steam会话一起使用。这将使我们更容易在真实的多人会话中通过互联网测试我们的项目。让我们开始吧。 创建新项目第一步是创建一个全新的项目。我们将打开Epic Games启动器并转到库。我们使用的是虚幻引擎5,在拍摄时,最新版本是Early Access 2。请使用可用的最新版本,因此我们可以简单地启动虚幻引擎5。 接下来,我们选择“游戏”,并且我们将从头开始创建一切,所以选择“空白”而不是使用提供的模板。现在,我们需要选择项目的目标位置。我将在这里选择,并点击“选择文件夹”。项目名称我将命名为“Blaster”。这将是一个C++项目,所以我选择C++并点击“创建”。我现在有了我的空白项目,虽然并不完全空白,我们有一个地面和其他一些物体,但总体来说,这个项目是非常基础的。 导航内容浏览器如果你是虚幻引擎5的新手,来自虚幻引擎4,可能会想知道内容浏览器在哪里。你可以通过点击内容抽屉来调出它,也可以使用 当我开发时,我喜欢打开输出日志,因此我将转到“窗口”并勾选“输出日志”,以便在这里也有该标签。如果你看不到“放置演员”面板,可以去“窗口”中勾选“放置演员”。这在创建关卡时可以用来引入常用的演员。 测试多人会话现在我们有了一个空白项目,我们希望能够通过Steam会话在真实的多人环境中测试此项目。如果你跳过了创建多人插件的第一部分,你可以下载插件,链接将在本视频的资源中提供,我们将在本视频中将该插件添加到项目中。 接下来的步骤是将插件添加到项目中。这里是我的项目文件夹,我已在此下载了插件,所以我将提取它。现在我得到了这个插件文件夹,打开后可以看到“Plugins”文件夹,其中包含“MultiplayerSessions”,这就是我们的插件。在其中有更多的文件夹,包括一个 将插件添加到项目我将这个“Plugins”文件夹拖到我的项目中。我不想将其放入其他文件夹中,不要拖到“Content”文件夹或其他地方,保持在项目级别就可以了。如果你将其带入其他已有插件文件夹的项目中,只需将“MultiplayerSessions”文件夹放入你的“Plugins”文件夹中。现在,我们的多人会话插件已经添加到项目中。 配置项目以支持多人游戏为了配置该项目以支持多人游戏,我们需要遵循几个步骤。我在一份PDF文档中概述了这些步骤,你可以在本讲的资源中找到,因此如果你打算在其他项目中再次执行此操作,可以参考该文档。 启用Steam在线子系统插件首先,我们需要启用“OnlineSubsystemSteam”插件。为此,我们可以转到“编辑”>“插件”。在插件编辑器中,我们可以搜索“OnlineSubsystemSteam”,勾选该插件的启用框。虚幻引擎会告诉我们需要重启以使更改生效,因此我们可以重启。现在选择“是”,它会问我是否希望为多人会话构建模块,我点击“是”。现在,虚幻引擎已重启,我们的“OnlineSubsystemSteam”插件已启用。 修改配置文件接下来,我们需要更改几个配置文件。返回到项目文件夹,进入“Config”文件夹。注意我们有几个 我们需要滚动到“Finished Settings”部分,看到这里是我们需要添加到 在 配置游戏的最大玩家数量另一个更改是在我们的 保存并关闭该文件。 构建解决方案我们已添加了一些配置设置。接下来,让我们回到Visual Studio项目,使用“构建解决方案”或 现在我们希望为我们的插件生成Visual Studio项目文件。进入“Plugins”>“MultiplayerSessions”,也删除此文件夹中的“Binaries”和“Intermediate”文件夹。然后返回,右键点击“Blaster”,生成Visual Studio项目文件。它会询问我虚幻引擎版本,我使用的是5,所以我点击“确定”。 生成完成后,我们可以双击我们的新项目,它会询问我是否要为Blaster重建模块,这是我的整体项目和“MultiplayerSessions”插件。点击“是”。虚幻引擎打开后,我将最小化它,打开Visual Studio项目解决方案。 生成Visual Studio项目文件后,我现在可以看到插件文件夹,并展开“MultiplayerSessions”的下拉菜单。里面有一个“Source”文件夹和“MultiplayerSessions”,再展开,我可以看到“Public”和“Private”文件夹,并在这里有一些C++文件。“MultiplayerSessionSubsystem”包含创建游戏会话的所有代码,而“Menu.cpp”和“Menu.h”是插件中包含的新用户小部件,它允许我们使用一个准备好的菜单小部件,因此我们不必自己创建一个。 在虚幻引擎中查看插件现在我们关闭插件文件夹,回到虚幻引擎。在虚幻引擎中我们看不见,但我们的插件已在项目中。为了显示它,我们可以点击设置按钮,然后点击“显示插件内容”,现在我们可以看到我们的“MultiplayerSessions”插件文件夹。我们有一个内容文件夹,在这个文件夹中有一个小部件蓝图。双击它,我们会看到它非常基础,包含一个托管和一个加入按钮,这些按钮上方还有一些文本。 你可以点击图表,看到这里完全是空的,所有逻辑都在C++中。如果点击类设置,你会看到父类是“Menu”,即我们刚添加的C++类。 添加小部件到视口我们的 它设置为默认值,但由于这是一个空白项目,我们没有名为“Lobby”的文件夹或地图。因此,我们将创建一个大厅关卡。我将编译,然后返回到当前打开的关卡,首先保存此关卡。创建一个名为“Maps”的文件夹,点击“Content”,选择“新建文件夹”,创建一个名为“Maps”的文件夹。 创建大厅关卡现在我将文件,保存当前关卡为,选择“Maps”,将其命名为“GameStartupMap”,并保存。这将是我们的游戏打开时所显示的地图。转到编辑,项目设置,确保这是正确的。点击“Maps and Modes”,对于编辑器启动地图,我们可以选择“GameStartupMap”,对于游戏默认地图,我们也选择“GameStartupMap”。 现在我关闭它,需要创建我们的大厅关卡。转到文件,新建关卡,选择默认,然后保存为“Lobby”。在文件中选择“保存当前关卡为”,在“Maps”文件夹中将其命名为“Lobby”,然后点击保存。 配置大厅路径现在返回到“GameStartupMap”,重新进入关卡蓝图。在菜单设置函数中,我们需要提供大厅的路径。所以我 将使用“Game/Maps/Lobby”。在你完成本课程第一部分创建这个插件时,会看到它是如何工作的。 现在,如果我们点击播放,可以看到这个菜单小部件已添加到视口,这也是在 测试Steam会话需要注意的是,我们无法在编辑器或“播放”模式中使用Steam会话。我们必须实际打包游戏才能创建和加入Steam会话。因此,这个“GameStartupMap”主要在我们打包和测试游戏时使用。频繁地打包游戏很重要,以确保它在打包时没有错误,并在实际互联网环境中测试游戏。 配置插件设置如果你使用的是虚幻引擎预览版2或虚幻引擎5.0的最新正式版,可能需要对插件进行一些更改。进入解决方案资源管理器,在Blaster下选择插件,打开“MultiplayerSessions”,在“Source”下选择“MultiplayerSessions”,然后打开“MultiplayerSessionSubsystem”,在 对于预览版2或虚幻引擎5.0的最新正式版,你需要添加一行代码,内容为 关闭Visual Studio,关闭编辑器,返回项目,进入插件的“MultiplayerSessions”,删除其中的“Binaries”和“Intermediate”文件夹。然后返回,右键点击新项目,生成Visual Studio项目文件。这将使你对插件代码所做的更改生效。 检查配置文件在打包游戏之前,转到“编辑”和“项目设置”,搜索“包含的地图”,在打包时查看要包括在构建中的地图列表。我们可以点击加号添加内容,输入“/Game/Maps/Lobby”,或者根据你放置大厅关卡的位置添加。我们还可以添加“Game/Maps/GameStartupMap”。这将确保在打包构建时,也将这些地图包括在内。确保将游戏中的所有地图添加到此列表中,并确保将它们的路径正确放置。 打包测试游戏在视频结束之前,我们将测试打包的游戏。因此,这里是我的项目,我将右键点击,创建一个名为“Build”的新文件夹。这个构建文件夹可用于打包游戏项目,现在我们就来打包。因此,我将转到平台,选择Windows并打包项目。询问我将项目发送到哪里,我将选择新创建的“Build”文件夹,并点击“选择文件夹”。我可以点击输出日志查看构建进度。 一旦打包完成,我可以返回构建文件夹,现在看到一个Windows文件夹,其中有我的打包游戏项目,即可执行文件 启动Steam客户端这个插件使用Steam,因此为了托管或加入会话,Steam必须在我们的机器上运行。测试此项目时,我需要两台不同的机器上登录两个不同的Steam帐户,以便找到彼此的游戏会话。我们需要确保连接到相同的Steam区域。可以在Steam的设置中点击下载,我的下载区域设置为“美国凤凰城”。 因此,如果我打包此项目并在另一台机器上使用,另一台机器需要有自己唯一的Steam帐户登录,并且下载区域应与我的机器设置相同,即“美国凤凰城”。点击确定并关闭。 课程总结我们现在在新项目中添加了我们的“MultiplayerSessionsSubsystem”插件,整个课程中我们将频繁使用它来测试我们的多人游戏,并确保它在通过Steam会话进行在线游戏时按预期工作。在本讲中,我们创建了游戏项目并添加了菜单系统插件。现在我们有了一个菜单小部件和我们的游戏启动地图,我们将在整个课程中使用这个插件,通过Steam网络连接正在玩我们游戏的机器。 做得好!我们现在准备开始真正制作这个游戏,以便进行网络测试。我们下次见! 2. 测试在线会话测试打包游戏欢迎回来。在本讲中,我们将测试打包的游戏,以确保我们的插件正常工作。然后,我们将连接到互联网中的其他机器。我们的游戏现在相当基础,因此我们将添加一个第三人称角色,以便在测试时可以看到我们正在玩的伙伴移动。 上传项目首先,我们需要上传我们的项目,以便可以在第二台机器上下载。我将使用Google Drive上传我们在上一个视频中打包的项目文件。这里是我的项目文件夹,我的“Build”文件夹中包含Windows文件夹,而里面有我们的游戏可执行文件。因此,我将压缩Windows文件夹,右键选择“发送到”压缩(zip)文件夹。压缩完成后,我将这个文件上传到Google Drive。 上传完成后,我将在另一台机器上下载这个压缩文件。 下载并启动游戏现在,我已经在另一台机器上下载了这个zip文件,并解压缩。在那台机器上,Steam正在运行,并且使用的是与我自己的Steam帐户完全不同的帐户。我在两台不同的机器上登录了两个Steam帐户,并在另一台机器上启动了游戏。 现在,我可以在这台机器上启动游戏,所以我将双击我的可执行文件。打开后,这里是启动关卡,当然我有托管或加入的选项。我将在另一台机器上托管,而在这台机器上加入。因此,我在另一台机器上启动这个游戏项目并点击托管,这导致我的另一台机器进入大厅关卡。 加入游戏会话现在那台机器正在托管游戏,我将点击加入,结果我也进入了大厅关卡。这时我看到的是由我的另一台机器控制的默认Pawn。当前,我们在这里并没有太多可以做的,实际上我们只是操控着默认Pawn,甚至还没有设置任何复制,因此目前这个项目并不是很有趣。但我们知道的是,我们通过Steam会话在互联网上成功连接了。 退出游戏我将使用Alt + Tab强制关闭游戏项目,因为我们尚未编程实现优雅退出游戏的方式,稍后我们会处理这个问题。但现在我们知道我们在打包的构建中通过互联网连接了。 添加第三人称角色现在我想回到我的游戏项目,而不是仅仅使用默认Pawn进行操控。我希望我们能够看到彼此的动作,因此我将快速设置这个。我们可以为项目添加一些内容。我会在内容浏览器中点击添加,然后在顶部选择添加功能或内容包,我可以添加第三人称模板材料。这样做的原因是,第三人称角色已经具有移动功能,并且该功能会自动复制。因此,如果我在另一台机器上加入游戏,我们都可以跑动并看到彼此的动作。 我将点击“添加到项目”,现在我们有了第三人称模板材料。点击关闭,选择我的“Maps”文件夹,进入大厅。在大厅中,我们看到这里有一个玩家起始点,这就是我们开始在此关卡中玩时会生成的位置。 重写游戏模式为了使用第三人称角色,我们需要重写这个关卡的游戏模式。由于我们在“第三人称BP”下添加了第三人称模板材料,所以有一个第三人称游戏模式。如果我双击这个,我可以看到第三人称游戏模式蓝图,它的默认Pawn类是第三人称角色。 如果我重写大厅关卡的游戏模式并选择第三人称游戏模式,可以看到默认Pawn类是第三人称角色。因此,如果我在“Play In Editor(PIE)”中点击播放,就会看到第三人称角色并且移动正常。 打包游戏现在我可以打包这个游戏。由于我们的大厅关卡使用了第三人称角色,因此在两个机器上都会生成第三人称角色,且移动会被复制。因此,我们应该能够在关卡中都跑动。 我将首先进入我的构建文件夹并删除之前的构建,然后再次打包游戏。转到平台,选择Windows并打包项目,选择我的构建文件夹并进行打包。打包完成后,我在这里得到了打包的项目,并将其发送到压缩文件夹。 上传新打包版本现在我已经压缩完成,可以将其上传到Google Drive。为了不混淆我的构建,我将删除之前的一个版本,右键选择删除,现在这个文件夹是空的,因此我可以将新打包并压缩的构建拖入并上传。 上传完成后,我将在另一台机器上下载这个文件以进行游戏测试。 测试多人会话我在另一台机器上下载了这个zip文件并解压缩,然后启动游戏。这次我想在这台机器上进行托管测试,所以我将启动可执行文件并点击托管。现在我在托管一个游戏,而在我的另一台机器上可以点击加入,这样我们就可以看到在另一台机器上加入的玩家。 我们可以看到,他们在跑动,我也在移动,我们能看到彼此的动作,确认我们在同一个游戏中。因此,我们通过互联网连接起来,这个插件使得建立多人会话变得非常简单。 小结在本讲中,我们测试了在线会话。我们成功地将两台机器连接并一起玩同一个游戏。我们添加了第三人称角色,以便能够看到彼此移动,证明我们在玩同一个游戏。这是一个很好的起点,我们将以此为基础,继续构建我们的游戏项目。做得好,我们下次见! 3. 资产添加游戏资产以丰富多人项目欢迎回来。在本讲中,我们将为我们的多人项目添加一些游戏资产,以使其更有趣。目前,我们正在使用默认的人偶,我们希望引入更吸引人的角色。因此,我们将添加一些环境、动画和可以在多人游戏中使用的武器。 上传项目首先,我们需要上传我们的项目,以便在第二台机器上下载。我将使用Google Drive。我这里有一个Google Drive,我将上传我们在之前的视频中打包的项目。这里是我的项目文件夹,我的构建文件夹包含Windows文件夹,里面有游戏的可执行文件。 我将压缩Windows文件夹,右键选择“发送到”压缩(zip)文件夹。压缩完成后,我将这个文件上传到Google Drive。 下载并启动游戏上传完成后,我将在另一台机器上下载这个zip文件,并解压缩。在那台机器上,Steam正在运行,并且使用的是与我自己的Steam帐户完全不同的帐户。我在两台不同的机器上登录了两个Steam帐户,并在另一台机器上启动了游戏。 现在,我可以在这台机器上启动游戏,所以我将双击我的可执行文件。打开后,这里是启动关卡,当然我有托管或加入的选项。我将在另一台机器上托管,而在这台机器上加入。因此,我在另一台机器上启动这个游戏项目并点击托管,这导致我的另一台机器进入大厅关卡。 加入游戏会话现在那台机器正在托管游戏,我将点击加入,结果我也进入了大厅关卡。这时我看到的是由我的另一台机器控制的默认Pawn。当前,我们在这里并没有太多可以做的,实际上我们只是操控着默认Pawn,甚至还没有设置任何复制,因此目前这个项目并不是很有趣。但我们知道的是,我们通过Steam会话在互联网上成功连接了。 退出游戏我将使用Alt + Tab强制关闭游戏项目,因为我们尚未编程实现优雅退出游戏的方式,稍后我们会处理这个问题。但现在我们知道我们在打包的构建中通过互联网连接了。 添加武器资产现在我想为我们的项目添加一些内容。我们将开始寻找一些武器。打开Epic Games启动器,我将搜索“Military Weapons Silver”。我找到了一个包含大量武器的免费资产包,名为“Military Weapons Silver”。这个包在免费收藏中,并且没有计划将其从免费收藏中移除。这是一个很棒的起始包,包含多种武器资产,还包括每种武器的粒子系统和声音。 导入武器资产现在,虽然这个资产包的支持引擎版本只列出了4.4到4.21,而我们使用的是虚幻引擎5,但我想展示如何将这些资产导入到虚幻引擎5项目中。这是一个非常好的技能,能为你在虚幻引擎5项目中添加资产提供更多选择。 我不能直接给你这些资产,因为我没有许可,因此我将向你展示如何将其添加到你的项目中。首先,我们需要安装虚幻引擎版本4.21。可以在我的库中找到。我已经安装了它。 如果你的硬盘空间有限,你可以选择市场上的其他武器资产或其他来源的资产,照样可以继续进行。但我将展示如何将仅与4.21兼容的资产导入到我们的虚幻引擎5项目中。 创建4.21项目我将创建一个4.21项目,启动虚幻引擎4.21,选择“新建项目”,保持为蓝图项目,选择“空白”,因为我们不需要任何起始内容。选择一个文件夹,我将其放在Blaster项目旁边,命名为“YUI_For_Assets”,并创建项目。 现在这是我的虚幻引擎4.21项目,它是完全空的。我将把“Military Weapons Silver”资产添加到这个项目中。在市场中找到“Military Weapons Silver”资产包,点击“添加到项目”,选择“YUI_For_Assets 4.21项目”,点击“添加到项目”。 完成后,我在项目中有了“Military Weapons Silver”,并且有一个展示关卡,展示所有资产,包括突击步枪、手枪、狙击步枪、火箭发射器、霰弹枪和榴弹发射器。我们可以在项目中使用这些武器。 迁移资产到虚幻引擎5项目我希望将这些资产迁移到我的虚幻引擎5项目中。我可以通过右键点击“Military Weapons Silver”下的内容文件夹,选择“迁移”来轻松做到这一点。它会显示所有将要迁移的资产,我点击“确定”,然后回到Blaster项目,选择内容文件夹。 迁移资产时,必须迁移到内容文件夹。选择该文件夹,我看到内容迁移成功完成。 添加环境和动画现在我已经拥有了这些资产,我准备添加一些环境。我要关闭虚幻引擎4.21项目,返回市场,搜索“Unreal Learning Kit Games”。这是Epic Games发布的一个资产包,包含一个角色和一些环境。 我选择这个资产包的原因是,它有大量资产,并且风格一致。因此,这些资产将会在我们组合成一个游戏时显得非常出色。 创建4.26项目但这个资产包只与4.26兼容。因此,我需要在库中确保我已安装4.26。创建项目时,我选择4.26,并将其放在与Blaster项目相邻的文件夹中,命名为“UnrealLearningKitGames”,点击“创建”。 现在我创建了这个项目,将关闭虚幻引擎4.21项目,打开“Unreal Learning Kit Games”项目。我们有这个学习套件项目,里面有很多可以使用的资产,同时也是4.26项目。因此,我们可以从市场中为该项目添加更多资产,然后一旦准备好,我们可以将所有内容迁移到虚幻引擎5项目中。 获取动画资产我还想获取更多资产,打开市场,寻找“Animation Starter Pack”。这里我们看到由Epic Games提供的资产包,免费可用,因此我们可以将其添加到项目中。 确保选择正确的资产,将其添加到学习套件游戏项目中。 编译和准备工作现在它出现在我的学习套件游戏项目中,我们有动画启动包,这些动画已绑定到虚幻引擎4的人偶。在这里,我们可以使用它来重新定位这些动画到我们想使用的角色上。 接下来,我们将在准备好时进行这项工作。虽然动画启动包提供了很多很好的射击动画,但它并不完全具备我们所需的所有动画。例如,它没有站立和蹲下的转身动画。 结论在本讲中,我们为我们的项目添加了一些资产。我们将继续寻找一些免费的动画,以确保项目更完整。期待在下节课见到你! 4. 调整动画添加游戏资产以丰富多人项目欢迎回来。在本讲中,我们将为我们的多人项目添加一些游戏资产,以使其更有趣。我们将引入一些环境、动画和武器,使游戏体验更加生动。 下载角色模型首先,我们需要选择一个角色使用。我将选择一个与Epic Games的人偶相似的角色。我们注意到它是T姿势而不是A姿势,这是Epic骨架的姿势,但这没关系。一旦选择了要使用的角色,我们可以点击下载。确保下载为FBX格式,可以保留为T姿势。 导入角色到项目下载完成后,我将在我的Unreal Learning Kit项目中添加这个角色。首先,在内容浏览器中创建一个名为“Maximo”的新文件夹,然后在其中再创建一个名为“Character”的文件夹。在这里,我可以导入刚才下载的角色,将其重命名为“Maximo Character”。 接下来,点击“添加导入”,选择Maximo Character的FBX文件。导入时,选择导入骨骼网格,而不选择骨骼,因为FBX文件中已有其骨骼。点击导入所有,并确认可能出现的无平滑组信息错误。这是常见的,只需关闭该提示。 组织文件夹现在,我有了Maximo角色和其骨骼。如果查看骨骼,会发现它与Epic Games的骨骼相似,但层次结构和名称略有不同。在“Maximo”文件夹中右键点击,创建一个名为“Animations”的新文件夹,以便下载Maximo的动画。 下载动画接下来,我将查找一些Maximo动画。很重要的是,我使用下载的角色,因为所有动画都将与这个角色绑定。我们需要一些转身动画。我将搜索“Turn Right”。选择适合的动画后,确保下载时选择带皮肤的ABC格式,以确保它绑定到正在使用的角色。 同样的步骤,我会下载左转、蹲下转身和其他所需的动画。我们还需要跳跃动画,因此会搜索“Jump”,下载跳跃上升、跳跃下降和跳跃循环动画。下载完成后,我们将导入这些动画到我们的项目中。 导入动画到项目在“Animations”文件夹中,点击导入,将所有动画导入到项目中。选择Maximo Character Skeleton作为骨骼,不需要导入网格。导入后,我发现每个动画都被导入了两次,带“Take 1”的版本可以删除。 重新绑定动画我将保留导入的动画,并准备将它们重新绑定到Epic Games的人偶骨骼。打开UE4人偶的骨骼,并在重定向管理器中选择人形骨架。对于Maximo骨骼,我们需要将其设置为人形骨架,并映射骨骼。详细步骤已在附带的PDF中列出。 完成后,我将保存并准备重定向Maximo的动画到Epic骨骼。为了匹配姿势,我会将人偶的手臂抬起,确保它们的姿势一致。调整完成后,我可以重定向动画,确保所有动画都适配到Epic骨骼。 清理和组织文件夹导入和重定向后,我将在项目中创建一个新的“Assets”文件夹,并将所有动画移动到此文件夹中。检查每个动画,确保它们看起来不错,然后清理不需要的文件夹。 小结现在我们已经添加了一些资产,并成功将动画重新绑定到Epic骨骼。随着这些新资产的引入,我们可以开始开发游戏项目。干得好!我们下次见! 5. 爆破角色创建角色类欢迎回来。我们现在准备开始创建我们的角色类。在本视频中,我们将确保为C++类设置文件夹结构,以保持项目的组织性。让我们开始吧。 设置项目结构这是我们的项目。目前,C++类文件夹下有Blaster游戏模式基类。我们将创建一个新的角色类,可以通过右键点击C++类中的Blaster,选择“新建C++类”来实现。我们将基于“Character”类进行创建,因此选择“Character”并点击“下一步”。 命名角色类对于这个项目,我将角色命名为“BlasterCharacter”。因为我们会为这个项目创建许多类,所以我希望将它们组织到自己的文件夹中。我将Blaster类放在名为“Character”的文件夹中。你可以选择是否使用公共和私有的文件夹结构,我个人不使用私有文件夹,因此我将保持现状,只添加BlasterCharacter到它自己的角色文件夹中。点击“创建类”。 处理编译错误由于我们选择将角色类放在自己的角色文件夹中,我们会收到一条消息,提示我们需要重新编译Blaster模块,这是因为出现了自动编译错误。点击“否”,Visual Studio会询问我是否想重新加载项目,点击“重新加载所有”。 现在在项目中,我可以看到Blaster的源文件夹下有一个角色文件夹,里面有BlasterCharacter.h和BlasterCharacter.cpp。在BlasterCharacter.cpp中,我们有一个包含错误,因为它试图从角色文件夹中包含BlasterCharacter.h,但我们的cpp文件已经在角色文件夹中。因此,我们只需在包含语句中去掉“Character”,就能消除错误。现在我们应该能够成功编译。 创建角色蓝图现在我们成功编译后,可以返回编辑器,并基于新的BlasterCharacter类创建角色蓝图。右键点击内容,创建一个新文件夹,用于我们为这个项目创建的所有蓝图。我将这个文件夹命名为“Blueprints”,然后在蓝图文件夹中创建一个名为“Character”的文件夹。在这里,我将放置角色蓝图。 创建新蓝图时,我将选择基于BlasterCharacter的C++类,命名为“BP_BlasterCharacter”,这样可以明确区分蓝图类和C++类。点击“创建蓝图类”。 配置角色蓝图现在这是我们的角色蓝图。首先,我可以选择网格,因此我将选择“Mesh”。在骨骼网格中,我将选择来自学习套件游戏的角色。找到相应的角色后,我发现它面朝Y方向,而我希望它面朝X方向。因此,我将其旋转90度。现在它的脚位于胶囊的中心,而我的胶囊半高度为88,所以我可以将网格向下移动88个单位。 设置其Z轴位置为-88,使角色正确放置在地面上。编译并保存。现在我们有了角色类和基于该类的蓝图,并且将该类放在角色文件夹中。我们的C++解决方案已组织好。 下一步接下来的视频中,我们将添加一个相机和弹簧臂,并添加一些输入以编程实现移动功能。期待在下节课见到你! 6. 相机和弹簧臂添加相机组件和弹簧臂欢迎回来。现在我们已经有了角色类和角色蓝图,是时候开始添加组件,包括相机组件和弹簧臂组件。让我们开始吧。 设置角色蓝图如果我们进入大厅地图并拖入BP_BlasterCharacter,首先我们没有设置游戏模式,因此不会自动占有角色。但是,如果我们选中角色并在详细面板中搜索“Auto Possessed Player”,将其设置为Player Zero,那么当我们点击播放时,就会自动占有这个角色。但目前我们会发现相机几乎位于角色内部,所以我们需要添加相机和弹簧臂来控制视角。 声明变量现在我们回到C++代码。在BlasterCharacter.h和BlasterCharacter.cpp中,我们将声明几个新变量。在公共部分的构造函数上方,我们有一个第二个公共部分,包含TTIC和设置玩家输入组件的内容。我想将这些公共函数移动到顶部的公共部分,并且我认为这些注释现在可以去掉,因为我们应该都知道这些函数的作用。 我将保留下面的公共部分,以便为各种成员变量保留简单的getter和setter。现在,在私有部分,我想添加弹簧臂和相机。我们将提前声明弹簧臂组件,命名为“CameraBoom”。这需要一个新的属性宏,我将设置为“VisibleAnywhere”,并将其放在“Camera”类别中。 当然,我们还需要实际的相机组件,也将提前声明,命名为“FollowCamera”。同样,将其设置为“VisibleAnywhere”,并放入“Camera”类别中。现在我们已经声明了变量,但我们还需要在构造函数中构建它们。 构造函数实现在BlasterCharacter的构造函数中,我将构建相机弹簧臂。使用 通常,我们会将相机弹簧臂附加到根组件,但我想将其附加到网格组件,因为稍后我们会使用蹲下功能来改变胶囊的大小。如果我们将弹簧臂附加到胶囊上,当胶囊大小改变时,弹簧臂的位置也会移动。因此,我将使用 接下来,我将设置相机弹簧臂的目标臂长为600,虽然我们可以稍后调整。相机弹簧臂还需要使用控制旋转,因此我将这个选项设置为true,以便在添加鼠标输入时能够跟随控制器旋转。 创建相机组件现在我们创建相机组件,使用 跟随相机不需要使用控制旋转,因为它是附加在弹簧臂上的,所以我将其设置为false。现在编译代码,我们应该能够成功。 调整组件位置在蓝图中,我们可以看到相机弹簧臂附加到了网格的底部,并且目标臂长是600单位。由于相机可能与地面发生碰撞,我们需要将弹簧臂的位置上移,确保它不是从地面开始附加。我将相机弹簧臂的Z轴位置设置为88单位,这样它将处于角色的中间。 编译并点击播放,现在我可以看到角色与相机之间的正确距离。 准备编程移动功能当然,目前我们还不能移动,这因为我们尚未编程实现这一功能。这将是我们的下一个步骤。在本讲中,我们添加了相机组件和弹簧臂,并设置了它们的附加关系。我们将弹簧臂附加到网格,而不是根组件(胶囊),这样在蹲下和改变胶囊大小时,不会影响弹簧臂的高度。 我们现在准备编程移动功能,下一次我们将开始这部分工作。期待下次见面! 7. 角色移动配置角色输入和移动功能欢迎回来。现在我们有了角色、弹簧臂和相机组件,是时候为项目配置输入并编程实现角色的移动功能了。让我们开始吧。 设置输入映射我们需要为项目设置一些输入。为此,转到“编辑”>“项目设置”。在这里,我们可以选择“输入”,然后展开我们的“Action Mappings”和“Axis Mappings”。在这里我看到一些输入映射,这是在从学习套件游戏迁移资产时创建的。我将删除项目设置中的所有轴映射,从头开始设置。 创建动作映射首先,我们想要能够跳跃。因此,我将创建一个跳跃的动作映射,并将其映射到空格键。我可以点击图标,然后按空格键将其链接到跳跃动作映射。 创建轴映射接下来,我们将添加一些轴映射。我要添加一个名为“Move Forward”的映射,将其映射到W键,同时还想将其映射到S键,缩放设置为-1,以便向后移动。接下来,我们还需要一个“Move Right”映射,将其映射到D键,同时将A键映射到-1,这样我们就可以左右移动。 此外,我们还想使用鼠标来旋转相机。因此,我将添加两个轴映射,一个叫“Turn”,另一个叫“Look Up”,将“Turn”映射到鼠标X轴,将“Look Up”映射到鼠标Y轴。对于“Look Up”,我会将缩放设置为-1,这样当我向前移动鼠标时,视角会向上看,而不是向下。 创建角色移动函数现在,我们已经设置了这些动作和轴映射,我们可以在角色类中创建一些函数来绑定这些映射。在BlasterCharacter.h中,我们将创建处理移动的函数。我将这些函数放在protected部分,以便以后可能会从子类中访问。 我将创建一个名为 实现移动逻辑现在,我们有了这些函数定义。在构造函数中,我将调用 我们将获取控制器的前方方向,而不是使用角色的前向向量。我们将使用控制器的旋转值来确定移动方向。通过创建FRotator和FVector,我们可以获取相应的前方方向向量。最后,我们将调用 对于 绑定输入现在我们需要将这些移动函数绑定到输入映射中。在 此外,我们也会处理跳跃的动作映射,通过 编译并测试现在编译代码,并回到编辑器中。确保在详细面板中设置 下一步在接下来的步骤中,我们将为角色添加动画蓝图,并继续设置角色的基本功能。很高兴我们已经完成了角色的输入和移动配置,期待在下节课中深入了解多人编程的概念。下次见! 8. 动画蓝图配置角色动画和运动功能欢迎回来。现在我们有了角色的运动功能,但角色尚未动画化,因此我们需要设置动画实例,这是我们的动画蓝图所基于的C++类。我们需要这个C++类,以便能够从C++访问并设置其属性。 创建动画实例在我们的项目中,角色的动作很僵硬,因此我们需要设置动画实例。进入C++类,在角色文件夹中右键单击,选择“新建C++类”,选择所有类并搜索“AnimInstance”。选择后,点击“下一步”,并将其命名为“BlasterAnimInstance”。这将放置在角色文件夹中。 我们会收到与创建角色类时相同的警告消息,再次是因为我们将其放在角色文件夹中,因此点击“否”。在Visual Studio中,我找到BlasterAnimInstance和BlasterAnimInstance.cpp。删除路径中的“Character”文件夹,应该能够成功编译。 设置基本变量我们的动画实例将非常简单,首先设置几个关键变量来驱动基本的未装备动画。我将添加一个公共部分,并重写几个继承的函数。第一个是 我们需要确保在调用这些函数时调用超类的版本。接下来,在私有部分添加一些变量。第一个变量将存储Blaster角色的指针,并将其声明为 设置运动状态接下来,我还会添加几个变量来跟踪角色的运动状态,包括速度、是否在空中和是否正在加速。我们将在 在 创建动画蓝图现在,我们可以基于这个动画实例创建动画蓝图。编译代码后,进入蓝图文件夹的角色文件夹,创建一个新的动画蓝图,选择BlasterAnimInstance作为父类,并设置Skeleton为Epic Character Skeleton。命名为“BlasterAnimBP”。 在动画蓝图的类设置中,确保将父类设置为BlasterAnimInstance。这样,我们可以在蓝图中访问在C++中声明的变量,例如速度、是否在空中和加速状态。 创建状态机我们将创建一个状态机来处理未装备状态。添加新的状态机,并命名为“Unequipped”。在状态机中,我们将创建几个状态,包括“Idle/Walk/Run”和“Jump”。在这些状态之间设置转换规则,根据角色是否在空中来决定状态切换。 我们使用的跳跃动画来自学习套件游戏包,命名为“Jump Start”、“Falling”和“Jump Stop”。在“Jump Stop”中,我们将使用时间剩余节点,以确保在动画播放到一定程度后再返回到“Idle/Walk/Run”。 测试动画在设置好状态机后,回到BP_BlasterCharacter蓝图,选择网格,使用新的动画蓝图。编译并测试游戏,查看角色是否能够正确运动。注意,角色仍然会随控制器旋转,但我们可以通过设置C++中的一些变量来调整这一点。 设置 结论在本讲中,我们设置了动画蓝图,并使用BlasterAnimInstance C++类作为父类,这样我们可以从C++中设置变量并在蓝图中访问它们来驱动动画。角色现在能够运行,跳跃,接下来我们将添加更复杂的功能。做得好!期待在下节课见到你! 9. 无缝旅行和大厅配置无缝旅行欢迎回来。现在我们已经为项目设置了角色、输入和动画,是时候讨论如何在多人游戏中实现无缝旅行。无缝旅行是虚幻引擎中首选的旅行方式,它可以提供更流畅的体验,因为客户端不需要从服务器断开连接。它还帮助避免重新连接时可能出现的问题,例如无法找到服务器或服务器突然满员导致玩家无法重新加入。 启用无缝旅行我们可以在游戏模式中启用无缝旅行。游戏模式有一个布尔变量叫做 旅行方式我们讨论的旅行方式之一是调用 创建大厅游戏模式我们希望在创建的大厅游戏模式中使用 现在我们需要为大厅创建一个新的游戏模式类。进入C++类,右键点击Blaster,选择“新建C++类”,搜索“GameMode”。我们将使用 创建游戏模式文件夹我希望将多个游戏模式保持在自己的文件夹中,因此在Blaster中创建一个名为“GameMode”的新文件夹,并将这个游戏模式命名为“LobbyGameMode”。点击“创建类”。我们将收到与之前相同的消息,点击“否”。现在我们已经有了大厅游戏模式。 计数连接的玩家大厅游戏模式需要实现的功能是查看有多少玩家连接到了大厅地图。一旦达到一定数量,我们就可以旅行到实际的游戏地图。我们将使用 在 访问游戏状态游戏模式中存在一个变量叫做 使用 判断玩家数量我们需要检查 创建Blaster地图在Maps文件夹中,创建一个新的关卡并命名为“BlasterMap”。接着,我们将使用这个关卡作为目标地图,并在大厅游戏模式中调用 设置过渡地图我们还需要创建一个过渡地图。创建一个新的空关卡,命名为“TransitionMap”,并保存到Maps文件夹。接下来,确保在项目设置中将这个过渡地图设置为过渡关卡。 测试无缝旅行现在一切都设置好了。当有足够的玩家加入游戏时,服务器将调用 挑战任务现在我们有多个地图,但它们看起来都很简单。我想给你一个挑战,去美化这些地图。首先,给游戏启动地图添加一些资产,制作一个视觉上吸引人的背景。然后,给大厅地图增加一些细节,使其看起来更有趣。最后,制作BlasterMap,这将是玩家实际进行游戏的地方。加入障碍物、道具、武器等元素。 完成这些后,我们将一起测试游戏。希望你在创建这些关卡时玩得开心!我将在下节课中与大家见面。 10. 网络角色理解网络角色欢迎回来。在本讲中,我们将探讨网络角色的概念,以及如何在多人游戏中区分角色的不同实例。每个角色在网络中的表示取决于它在服务器和客户端之间的角色。 网络角色的分类当你在服务器上运行游戏时,服务器会为每个连接的玩家创建角色的一个实例。如果有多个玩家连接,那么每个客户端机器上也会有该角色的一个版本。例如,在三人游戏中,每台机器上都会有角色的三个副本,因此在代码中区分哪个角色至关重要。 为了处理这一点,虚幻引擎有一个称为角色的概念,存在一个枚举 在此角色中,还有一种称为模拟代理(Simulated Proxy)的角色,这些是存在于不控制该Pawn的机器上的角色版本。当你在自己的机器上控制角色时,该角色的角色为自主代理(Autonomous Proxy)。需要注意的是,在你的机器上和每台其他机器上都存在角色的多个版本。 创建HUD小部件现在我们回到编辑器,创建一个新的C++类,用于显示在角色头顶上的小部件。进入C++类的Blaster文件夹,右键点击,选择“新建C++类”,选择“UserWidget”作为基类,这样我们就可以使用C++变量驱动用户小部件。将其放入名为“HUD”的文件夹中,命名为“OverheadWidget”。 我们会收到熟悉的消息,点击“否”后,我们就有了新的用户小部件。在C++类中,我们将删除包含中的HUD部分,以消除编译错误。接下来,我们将这个新用户小部件用作显示角色头顶上角色状态的蓝图的父类。 设置小部件这个小部件将包含一个文本块。我们在公共部分声明一个新的文本块指针,命名为“DisplayText”,用于设置显示的文本。接下来,我们将在蓝图文件夹中创建一个新的HUD文件夹,并在其中右键选择“用户界面”>“小部件蓝图”,命名为“WBP_OverheadWidget”。 在小部件蓝图中,选择文本块,并确保其变量名称与C++中的变量名称相同,这样C++代码才能正确地控制其显示文本。设置完文本块的字体和对齐方式后,我们可以开始为这个小部件添加功能。 处理网络角色我们将在C++类中重写一个虚拟函数,称为 此外,我们将创建一个显示玩家网络角色的函数,名为 将小部件添加到角色接下来,回到BlasterCharacter类,在私有部分添加一个新的WidgetComponent用于存储OverheadWidget。我们将在构造函数中初始化它,并将其附加到根组件。通过将这个小部件设置为可编辑,我们可以在蓝图中进行调整。 测试网络角色编译并运行游戏,检查小部件是否在角色头顶上正确显示网络角色信息。在编辑器中,可以通过调整小部件的位置来确保它与角色头部对齐。 小结在本讲中,我们讨论了网络角色的概念,包括权威、自治代理和模拟代理。我们还创建了一个HUD小部件,能够显示角色的网络状态信息。接下来,我们将使用这些知识进一步开发游戏的多人功能。期待在下节课见到你! |
4. 武器1. 武器类创建武器类欢迎回来。在本讲中,我们将创建武器类,并添加所有武器应具备的基本组件,以及一个武器状态的枚举,以便根据状态正确处理武器。让我们开始吧。 创建武器类我们需要一个武器类,所以我将右键单击并添加一个新的C++类。我们的武器类可以是一个Actor,因此选择“Actor”,然后点击“下一步”。我希望将武器类放在名为“Weapon”的文件夹中,这样将来派生出更多类时,可以将所有武器类放在这个文件夹里。将类命名为“Weapon”,然后点击“创建类”。 在弹出消息中点击“否”。现在在Visual Studio中,我可以看到我的武器类。我暂时不需要其余的标签,因此右键点击 设置武器组件进入 我将将 添加骨骼网格组件我们将添加一个新的骨骼网格组件,命名为 我们将为武器添加更多组件,但目前这些组件已足够。接下来,我们将实现这些组件,并在 构造函数实现在构造函数中,我将首先将 我们将使用 设置碰撞响应设置完碰撞响应后,我希望忽略角色的碰撞,以便角色可以穿过武器而不与其发生碰撞。起初,我希望我的武器网格的碰撞被禁用,这样角色就可以走近并拾取它。 在构造函数中将 添加武器状态枚举在结束之前,我想为武器的状态添加一个枚举。在 创建蓝图在完成武器类的设置后,我们可以创建一个蓝图,基于新创建的武器类。进入蓝图文件夹,创建一个名为“Weapon”的新文件夹,然后右键创建蓝图类,基于我们的武器C++类,命名为“BP_Weapon”。 在蓝图中,我们可以设置武器的网格,选择相应的资产,比如突击步枪,并调整其位置和碰撞体积。完成后,编译并保存,然后将武器拖入关卡中。 小结在本讲中,我们创建了武器类并添加了一些组件,以及一个武器状态的枚举,以便根据当前状态处理武器。下一步,我们将显示一个拾取小部件,提示玩家可以拾取武器。期待在下节课中见到你! 2. 拾取小部件创建武器拾取小部件欢迎回来。在本讲中,我们将为我们的武器类制作一个拾取小部件。这将使我们能够知道何时可以拾取武器,然后根据武器状态决定何时设置此拾取小部件的可见性。 设置拾取小部件首先,我将进入我的HUD文件夹,右键点击,选择“用户界面”,然后选择“小部件蓝图”。我将这个小部件命名为 编译并保存后,我接下来要在武器类中添加一个小部件组件。回到 构造小部件组件接下来,我们需要在 编译后,回到编辑器,打开 显示和隐藏小部件现在我们需要决定何时显示和隐藏这个小部件。我希望当角色与区域球体重叠时,显示这个小部件。同时,我不再需要在角色上显示“Overhead Widget”。不过,我会保留“Overhead Widget”,因为我们稍后可能会用它来显示角色的名称。 接下来,我们需要为区域球体设置重叠事件,以便能够显示和隐藏小部件。我将在protected部分添加一个虚拟函数,命名为 绑定重叠事件我们将绑定此重叠函数到区域球体的“OnComponentBeginOverlap”事件。在 在 初始化小部件在 调试可见性在测试中,我们发现服务器上可见,但客户端上不可见。这是因为我们仅在服务器上处理重叠事件。我们需要确保在客户端也能看到这个小部件。为此,我们需要引入复制(Replication),以便将可见性状态从服务器同步到客户端。 小结在本讲中,我们添加了一个拾取小部件到武器类,并创建了一个重叠函数,将其绑定到区域球体的重叠事件。现在服务器控制着小部件的可见性,下一步将是实现变量的复制,从而让客户端知道何时需要显示拾取小部件。干得好!期待下次见到你! 3. 变量复制理解变量复制和网络交互欢迎回来。在本讲中,我们将深入探讨变量的复制,以及如何通过网络处理武器的交互。我们将实现复制功能,以便正确处理玩家与武器之间的交互。 创建复制函数首先,我们需要在BlasterCharacter类中设置复制。在函数定义中创建 注册重叠武器变量在这个函数内部,我们需要注册我们的 这样, 创建Setter函数为了在武器类中设置重叠武器,我们需要在BlasterCharacter中添加一个公共的Setter函数。这个函数命名为 只要 处理重叠事件在武器类的 在BlasterCharacter类中,我们需要决定何时显示这个小部件。为此,我们将在武器类中创建一个显示小部件的函数,命名为 调整Tick函数在BlasterCharacter的Tick函数中,我们将检查 编译与测试编译代码,并在编辑器中测试这个实现。通过控制客户端角色接近武器,验证小部件的显示与隐藏是否正常工作。注意,由于复制是从服务器到客户端的,因此我们需要确保小部件仅在拥有角色的客户端上显示。 引入Rep Notify为了优化我们的实现,我们将使用Rep Notify机制。当 在BlasterCharacter中,我们将设置 完成复制设置完成上述设置后,我们可以对代码进行整理,确保逻辑清晰。在测试中,观察到在服务器上显示的Pickup Widget只在客户端上可见。这样,只有拥有角色的客户端会看到武器的拾取提示。 小结在本讲中,我们学习了变量复制的机制,如何通过Rep Notify函数来管理变量的复制,以及如何优化小部件的显示和隐藏。我们还实现了一个系统,使得在角色与武器交互时,只有特定的客户端会看到相应的小部件提示。期待在下一节课中继续深入! 4. 装备武器5. 远程程序调用6. 装备动画姿势7. 蹲伏8. 瞄准9. 运行混合空间10. 倾斜和侧移11. 空闲和跳跃12. 蹲行13. 瞄准行走14. 瞄准偏移15. 应用瞄准偏移16. 多人游戏中的俯仰17. 使用我们的瞄准偏移18. FABRIK IK19. 转向20. 旋转根骨21. 网络更新频率22. 未装备时蹲伏23. 旋转跑步动画24. 脚步和跳跃声音 |
5. 发射武器1. 投射武器类2. 发射蒙太奇3. 发射武器效果4. 多人游戏中的发射效果5. 命中目标6. 生成投射物7. 投射物移动组件8. 投射物曳光9. 复制命中目标10. 投射物命中事件11. 子弹壳12. 壳体物理 |
6. 武器瞄准机制1. 爆破HUD和玩家控制器2. 绘制十字准星3. 准星扩散4. 纠正武器旋转5. 瞄准时放大6. 瞄准时缩小准星7. 改变准星颜色8. 延长痕迹起点9. 命中角色10. 为代理平滑旋转11. 自动射击12. 测试游戏 |
7. 健康和玩家统计1. 游戏框架2. 健康3. 在HUD中更新健康4. 伤害5. 爆破游戏模式6. 消灭动画7. 重生8. 溶解材料9. 溶解角色10. 使用曲线溶解11. 消灭时禁用移动12. 消灭机器人13. 占有14. 爆破玩家状态15. 失败 |
8. 弹药1. 武器弹药2. 能否开火3. 携带弹药4. 显示携带弹药5. 重新装填6. 重新装填战斗状态7. 允许开火8. 更新弹药9. 重新装填效果10. 自动重新装填 |
9. 比赛状态1. 游戏计时器2. 同步客户端和服务器时间3. 比赛状态4. 设置比赛状态5. 热身计时器6. 更新热身时间7. 自定义比赛状态8. 冷却公告9. 重启游戏10. 爆破游戏状态 |
10. 不同的武器类型1. 火箭弹2. 火箭轨迹3. 生成火箭轨迹4. 火箭移动组件5. 扫描射击武器6. 光束粒子7. 冲锋枪8. 带子物理9. 霰弹枪10. 武器散射11. 狙击步枪12. 狙击瞄准镜13. 榴弹发射器14. 投射榴弹15. 重新装填动画16. 霰弹枪重新装填17. 武器轮廓效果18. 投掷榴弹蒙太奇19. 投掷榴弹时的武器附着20. 榴弹资产21. 显示附着的榴弹22. 生成榴弹23. 多人游戏中的榴弹24. HUD中的榴弹 |
11. 拾取1. 拾取类2. 弹药拾取3. 增益组件4. 健康拾取5. 治疗角色6. 速度增益7. 跳跃增益8. 护盾条9. 更新护盾10. 护盾增益11. 拾取生成点12. 添加生成点到等级13. 生成默认武器14. 副武器15. 交换武器16. 丢弃副武器 |
12. 延迟补偿1. 延迟补偿概念2. 高ping警告3. 本地射击效果4. 本地显示小部件5. 复制散射6. 复制霰弹枪散射7. 客户端预测8. 霰弹枪火力远程程序调用9. 客户端预测弹药10. 客户端预测瞄准11. 客户端预测重新装填12. 服务器端回放13. 延迟补偿组件14. 命中箱15. 帧数据包16. 保存帧数据包17. 帧历史18. 倒带时间19. 帧间插值20. 确认命中21. 得分请求22. 霰弹枪的服务器端回放23. 确认霰弹枪命中24. 霰弹枪得分请求25. 请求霰弹枪命中26. 预测投射路径27. 属性编辑后变化28. 本地生成投射物29. 命中箱碰撞类型30. 投射物的服务器端回放31. 投射物得分请求32. 限制服务器端回放33. 更换武器动画34. 结束延迟补偿35. 作弊 |
使用C++在虚幻引擎5中创建多人射击游戏 Unreal Engine 5 C++ Multiplayer Shooter
1. 引言
2. 创建多人插件
3. 项目创建
4. 武器
5. 发射武器
6. 武器瞄准机制
7. 健康和玩家统计
游戏框架
健康
在HUD中更新健康
伤害
爆破游戏模式
消灭动画
重生
溶解材料
溶解角色
使用曲线溶解
消灭时禁用移动
消灭机器人
占有
爆破玩家状态
失败
8. 弹药
9. 比赛状态
10. 不同的武器类型
11. 拾取
拾取类
弹药拾取
增益组件
健康拾取
治疗角色
速度增益
跳跃增益
护盾条
更新护盾
护盾增益
拾取生成点
添加生成点到等级
生成默认武器
副武器
交换武器
丢弃副武器
12. 延迟补偿
更多多人游戏功能
返回主菜单
离开游戏
玩家簿记
获得领先
生成皇冠
消灭公告
动态消灭公告
头部射击
投射物头部射击
服务器端回放的头部射击
团队
团队
团队游戏模式
团队颜色
设置团队颜色
防止友伤
团队得分
更新团队得分
团队冷却公告
夺旗
夺旗
持有旗帜
拾取旗帜
给旗帜持有者增加负担
丢弃旗帜
团队旗帜
团队玩家开始
夺旗游戏模式
选择比赛类型
访问我们的子系统
团队和夺旗地图
恭喜
恭喜
附加讲座
Introduction
Introduction
About this Course
Creating a Multiplayer Plugin
Multiplayer Concepts
Testing Multiplayer
LAN Connection
Online Subsystem
Online Sessions
Configure For Steam
Accessing the Online Subsystem
Creating a Session
Setup for Joining Game Sessions
Steam Regions
Joining the Session
Creating a Plugin
Creating our Own Subsystem
Session Interface Delegates
The Menu Class
Accessing our Subsystem
Create Session
Callbacks to our Subsystem Functions
More Subsystem Delegates
Join Sessions from the Menu
Tracking Incoming Players
Path to Lobby
Polishing the Menu Subsystem
Project Creation
Project Creation
Testing an Online Session
Assets
Retargeting Animations
Blaster Character
Camera and Spring Arm
Character Movement
Animation Blueprint
Seamless Travel and Lobby
Network Role
The Weapon
Weapon Class
Pickup Widget
Variable Replication
Equipping Weapons
Remote Procedure Calls
Equipped Animation Pose
Crouching
Aiming
Running Blendspace
Leaning and Strafing
Idle and Jumps
Crouch Walking
Aim Walking
Aim Offsets
Applying Aim Offsets
Pitch in Multiplayer
Using our Aim Offsets
FABRIK IK
Turning in Place
Rotate Root Bone
Net Update Frequency
Crouch Unequipped
Rotating Running Animations
Footstep and Jump Sounds
Firing Weapons
Projectile Weapon Class
Fire Montage
Fire Weapon Effects
Fire Effects in Multiplayer
The Hit Target
Spawning the Projectile
Projectile Movement Component
Projectile Tracer
Replicating the Hit Target
Projectile Hit Events
Bullet Shells
Shell Physics
Weapon Aim Mechanics
Blaster HUD and Player Controller
Drawing the Crosshairs
Crosshair Spread
Correcting the Weapon Rotation
Zoom While Aiming
Shrink Crosshairs when Aiming
Change Crosshairs Color
Extending the Trace Start
Hitting the Character
Smooth Rotation for Proxies
Automatic Fire
Testing the Game
Health and Player Stats
Game Framework
Health
Update Health in the HUD
Damage
Blaster Game Mode
Elim Animation
Respawning
Dissolving the Character
Dissolve Material
Dissolving with Curves
Disable Movement when Elimmed
Elim Bot
On Possess
Blaster Player State
Defeats
Ammo
Weapon Ammo
Can Fire
Carried Ammo
Displaying Carried Ammo
Reloading
Reloading Combat State
Allowing Weapon Fire
Updating Ammo
Reload Effects
Auto Reload
Match States
Game Timer
Syncing Client and Server Time
Match State
On Match State Set
Warmup Timer
Updating Warmup Time
Custom Match States
Cooldown Announcement
Restart Game
Blaster Game State
Different Weapon Types
Rocket Projectiles
Rocket Trails
Spawning Rocket Trails
Rocket Movement Component
Hit Scan Weapons
Beam Particles
Submachine Gun
Strap Physics
Shotgun
Weapon Scatter
Sniper Rifle
Sniper Scope
Grenade Launcher
Projectile Grenades
Reload Animations
Shotgun Reload
Weapon Outline Effect
Grenade Throw Montage
Weapon Attachment while Throwing Grenades
Grenade Assets
Showing the Attached Grenade
Spawning Grenades
Grenades in Multiplayer
Grenades in the HUD
Pickups
Pickup Class
Ammo Pickups
Buff Component
Health Pickup
Healing the Character
Speed Buffs
Jump Buffs
Shield Bar
Updating the Shield
Shield Buffs
Pickup Spawn Point
Adding Spawn Points to the Level
Spawn Default Weapon
Secondary Weapon
Swap Weapons
Drop the Secondary Weapon
Lag Compensation
Lag Compensation Concepts
High Ping Warning
Local Fire Effects
Show the Widget Locally
Replicating Scatter
Replicating Shotgun Scatter
Client-Side Prediction
Shotgun Fire RPCs
Client-Side Predicting Ammo
Client-Side Predicting Aiming
Client-Side Predicting Reloading
Server-Side Rewind
Lag Compensation Component
Hit Boxes
Frame Package
Saving a Frame Package
Frame History
Rewinding Time
Interp Between Frames
Confirming the Hit
Score Request
Server-Side Rewind for Shotguns
Confirming Shotgun Hits
Shotgun Score Request
Requesting a Shotgun Hit
Predict Projectile Path
Post Edit Change Property
Spawning Projectiles Locally
Hit Box Collision Type
Projectile Server-Side Rewind
Projectile Score Request
Limiting Server-Side Rewind
Swap Weapon Animation
Wrapping up Lag Compensation
Cheating and Validation
More Multiplayer Features
Return to Main Menu
Leaving the Game
Player Bookkeeping
Gaining The Lead
Spawning the Crown
Elim Announcements
Dynamic Elim Announcements
Head Shots
Projectile Head Shots
Head Shots for Server-Side Rewind
Teams
Teams
Teams Game Mode
Team Colors
Setting Team Colors
Preventing Friendly Fire
Team Scores
Updating Team Scores
Teams Cooldown Announcement
Capture the Flag
Capture the Flag
Holding the Flag
Picking up the Flag
Burdening the Flag Bearer
Dropping the Flag
Team Flags
Team Player Starts
Capture the Flag Game Mode
Select Match Type
Accessing our Subsystem
Teams and Capture the Flag Maps
Congratulations
Congratulations
Bonus Lecture
The text was updated successfully, but these errors were encountered: