【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: 安全性相关的通用异常的正确解决方法,亲测有效!!! 目录 问题分析 报错原因 解决思路 解决方法 确定具体异常类型 检查输入参数 验证算法支持性 调整安全策略 确保资源可…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...
