艾尔登复刻Ep1——客户端制作、场景切换、网络控制

需要添加的插件内容

Netcode for GameObjects:是一个为 Unity 游戏开发提供高级网络功能的 SDK。它的主要作用是允许开发者在其 GameObject 和 MonoBehaviour 工作流中集成网络功能,并且可以与多种底层传输层协议兼容。

具体内容请看:https://zhuanlan.zhihu.com/p/669642159

ParrelSync:ParrelSync 是一个 Unity 编辑器扩展,旨在帮助开发者在没有构建项目的情况下测试多人游戏玩法。通过使用 ParrelSync,开发者可以在多个 Unity 编辑器窗口中同时运行项目,从而快速测试多人游戏的功能和同步问题。

具体内容请看:ParrelSync 安装和配置指南-CSDN博客

客户端制作

Network manager 

        添加了Net for work脚本后,可以给物体挂载Network manager脚本。我们需要创建一个空物体,并将该脚本挂载上。

编写客户端控制脚本

这段脚本代码的作用是管理游戏的标题屏幕,提供两个主要功能:

  1. 启动网络会话作为主机(StartNetworkAsHost),允许其他客户端连接。

  2. 开始一个新游戏(StartNewGame),加载游戏的初始状态。

using SG;
using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;namespace SG
{public class TitleScreenManager : MonoBehaviour{// Start is called before the first frame updatepublic void StartNetworkAsHost(){NetworkManager.Singleton.StartHost();}public void StartNewGame(){StartCoroutine(WorldSaveManager.instance.LoadNewGame());}}}

命名空间: 

  • namespace SG:定义了一个命名空间,用于组织代码,避免命名冲突。

    • 团队开发中,不同开发者可能会使用相同的标识符名称(如函数、类、变量等),导致命名冲突。命名空间通过为标识符添加一个前缀(即命名空间名称),将标识符限定在一个特定的作用域内,从而避免了全局作用域中的命名冲突。

StartNetworkAsHost方法:

  • 这个方法的作用是启动一个网络主机(Host)。在Unity Netcode中,主机既是服务器又是客户端,可以允许其他客户端连接到它
  • NetworkManager.Singleton.StartHost();:
    • NetworkManager是Unity Netcode(以前称为UNet)中的一个单例类,用于管理网络会话。

    • SingletonNetworkManager的单例实例,确保在整个应用程序中只有一个NetworkManager对象。

    • StartHost()NetworkManager的一个方法,用于启动主机模式。当用户调用StartHost()时,实际上是让用户的电脑设备承担了主机的角色,同时运行服务器和客户端的功能。

StartNewGame方法:

  • 这个方法用于开始一个新游戏。
    • WorldSaveManager.instance:假设WorldSaveManager是一个单例模式的管理器类,instance是其唯一的实例。

    • LoadNewGame():这是一个协程方法,用于加载新游戏。协程在Unity中用于执行需要分多个帧完成的操作,通常用于避免主线程阻塞。

        注意,这个挂载Network Manager脚本的空物体要加入预制体,在Unity中,将脚本挂载在空物体上作为单例管理器是一种常见的设计模式,这种模式能够确保在整个游戏或应用中只有一个实例存在,并且提供了一个全局的访问点,要添加至Asset—prefabs中。

挂载unity import

        将 Unity Transport 挂载在 NetworkManager 物体上,是为了让 NetworkManager 使用它来处理网络连接和数据传输。Unity Transport 作为 NetworkManager 的传输层,负责实际的网络通信工作,使得 NetworkManager 能够通过网络与其他客户端或服务器进行交互。

        将脚本Unity Transport挂载到Network Transport

编写切换大世界场景脚本 

        用于Unity游戏引擎中的世界保存管理器(WorldSaveManager)。它的主要功能是管理游戏世界的加载。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;namespace SG
{public class WorldSaveManager : MonoBehaviour{// Start is called before the first frame updatepublic static WorldSaveManager instance;[SerializeField] int worldSceneIndex = 1;private void Awake(){if (instance == null){instance = this;}else{Destroy(gameObject);}}private void Start(){DontDestroyOnLoad(gameObject);}public IEnumerator LoadNewGame(){AsyncOperation loadOperation = SceneManager.LoadSceneAsync(worldSceneIndex);yield return null;}}
}
[SerializeField] int worldSceneIndex = 1;
  • 这是一个Unity提供的特性(Attribute),用于指定一个私有字段(private field)应该在Unity编辑器的Inspector面板中显示并可编辑。

  • 通常情况下,私有字段不会在Inspector面板中显示,但添加了[SerializeField]特性后,该字段就会在Inspector中可见,允许你在编辑器中直接修改它的值。 

private void Start()
{DontDestroyOnLoad(gameObject);
}

 这是Unity的另一个生命周期方法,在Awake之后调用。在这里,它调用了DontDestroyOnLoad方法,确保WorldSaveManager实例在场景切换时不会被销毁。

public IEnumerator LoadNewGame()
{AsyncOperation loadOperation = SceneManager.LoadSceneAsync(worldSceneIndex);yield return null;
} 

        这段代码的作用是启动一个异步操作,用于加载指定索引的场景。加载过程不会阻塞主线程,游戏可以继续运行,同时场景在后台加载。

  • SceneManager.LoadSceneAsync(worldSceneIndex):使用Unity的场景管理器异步加载指定索引的场景(这里是worldSceneIndex)。

    • SceneManager.LoadSceneAsync:这是Unity引擎中SceneManager类的一个静态方法,用于异步加载场景。

    • AsyncOperation:这是一个返回值类型,表示异步操作的对象。通过这个对象,可以监听页面加载的进度和状态。

  • yield return null:这是一个协程的暂停点,表示在下一帧继续执行。这里可能需要进一步的逻辑来处理场景加载的完成,比如等待加载完成后再继续执行其他操作


        Q1:什么是异步操作?

        A1:异步操作是指一个操作在启动后,不会立即阻塞当前线程的执行,而是允许当前线程继续处理其他任务,直到该操作完成。

                异步操作通常用于执行耗时的任务,例如文件读写、网络请求、场景加载等,以避免主线程被阻塞,导致应用程序响应迟缓或卡顿。

        Q2:为什么这里要用异步操作?

        A2:在Unity中,加载场景是一个耗时的操作,特别是当场景包含大量资源(如模型、纹理、动画等)时。如果使用同步加载(即SceneManager.LoadScene),主线程会被阻塞,直到场景加载完成。这会导致游戏在加载期间出现卡顿,甚至完全冻结,严重影响用户体验。

                通过使用异步加载(即SceneManager.LoadSceneAsync),场景的加载过程会在后台进行,而主线程可以继续处理其他任务,例如更新UI、播放加载动画、响应用户输入等。这样可以确保游戏在加载场景时仍然保持流畅的运行。

        注意,这个挂载world Save Manager脚本的空物体要加入预制体 

        

如何设置场景序号

1、先将当前客户端场景——save as——保存到Asset——Scene中(相当于另存一份),再删去多余的一份。

2、为场景添加序号

        进入当前场景后,进入Building Setting界面,点击Add Open Scenes

为客户端设置按钮 

1、button的第一个设定:使网络会话作为主机(StartNetworkAsHost),允许其他客户端连接。

2、button的第二个设定:隐藏Start Game游戏栏

3、button的第三个设定:显示New Game游戏栏

4、button的第四个设定:Select 方法会将按钮设置为选中状态,这通常会触发按钮的选中效果(如高亮设置等视觉效果)

        将Screen Manager脚本挂载至Screen Canvas


        将Screen Canvas物体挂载到New Game游戏栏的按钮上,即点击New Game栏时,进入游戏场景

设置游戏角色管理脚本 

using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;namespace SG
{public class CharacterManger : MonoBehaviour{public static CharacterManger instance;[Header("NETWORK JOIN")][SerializeField] bool startGameAsClient;private void Awake(){if (instance == null){instance = this;}else{Destroy(gameObject);}}private void Start(){DontDestroyOnLoad(gameObject);}private void Update(){if (startGameAsClient){startGameAsClient = false;NetworkManager.Singleton.Shutdown();NetworkManager.Singleton.StartClient();}}}
}
[Header("NETWORK JOIN")]
[SerializeField] bool startGameAsClient;
  • bool startGameAsClient;:一个布尔变量,用于决定游戏启动时是否作为客户端加入游戏
  • [Header("NETWORK JOIN")] 的作用是将下面的变量 [SerializeField] bool startGameAsClient; 归类到"NETWORK JOIN"这一部分


    这样在Unity编辑器中,这个变量会显示在检查器面板的"NETWORK JOIN"标题下。

if (startGameAsClient)
{startGameAsClient = false;NetworkManager.Singleton.Shutdown();NetworkManager.Singleton.StartClient();
}
  1. if (startGameAsClient)

    • 检查startGameAsClient是否为true。如果是,表示需要以客户端模式加入游戏。

  2. startGameAsClient = false;

    • startGameAsClient设置为false,以确保这个逻辑只执行一次,避免重复触发。

  3. NetworkManager.Singleton.Shutdown();

    • 调用NetworkManager的单例实例的Shutdown方法。

    • 作用:关闭当前的网络管理器,清理网络状态。

    • 目的:确保在重新启动客户端连接之前,清除任何现有的网络连接和状态,避免冲突或资源泄漏。

  4. NetworkManager.Singleton.StartClient();

    • 调用NetworkManager的单例实例的StartClient方法。

    • 作用:以客户端模式启动网络连接,使游戏客户端连接到服务器。 

 使动画角色对应网络连接

        安装了网络插件后,为了让场景角色也有网络效应,我们要给物体加上该组件



        将物体挂载到NetworkManager的Player Prefab上,但需要注意:不同场景下执行挂载操作产生的效果不同

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

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

相关文章

2025探索短剧行业新可能报告40+份汇总解读|附PDF下载

原文链接:https://tecdat.cn/?p41043 近年来,短剧以其紧凑的剧情、碎片化的观看体验,迅速吸引了大量用户。百度作为互联网巨头,在短剧领域积极布局。从早期建立行业专属模型冷启动,到如今构建完整的商业生态&#xf…

正常的一个编码器的架构是怎么样,有哪些模块构成

正常的一个编码器架构及其模块构成 在音视频编码器(Video Encoder)中,通常包括多个核心模块,整个编码器架构遵循 输入 -> 预处理 -> 编码核心 -> 码流封装 的流程。 1. 编码器的整体架构 编码器的主要架构如下&#xf…

文件解析漏洞练习

iis6的目录解析漏洞 (.asp目录中的所有文件都会被当做asp文件执行) 1.在iis的网站根目录新建一个名为x.asp的文件 2.在x.asp中新建一个jpg文件。内容为<%now()%> asp代码。 3.在外部浏览器中访问windows2003的iis网站中的2.jpg 发现asp代码被执行 iis6的分号截断解析漏洞…

SQL Server性能优化实战:从瓶颈定位到高效调优

引言 在数据库应用中,性能问题直接影响用户体验和系统稳定性。本文基于实际案例,分享SQL Server性能优化的关键步骤与实用技巧,涵盖问题定位、索引优化、查询调优等多个维度。 目录 引言 一、性能瓶颈定位 1.1 监控工具使用 二、索引优化实战 2.1 索引碎片整理 2.2 缺…

【DNS系列】使用TCP传输

DNS ​默认使用UDP协议​&#xff08;端口53&#xff09;进行通信&#xff0c;但在以下场景中会切换到TCP协议​&#xff08;端口53&#xff09;&#xff1a; ​1. 响应数据过大&#xff08;超过512字节&#xff09;​ ​UDP限制&#xff1a;DNS的UDP协议默认限制单个数据包大…

Go Ebiten小游戏开发:俄罗斯方块

在这篇文章中&#xff0c;我们将一起开发一个简单的俄罗斯方块游戏&#xff0c;使用Go语言和Ebiten游戏库。Ebiten是一个轻量级的游戏库&#xff0c;适合快速开发2D游戏。我们将逐步构建游戏的基本功能&#xff0c;包括游戏逻辑、图形绘制和用户输入处理。 项目结构 我们的项…

MySQL中IN关键字与EXIST关键字的比较

文章目录 **功能等价性分析****执行计划分析**&#xff1a; **1. EXISTS 的工作原理****步骤拆解**&#xff1a; **2. 为什么需要“利用索引快速定位”&#xff1f;****索引作用示例**&#xff1a; **3. 与 IN 子查询的对比****IN 的工作方式**&#xff1a;**关键差异**&#x…

## DeepSeek写水果记忆配对手机小游戏

DeepSeek写水果记忆配对手机小游戏 提问 根据提的要求&#xff0c;让DeepSeek整理的需求&#xff0c;进行提问&#xff0c;内容如下&#xff1a; 请生成一个包含以下功能的可运行移动端水果记忆配对小游戏H5文件&#xff1a; 要求 可以重新开始游戏 可以暂停游戏 卡片里的水果…

【含文档+PPT+源码】基于Django框架的乡村绿色农产品交易平台的设计与实现

项目介绍 本课程演示的是一款基于Django框架的乡村绿色农产品交易平台的设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Python学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运…

idea超级AI插件,让 AI 为 Java 工程师

引言​ 用户可在界面中直接通过输入自然语言的形式描述接口的需求&#xff0c;系统通过输入的需求自动分析关键的功能点有哪些&#xff0c;并对不确定方案的需求提供多种选择&#xff0c;以及对需求上下文进行补充&#xff0c;用户修改确定需求后&#xff0c;系统会根据需求设…

@RestControllerAdvice注解

RestControllerAdvice RestControllerAdvice 是 Spring Framework&#xff08;3.2&#xff09;和 Spring Boot 中用于全局处理控制器层异常和统一响应格式的注解。它结合了 ControllerAdvice 和 ResponseBody 的功能&#xff0c;能够拦截控制器方法抛出的异常&#xff0c;并以 …

ActiveMQ监听器在MQ重启后不再监听问题

应用的监听器注解 JmsListener(destination "TopicName",containerFactory "FactoryName")工厂代码 BeanJmsListenerContainerFactory<?> FactoryName(ConnectionFactory connectionFactory){SimpleJmsListenerContainerFactory factory new S…

大白话 Vue 中的keep - alive组件,它的作用是什么?在什么场景下使用?

大白话 Vue 中的keep - alive组件&#xff0c;它的作用是什么&#xff1f;在什么场景下使用&#xff1f; 什么是 keep-alive 组件 在 Vue 里&#xff0c;keep-alive 是一个内置组件&#xff0c;它就像是一个“保存盒”&#xff0c;能把组件实例保存起来&#xff0c;而不是每次…

考研复试c语言常见问答题汇总2

11. 关键字和一般标识符有什么不同&#xff1f; C语言中关键字与一般标识符区别&#xff1a; 定义&#xff1a;关键字是C语言预定义的特殊单词&#xff08;如int、for&#xff09;&#xff0c;有固定含义&#xff1b;标识符是自定义的名称&#xff08;如变量名、函数名&#xf…

Scala编程_实现Rational的基本操作

在Scala中实现一个简单的有理数&#xff08;Rational&#xff09;类&#xff0c;并对其进行加法、比较等基本操作. 有理数的定义 有理数是可以表示为两个整数的比值的数&#xff0c;通常形式为 n / d&#xff0c;其中 n 是分子&#xff0c;d 是分母。为了确保我们的有理数始终…

若依框架-给sys_user表添加新字段并获取当前登录用户的该字段值

目录 添加字段 修改SysUser类 修改SysUserMapper.xml 修改user.js 前端获取字段值 添加字段 若依框架的sys_user表是没有age字段的&#xff0c;但由于业务需求&#xff0c;我需要新添加一个age字段&#xff1a; 修改SysUser类 添加age字段后&#xff0c;要在SysUser类 …

霍夫变换法是基于传统视觉特征的道路车道线检测算法中的一种经典方法

霍夫变换法是基于传统视觉特征的道路车道线检测算法中的一种经典方法&#xff0c;以下是对它的详细介绍&#xff1a; 基本原理 霍夫变换的基本思想是将图像空间中的点映射到参数空间中&#xff0c;通过在参数空间中寻找峰值来确定图像中特定形状的参数。在车道线检测中&#…

【论文笔记】Best Practices and Lessons Learned on Synthetic Data for Language Models

论文信息 论文标题&#xff1a;Best Practices and Lessons Learned on Synthetic Data for Language Models 作者信息&#xff1a; Ruibo Liu, Jerry Wei, Fangyu Liu, Chenglei Si, Yanzhe Zhang, Jinmeng Rao, Steven Zheng, Daiyi Peng, Diyi Yang, Denny Zhou1 and Andre…

Android调试工具之ADB

Android Debug Bridge ADB介绍**一、ADB下载****二、ADB安装****三、ADB基础使用命令** ADB介绍 ADB&#xff08;Android Debug Bridge&#xff09;是Android开发与调试的必备工具&#xff0c;掌握它能极大提升开发效率。 一、ADB下载 Windows版本&#xff1a;https://dl.goo…

第三篇《RMAN 备份与恢复指南:保障数据库安全》(RMAN)

《Oracle 数据迁移与备份系列》 第三篇&#xff1a;《RMAN 备份与恢复指南&#xff1a;保障数据库安全》&#xff08;RMAN&#xff09; 1.概述 RMAN&#xff08;Recovery Manager&#xff09; 是 Oracle 数据库内置的专用备份与恢复工具&#xff0c;提供高效、安全的物理级数…