需要添加的插件内容
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脚本。我们需要创建一个空物体,并将该脚本挂载上。
编写客户端控制脚本
这段脚本代码的作用是管理游戏的标题屏幕,提供两个主要功能:
启动网络会话作为主机(
StartNetworkAsHost
),允许其他客户端连接。开始一个新游戏(
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)中的一个单例类,用于管理网络会话。
Singleton
是NetworkManager
的单例实例,确保在整个应用程序中只有一个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(); }
if (startGameAsClient)
:
检查
startGameAsClient
是否为true
。如果是,表示需要以客户端模式加入游戏。
startGameAsClient = false;
:
将
startGameAsClient
设置为false
,以确保这个逻辑只执行一次,避免重复触发。
NetworkManager.Singleton.Shutdown();
:
调用
NetworkManager
的单例实例的Shutdown
方法。作用:关闭当前的网络管理器,清理网络状态。
目的:确保在重新启动客户端连接之前,清除任何现有的网络连接和状态,避免冲突或资源泄漏。
NetworkManager.Singleton.StartClient();
:
调用
NetworkManager
的单例实例的StartClient
方法。作用:以客户端模式启动网络连接,使游戏客户端连接到服务器。
使动画角色对应网络连接
安装了网络插件后,为了让场景角色也有网络效应,我们要给物体加上该组件
将物体挂载到NetworkManager的Player Prefab上,但需要注意:不同场景下执行挂载操作产生的效果不同