Unity使用Mirror制作局域网的同步

2023-09-14 14:32:36

1.脚本布置.参考tank那个demo制作

1.新建空物体,为管理脚本的物体:manager,挂载NetworkManager,kcpTransport,NetworkManagerHud.
2.设置玩家出生点,spawnPoint,设置好初始化的position的位置(*),挂载NetworkStartPosition的脚本
3.新建Player的预制体,挂载NetworkIdentity,NetworkTransform(unreliable)的脚本,还有自己的自定义脚本,注意自定义脚本需要继承NetworkBehaviour,这个在编辑的时候需要改改.下面是主玩家的移动代码MainPlayerControll.cs.
4.新建turret的预制体,挂载rigibody, NetworkIdentity, TurretMove,“rigibody需要关闭重力”.

using Mirror;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;

public class MainPlayerControll : NetworkBehaviour
{
    public float speed = 5;
    public float Rspeed = 25;
    public GameObject turretPrefab;
    public Transform firepoint;
    [SyncVar] public int health = 10;
    int lastHealth = 0;
    public TextMesh nameTxt;
    public override void OnStartLocalPlayer()
    {
        base.OnStartLocalPlayer();
        Camera.main.transform.SetParent(transform);
        Camera.main.transform.localPosition = new Vector3(0, 0.5f, 0);
        Camera.main.transform.localRotation = Quaternion.identity;
    }
    public override void OnStopLocalPlayer()
    {
        base.OnStopLocalPlayer();
        Camera.main.transform.SetParent(null);
    }
    void Update()
    {
        if (health != lastHealth)
        {
            nameTxt.text = $"{gameObject.name} <color=red>{health}</color>";
            lastHealth = health;
        }
        if (!isLocalPlayer) return;

        float horizontalInput = Input.GetAxis("Horizontal");
        float verticalInput = Input.GetAxis("Vertical");

        Vector3 movement = transform.forward * verticalInput * speed * Time.deltaTime;
        Vector3 rotation = new Vector3(0f, horizontalInput * Rspeed * Time.deltaTime, 0f);

        transform.Translate(movement, Space.World);
        transform.Rotate(rotation);
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CmdFire();
        }
    }
    [Command]
    void CmdFire()
    {
        GameObject projectile = Instantiate(turretPrefab, firepoint.position, firepoint.rotation);
        NetworkServer.Spawn(projectile);
    }
    [ServerCallback]
    void OnTriggerEnter(Collider other)
    {
        if (other.GetComponent<TurretMove>() != null)
        {
            --health;
            if (health == 0)
                NetworkServer.Destroy(gameObject);
        }
    }
}
using Mirror;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TurretMove : NetworkBehaviour
{
    public float destroyAfter = 2;
    public Rigidbody rigidBody;
    public float force = 1000;
    public override void OnStartServer()
    {
        Invoke(nameof(DestroySelf), destroyAfter);
    }

    void Start()
    {
        rigidBody.AddForce(transform.forward * force);
    }

    // destroy for everyone on the server
    [Server]
    void DestroySelf()
    {
        NetworkServer.Destroy(gameObject);
    }
    [ServerCallback]
    void OnTriggerEnter(Collider co) => DestroySelf();
}

2.注意:在manager的NetworkManager中,需要给PlayerPrefab赋值,拖入制作的player预制体,transport中拖入同物体的kcpTransport组件.playerspawnMethod选择RoundRobin.
player预制体的MainPlayerControll脚本需要拖入子弹的预制体,还要拖入一个开火点,开火点:就是创建一个空物体放在player上作为开火点.
子弹只需要把自己的的rigibody拖进去到TurretMode.cs脚本里

主玩家脚本里的广播的字段 需要这样声明写 [SyncVar] public int health = 10;

一些被动碰撞,触发的方法也要加上 [ServerCallback]

  [ServerCallback]
    void OnTriggerEnter(Collider other)
    {
        if (other.GetComponent<TurretMove>() != null)
        {
            --health;
            if (health == 0)
                NetworkServer.Destroy(gameObject);
        }
    }

主动触发 如开火:需要加 [Command]

    [Command]
    void CmdFire()
    {
        GameObject projectile = Instantiate(turretPrefab, firepoint.position, firepoint.rotation);
        NetworkServer.Spawn(projectile);
    }

总结:

[Command]:用于在客户端调用服务器上的方法。客户端可以使用该标记调用服务器上的方法,并将其作为命令进行处理。方法名称必须以 “Cmd” 开头。
[ClientRpc]:用于在服务器上调用并在所有连接的客户端上执行的方法。服务器可以使用该标记调用方法,并在所有连接的客户端上执行。方法名称可以任意命名。
[TargetRpc]:用于在服务器上调用并在特定客户端上执行的方法。服务器可以使用该标记调用方法,并在特定的客户端上执行。方法名称可以任意命名。
[ServerCallback]:用于指示方法只在服务器上执行,不在客户端上执行。该标记用于在服务器上定义特定逻辑或处理服务器端的事件。方法名称可以任意命名。

注意事项:

[Command]、[ClientRpc] 和 [TargetRpc] 方法必须在继承自 NetworkBehaviour 的脚本中使用,并且需要正确配置网络连接和同步设置。
[Command] 方法只能从客户端调用,并且只在服务器上执行。
[ClientRpc] 方法只能在服务器上调用,并在所有连接的客户端上执行。
[TargetRpc] 方法只能在服务器上调用,并且只在特定的客户端上执行。
[ServerCallback] 方法只在服务器上执行,不在客户端上执行。

方法开头规则:

[Command] 标记的方法名称必须以 “Cmd” 开头。
[ClientRpc]、[TargetRpc] 和 [ServerCallback] 标记的方法名称可以任意命名。

更多推荐

【二叉搜索树】将有序数组转换为二叉搜索树-力扣 108 题

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。推荐:kuan的首页,持续学习,不断总结,共同进步,活到老学到老导航檀越剑指大厂系列:全面总结java核心技术点,如集合,jvm,并发编程redis,kaf

Controller统一异常处理和yaml配置

目录Controller统一异常处理url解析static下静态资源文件的访问配置类如何访问static下的资源文件yaml基础语法注解赋值批量注入单个注入Controller统一异常处理Controller统一异常处理@ControllerAdvice:统一为Controller进行"增强"@ExceptionHan

微信小程序的疫苗接种预约设计与实现vue+uniapp

对于本小程序的疫苗预约的设计来说,系统开发主要是采用java语言,在整个系统的设计中应用MySql数据库来完成数据存储,具体根据疫苗预约信息的现状来进行开发的,具体根据现实的需求来实现疫苗预约网络化的管理,各类信息有序地进行存储,进入微信小程序的疫苗预约页面之后,方可开始操作主控界面,主要功能包括用户、疫苗分类、疫苗信

html学习综合案例1

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>个人简介</title></head><body><h1>尤

【c++&GDAL】IHS融合

【c++&GDAL】IHS融合基于IHS变换融合,实现多光谱和全色影像之间的融合。IHS分别指亮度(I)、色度(H)、饱和度(S)。IHS变换融合基于亮度I进行变换,色度和饱和度空间保持不变。IHS融合步骤:(1)将多光谱RGB影像变换到IHS空间;(2)基于一定融合规则使用亮度分量I与全色影像进行变换,得到新的全色I

WebGL 选中物体

目录前言如何实现选中物体示例程序(PickObject.js)代码详解gl.readPixels()函数规范示例效果前言有些三维应用程序需要允许用户能够交互地操纵三维物体,要这样做首先就得允许用户选中某个物体。对物体进行选中操作的用处很广泛。比如,让用户选中三维用户界面上的一个按钮,或者让用户选中三维场景中的多张照片中

提升前端开发效率:基于vue的van-radio-group组件封装指南

前言vant作为一款流行的ui框架,其中,van-radio-group组件是一个常用的单选框组件,但有时我们需要根据项目需求进行定制化封装。本文将介绍如何基于vue框架封装van-radio-group组件,让我们一起来探索吧!封装文件在这个组件中,使用了vant框架提供的van-radio-group和van-ra

Linux-网卡和网络配置

链接一篇大佬的博客:Linux之手把手教会修改网卡名称文章目录修改网卡名称步骤1:修改“/etc/default/grub”步骤2:修改“/etc/sysconfig/network-scripts”下的文件步骤3:修改“ifcfg-eth0”配置步骤4:判断操作系统的引导模式步骤5:根据不同的引导模式重新读取配置文件

el-table 列背景色渐变

最初的想法是,给每一行添加背景色,逐行递减透明度,发现结果比较突兀,效果如下:如果有需要这种样式的,代码如下:<template><div><el-table:data="tableData":header-cell-style="headerCellStyle":cell-style="cellStyle"style

Redis Part1

单体架构:一台Web服务器、一台数据库服务器。回顾,关系型数据库:基于二维表来存储数据的数据库就是关系型数据库。MySQL跟Redis的区别:MySQL是关系型数据库,它是基于表来存储数据的,MySQL数据是写在磁盘的,它是跟磁盘进行交互的;Redis是非关系型数据库,它是把数据存储在内存当中的,是跟内存进行交互的。M

Go基础语法:数组

6数组6.1数组的定义数组在定义时就需要声明其元素数量和类型://T即元素类型var数组变量名[元素数量]T如:vara[5]int.数组的长度必须是常量,并且长度是数组类型的一部分,一旦定义,长度不能变。所以,[5]int和[10]int是不同的类型。packagemainimport"fmt"funcmain(){

热文推荐