【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 frame
    void 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,即可让小伙伴加入房间远程游玩了。如果链接失败,记得关闭防火墙!

猜你喜欢

转载自blog.csdn.net/qq_45906972/article/details/139981297