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

【unity笔记】七、Mirror插件使用

一、简介

Mirror 是一个用于 Unity 的开源多人游戏网络框架,它提供了一套简单高效的网络同步机制,特别适用于中小型多人游戏的开发。以下是 Mirror 插件的一些关键特点和组件介绍:

  1. 简单高效:Mirror 以其简洁的 API 和高效的网络代码而受到开发者的欢迎。
  2. 基于 UnityEngine 生命周期:Mirror 利用 Unity 的生命周期回调进行数值同步,简化了网络开发流程。
  3. RPC 调用:Mirror 提供了三种远程过程调用(RPC)的方式:[Command]、[ClientRpc] 和[TargetRpc],允许开发者在不同客户端或服务器上执行特定的函数。
  4. 网络组件
  • NetworkManager:用于管理网络会话,包括开始服务器、客户端和处理玩家连接。
  • NetworkIdentity:为游戏对象添加网络身份,使其能够在网络上被识别和同步。
  • NetworkStartPosition:用于设置玩家的初始生成位置。 网络发现:Mirror
  1. 支持局域网内的网络发现功能,方便玩家发现并加入游戏。

  2. 运输层兼容性:Mirror 兼容多种低级运输层,包括但不限于 TCP、UDP 和 KCP 协议。

  3. 开箱即用:Mirror 在 Unity Asset Store 中免费提供,并且具有丰富的文档和社区支持。

  4. 适用于小体量游戏: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,即可让小伙伴加入房间远程游玩了。如果链接失败,记得关闭防火墙!

http://www.lryc.cn/news/383804.html

相关文章:

  • 掌握SEO:如何优化用ChatGPT生成的文章以提升搜索排名
  • Java面试问题(一)
  • Firewalld防火墙基础
  • 解决Java中多线程同步问题的方案
  • 每日一练 - RSTP与STP收敛速度对比
  • ZS-20H型水泥胶砂振实台
  • 力扣377 组合总和Ⅳ Java版本
  • 昇思25天学习打卡营第3天 | 数据集 Dataset
  • 交换机三层架构及对流量的转发机制
  • 开发者配置项、开发者选项自定义
  • 【Java】解决Java报错:IndexOutOfBoundsException in Collections
  • C++编程(三)面向对象
  • Batch入门教程
  • 49-2 内网渗透 - 使用UACME Bypass UAC
  • Django 表单使用示例:数据格式校验
  • OkHttp框架源码深度剖析【Android热门框架分析第一弹】
  • 【MySQL】数据库——备份与恢复,日志管理1
  • 什么样的企业适合SD-WAN网络专线?
  • 已解决java.security.GeneralSecurityException: 安全性相关的通用异常的正确解决方法,亲测有效!!!
  • 秋招Java后端开发冲刺——非关系型数据库篇(Redis)
  • 个人对JVM的一点理解
  • Flutter【组件】可折叠文本组件
  • 内容安全复习 7 - 对抗攻击与防御
  • 淘宝店铺商家订单API-接入ERP,多平台订单同步的利器
  • 【微前端-Single-SPA、qiankun的基本原理和使用】
  • 多元化功能空间,打造影像产业生态圈
  • 华为鸿蒙正式杀入工业自动化,反攻开始了!
  • 学历优先还是专业优先?高考志愿填报的抉择
  • SpringAOP常用功能实现
  • Java基础的重点知识-04-封装