【unity笔记】七、Mirror插件使用
一、简介
Mirror 是一个用于 Unity 的开源多人游戏网络框架,它提供了一套简单高效的网络同步机制,特别适用于中小型多人游戏的开发。以下是 Mirror 插件的一些关键特点和组件介绍:
- 简单高效:Mirror 以其简洁的 API 和高效的网络代码而受到开发者的欢迎。
- 基于 UnityEngine 生命周期:Mirror 利用 Unity 的生命周期回调进行数值同步,简化了网络开发流程。
- RPC 调用:Mirror 提供了三种远程过程调用(RPC)的方式:[Command]、[ClientRpc] 和[TargetRpc],允许开发者在不同客户端或服务器上执行特定的函数。
- 网络组件:
- NetworkManager:用于管理网络会话,包括开始服务器、客户端和处理玩家连接。
- NetworkIdentity:为游戏对象添加网络身份,使其能够在网络上被识别和同步。
- NetworkStartPosition:用于设置玩家的初始生成位置。 网络发现:Mirror
-
支持局域网内的网络发现功能,方便玩家发现并加入游戏。
-
运输层兼容性:Mirror 兼容多种低级运输层,包括但不限于 TCP、UDP 和 KCP 协议。
-
开箱即用:Mirror 在 Unity Asset Store 中免费提供,并且具有丰富的文档和社区支持。
-
适用于小体量游戏:Mirror 更适合小型到中型的游戏项目,对于大型游戏项目可能需要更复杂的网络解决方案。
Mirror官网方文档:https://mirror-networking.gitbook.io/docs。
二、 使用示例
2.1 效果预览
实现简单多人联机小游戏

2.2 步骤1 添加网络管理
新建一个空对象,并为其添加Network Manager、Kcp Transport、Network Manager HUD组件。

其中:在Network Manager中添加在线场景和离线场景以及玩家预制体,玩家预制体可以从网上寻找模型或者使用内置模型代替,注意玩家预制体要添加 Network Identity组件。
最大玩家设为4对应4个玩家生成点,玩家生成方法可以设为随机或轮循。

在Kcp Transport中的配置可以不用动,也可以根据需要配置。

2.3 环境设置
- 地形可以简单用一个Plane来代替,如果对质量要求高可以后期替换为别的素材,添加天气系统,使用HDRP等可以看往期内容。
- 为玩家添加生成位置,这里放置四个位置生成玩家,前面已经设置了最大玩家数为4,则可以有四个不同玩家进入游戏,并在预设位置生成。可以先设置好一个,在复制加下来几个并设置好想要生成的位置。使用一个空对象添加Network Start Position即可。

2.3 代码部分
为玩家添加代码来操作玩家移动
playerScript参考代码
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Numerics;
using Mirror;
using UnityEngine;
using static System.Runtime.CompilerServices.RuntimeHelpers;
using Color = UnityEngine.Color;
using Random = UnityEngine.Random;
using Vector3 = UnityEngine.Vector3;public class PlayerScrpt : NetworkBehaviour
{public GameObject floatingInfo;public TextMesh nameText;//武器public GameObject[] weaponArray;private int currentWeapon;private Weapon activeWeapon;private float coolDownTime;private Material playMaterialClone;//private UIScript UI;[SyncVar(hook = nameof(OnPlayerNameChanged))]private string playerName;[SyncVar(hook = nameof(OnPlayerColorChanged))]private Color playerColor;[SyncVar(hook = nameof(OnWeaponChanged))]private int currentWeaponSynced;//name改变触发private void OnPlayerNameChanged(string oldName, string newName){nameText.text = newName;}//颜色改变触发private void OnPlayerColorChanged(Color oldColor, Color newColor){//同步名称颜色nameText.color = newColor;//同步材质颜色playMaterialClone = new Material(GetComponent<Renderer>().material);playMaterialClone.SetColor("_Color", newColor);}//切换武器private void OnWeaponChanged(int oldIndex, int newIndex){//判断旧武器是否存在,若存在则隐藏if (0 < oldIndex && oldIndex < weaponArray.Length && weaponArray[oldIndex] != null){weaponArray[oldIndex].SetActive(false);}if (0 < newIndex && newIndex < weaponArray.Length && weaponArray[newIndex] != null){weaponArray[newIndex].SetActive(true);activeWeapon = weaponArray[newIndex].GetComponent<Weapon>();//显示当前武器子弹数量//UI.canvasBulletText.text = activeWeapon.bulletCount.ToString();}else{activeWeapon = null; //若武器不存在,则激活武器为空//UI.canvasBulletText.text = "No Weapon";}}[Command]public void CmdSetupPlayer(string newName, Color colorValue){playerName = newName;playerColor = colorValue;}[Command]public void CmdActiveWeapon(int index){currentWeaponSynced = index;}[Command]public void CmdFire(){/*if (activeWeapon == null)return;*/RpcFire();}[ClientRpc]public void RpcFire(){var bullet = Instantiate(activeWeapon.bullet, activeWeapon.firePos.position, activeWeapon.firePos.rotation);bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * activeWeapon.bulletSpeed;Destroy(bullet, activeWeapon.bulletLifetime);}private void Awake(){foreach (var weapon in weaponArray){if (weapon != null){weapon.SetActive(false);}}}public override void OnStartLocalPlayer(){//摄像机与Player绑定Camera.main.transform.SetParent(transform);Camera.main.transform.localPosition = Vector3.zero;floatingInfo.transform.localPosition = new Vector3(0f, -2.7f, 6f);floatingInfo.transform.localScale = new Vector3(1f, 1f, 1f);changePlayerNameAndColor();}// Update is called once per framevoid Update(){if (!isLocalPlayer){floatingInfo.transform.LookAt(Camera.main.transform);return;}var moveX = Input.GetAxis("Horizontal") * Time.deltaTime * 110f;var moveZ = Input.GetAxis("Vertical") * Time.deltaTime * 4.0f;transform.Rotate(0, moveX, 0);transform.Translate(0, 0, moveZ);if (Input.GetKeyDown(KeyCode.C)) //按下c改变颜色{changePlayerNameAndColor();}if (Input.GetButtonDown("Fire2")){currentWeapon += 1;if (currentWeapon > weaponArray.Length)currentWeapon = 1;CmdActiveWeapon(currentWeapon);}if (Input.GetButtonDown("Fire1")){if (activeWeapon != null && Time.time > coolDownTime && activeWeapon.bulletCount > 0){coolDownTime = Time.time + activeWeapon.coolDown;//更新子弹数量activeWeapon.bulletCount--;//UI.canvasBulletText.text = activeWeapon.bulletCount.ToString();CmdFire();}}}//改变玩家名称和颜色private void changePlayerNameAndColor(){var tempName = $"Player {Random.Range(1, 999)}";var tempColor = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f));CmdSetupPlayer(tempName, tempColor);}
}
Weapon参考代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Weapon : MonoBehaviour
{public Transform firePos; //子弹位置public GameObject bullet; // 子弹对象public float bulletSpeed = 5f; //子弹速度public float bulletLifetime = 3f;//子弹生命周期public int bulletCount = 15; //子弹数量public float coolDown = 0.5f;}
三、项目生成
接下来就可以点击文件->构建和运行,把游戏文件发给小伙伴一起玩耍。

将localhost改成自己当前ip,即可让小伙伴加入房间远程游玩了。如果链接失败,记得关闭防火墙!
相关文章:
【unity笔记】七、Mirror插件使用
一、简介 Mirror 是一个用于 Unity 的开源多人游戏网络框架,它提供了一套简单高效的网络同步机制,特别适用于中小型多人游戏的开发。以下是 Mirror 插件的一些关键特点和组件介绍: 简单高效:Mirror 以其简洁的 API 和高效的网络…...
掌握SEO:如何优化用ChatGPT生成的文章以提升搜索排名
在数字化时代,搜索引擎优化(SEO)已经成为网站流量的重要来源。随着人工智能技术的进步,越来越多的人开始使用ChatGPT等AI工具来生成文章。然而,虽然这些工具可以快速生成内容,但要确保这些内容在搜索引擎中…...
Java面试问题(一)
一.Java语言具有的哪些特点 1.Java是纯面向对象语言,能够直接反应现实生活中的对象 2.具有平台无关性,利用Java虚拟机运行字节码文件,无论是在window、Linux还是macOS等其他平台对Java程序进行编译,编译后的程序可在其他平台上运行…...
Firewalld防火墙基础
Firewalld 支持网络区域所定义的网络连接以及接口安全等级的动态防火墙管理工具 支持IPv4、IPv6防火墙设置以及以太网桥 支持服务或应用程序直接添加防火墙规则接口 拥有两种配置模式 运行时配置:临时生效,一旦重启或者重载即不生效 永久配置:…...
解决Java中多线程同步问题的方案
解决Java中多线程同步问题的方案 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在Java开发中,多线程同步问题是我们经常面对的挑战之一。正确处理…...
每日一练 - RSTP与STP收敛速度对比
01 真题题目 RSTP 收敛速度比 STP 要快,以下说法正确的是? A. 在 RSTP 中检测拓扑是发生变化只有一个标准.一个非边缘端口迁移到 Forwarding 状态 B. 在 STP 中,为了避免临时环路,至少要等待一个 Forwarding Delay 待全网端口确定,所有端口才能进行转发 C. P/A …...
ZS-20H型水泥胶砂振实台
一、 概述 水泥胶砂振实台是为我国水泥胶砂强度检验方法等同采ISO679国际标准而设计。该仪器符合 JC/T 682《水泥胶砂试体成型振实台》要求,适用于水泥强度检验所用试样的制备。 二、 技术数据 1、台盘(包括臂杆、压模框等)的总质量 13.75 …...
力扣377 组合总和Ⅳ Java版本
文章目录 题目描述代码 题目描述 给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 示例 1: 输入:nums [1,2,3], targe…...
昇思25天学习打卡营第3天 | 数据集 Dataset
数据是深度学习的基础,高质量的数据输入将在整个深度神经网络中起到积极作用。MindSpore提供基于Pipeline的数据引擎,通过数据集(Dataset)和数据变换(Transforms)实现高效的数据预处理。其中Dataset是Pipel…...
交换机三层架构及对流量的转发机制
交换机的作用: 区别集线器(HUB); HUB 为物理层设备,只能直接转发电流 交换机为数据链路层设备,可以将电流与二进制转换,实现了以下功能: 无限的传输距离 彻底解决了冲突-所有的接口可以同时收发数据 二…...
开发者配置项、开发者选项自定义
devOptions.vue源码 <!-- 开发者选项 (CtrlAltShiftD)--> <template><div :class"$options.name" v-if"visible"><el-dialog:custom-class"sg-el-dialog":append-to-body"true":close-on…...
【Java】解决Java报错:IndexOutOfBoundsException in Collections
文章目录 引言一、IndexOutOfBoundsException的定义与概述1. 什么是IndexOutOfBoundsException?2. IndexOutOfBoundsException的常见触发场景3. 示例代码 二、解决方案1. 检查索引范围2. 使用增强型for循环3. 使用ListIterator进行遍历4. 使用线程安全的集合 三、最…...
C++编程(三)面向对象
文章目录 一、概念二、类的定义(一)声明一个类类型的语法格式:(二)类中的访问控制权限(三)实例化对象1. 栈区对象2. 堆区对象 (四)类内声明类外实现(五&#…...
Batch入门教程
Batch学习在多个领域有不同的应用,但最常见的是在机器学习和教育学习领域。以下是一个关于Batch学习入门的清晰指南,将分别介绍这两个领域中的Batch学习概念、方法和一些实用信息。 1. 机器学习中的Batch学习 定义与概念 Batch_Size:在机器…...
49-2 内网渗透 - 使用UACME Bypass UAC
靶场准备: 1. 使用已有的 Windows 2012 虚拟机 确保你的虚拟机正在运行,并且可以正常访问。2. 添加 test 用户到管理员组(如上篇文件添加过了就跳过这一步) 具体命令如下: net localgroup administrators test /add 3. 切换用户登录 注销当前会话,并使用 test 用户登录。…...
Django 表单使用示例:数据格式校验
在本文中,我们将使用 Django 的表单(Forms)功能来创建一个添加角色的页面,并对用户提交的数据进行格式校验。 创建 Django 项目和应用 首先,我们创建一个名为 form_demo 的 Django 项目和一个名为 app01 的应用: django-admin startproject form_de…...
OkHttp框架源码深度剖析【Android热门框架分析第一弹】
OkHttp介绍 OkHttp是当下Android使用最频繁的网络请求框架,由Square公司开源。Google在Android4.4以后开始将源码中的HttpURLConnection底层实现替换为OKHttp,同时现在流行的Retrofit框架底层同样是使用OKHttp的。 源码传送门 优点: 支持Http1、Http…...
【MySQL】数据库——备份与恢复,日志管理1
一、数据备份的重要性 1.备份的主要目的是灾难恢复 在生产环境中,数据的安全性至关重要 任何数据的丢失都可能产生严重的后果造成数据丢失的原因: 程序错误人为,操作错误运算错误磁盘故障灾难(如火灾、地震)和盗窃 2.数据库备份…...
什么样的企业适合SD-WAN网络专线?
SD-WAN(Software-Defined Wide Area Network,软件定义广域网)是一种网络技术,它利用软件定义的方式管理和控制广域网(WAN),旨在提高网络效率、降低成本并简化网络管理。以下是适合采用SD-WAN网络…...
已解决java.security.GeneralSecurityException: 安全性相关的通用异常的正确解决方法,亲测有效!!!
已解决java.security.GeneralSecurityException: 安全性相关的通用异常的正确解决方法,亲测有效!!! 目录 问题分析 报错原因 解决思路 解决方法 确定具体异常类型 检查输入参数 验证算法支持性 调整安全策略 确保资源可…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
