当前位置: 首页 > news >正文

艾尔登复刻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 update
        public 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 update
        public 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上,但需要注意:不同场景下执行挂载操作产生的效果不同

相关文章:

  • Spring Boot 读取 ZooKeeper (ZK) 属性的总结指南
  • Lsposed模块原理详解
  • AI概率学预测足球大小球让球数据分析
  • 工作记录 2017-01-06
  • 支持向量机(SVM)原理与应用
  • Redis Sentinel 深度解析:构建高可用分布式缓存系统的核心机制
  • ActiveMQ监听器在MQ重启后不再监听问题
  • 用户可免费体验!国家超算互联网平台上线阿里开源推理模型接口服
  • Python网络爬虫之requests库的使用方法
  • 在虚拟机中部署kafka
  • AI 中对内存的庞大需求
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_04带选择框的固定表头表格
  • JavaScript_Day2
  • Xcode 16.2 最低部署版本调整
  • 卡尔曼滤波算法从理论到实践:在STM32中的嵌入式实现
  • 【isaacgym报错】安装isaacgym运行报错RuntimeError: Error building extension ‘gymtorch‘
  • 无电池也能通信!中国移动5G-A芯片重塑物联网未来
  • Linux信号之捕捉信号
  • 【算法day8】整数反转
  • 【Linux】动/静态库
  • 王毅将主持召开第三次中国—太平洋岛国外长会
  • 马上评|当众猥亵女演员,没有任何开脱理由
  • 西岸大剧院夏秋演出季公布,阿云嘎制作《风声》9月驻演
  • 秦洪看盘|热门股或将退潮,短线波动难免
  • 【社论】鸿蒙破壁,向最难处攻坚
  • 又是“9+2”复式票,浦东退休阿姨擒大乐透1153万头奖