Unity学习之路10——多人游戏与网络

2023-11-19

Unity学习之路10——多人游戏与网络

作业要求:

  • 选择一个以前的作业或自己选择一个小游戏,设计成网络游戏

效果图:

实现过程

上一次作业的基础上,将AI小坦克改成双人对战坦克游戏。

  • 主要参考资料——老师的博客
  • Step1:
    为了简化,去掉了上次作业的SceneController,IUserAction,IUserGUI,GameDirector,Enemy代码文件,只保留Player.cs,Bullet.cs,MyFactory.cs,Tank.cs文件。

  • Step2:Player中原逻辑不变,将UI中检测用户按键输入的代码迁移到Player.cs里的Update函数中:

public class Player : Tank{
    // player被摧毁时发布信息;
    /* public delegate void DestroyPlayer();
     public static event DestroyPlayer destroyEvent;*/

    public override void OnStartLocalPlayer()
    {
        GetComponent<MeshRenderer>().material.color = Color.blue;
    }
    void Start () {
        setHP(500);   
    }

    // Update is called once per frame
    void Update () {
        if (!isLocalPlayer)
            return;
        Camera.main.transform.position = new Vector3(gameObject.transform.position.x, 18, gameObject.transform.position.z);
        if (getHP() <= 0)    // Tank is destoryed
        {
            this.gameObject.SetActive(false);
            //destroyEvent();
        }

        if (Input.GetKey(KeyCode.W))
        {
            moveForward();
        }

        if (Input.GetKey(KeyCode.S))
        {
            moveBackWard();
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("space");
            CmdFire(TankType.PLAYER);
        }
        //获取水平轴上的增量,目的在于控制玩家坦克的转向
        float offsetX = Input.GetAxis("Horizontal");
        turn(offsetX);
    }

    //向前移动
    public void moveForward()
    {
        gameObject.GetComponent<Rigidbody>().velocity = gameObject.transform.forward * 25;
    }
    //向后移动
    public void moveBackWard()
    {
        gameObject.GetComponent<Rigidbody>().velocity = gameObject.transform.forward * -25;
    }

    //通过水平轴上的增量,改变玩家坦克的欧拉角,从而实现坦克转向
    public void turn(float offsetX)
    {
        float x = gameObject.transform.localEulerAngles.x;
        float y = gameObject.transform.localEulerAngles.y + offsetX*2;
        gameObject.transform.localEulerAngles = new Vector3(x, y, 0);
    }
}
  • Step3:其中Player继承的Tank需要改一下,记住Tank.cs继承的不再是MonoBehaviour,而是NetworkBehaviour:
public class Tank : NetworkBehaviour
{
    private float hp =500.0f;
    // 初始化
    public Tank()
    {
        hp = 500.0f;
    }

    public float getHP()
    {
        return hp;
    }

    public void setHP(float hp)
    {
        this.hp = hp;
    }

    public void beShooted()
    {
        hp -= 100;
    }

    [Command]
    public void CmdFire(TankType type)
    {
        GameObject bullet = Singleton<MyFactory>.Instance.getBullets(type);

        bullet.transform.position = new Vector3(gameObject.transform.position.x, 1.5f, gameObject.transform.position.z) + gameObject.transform.forward * 1.5f;
        bullet.transform.forward = gameObject.transform.forward; //方向
        bullet.GetComponent<Rigidbody>().AddForce(bullet.transform.forward * 20, ForceMode.Impulse);

        NetworkServer.Spawn(bullet);

        Destroy(bullet, 2.0f);
    }
}

其中[Command]是用来标记该函数是在服务端执行的,即使是在客户端触发也是在服务端执行,还有该函数名一定是要以Cmd开头命名的;然后在函数里调用NetworkServer.Spawn()使服务端和客户端同步。

  • Step4:Bullet.cs根据需要修改一下,代码模块就修改成这样,接下来是网络的构建,按照老师的一步一步来:
    Game Object -> Create Empty 添加一个新的空游戏对象;将对象重命名为“NetworkManager”,往该物体添加NetworkManager和NetworkManagerHUD组件(选中该物体,在菜单栏里选Component-> Network -> NetworkManager);成功后界面应该是这样:

另外还要将Player和Bullet预制(即坦克与子弹预制)拖进对应的slot槽才有以上界面,而预制要按Step5里的步骤添加组件才能拖到对应的slot槽里。

  • Step5:分别往Player和Bullet预制添加NetworkIdentity和NetworkTransform组件(Component->Network->NetworkIdentity或NetworkTransform)其中NetworkIdentity组件用于标识服务器和客户端之间的对象,而NetworkTransform组件使对象在网络中同步它的位置。
    Player预制添加组件后的效果,记得把Local Player Authority勾上:

  • Step6:Bullet预制添加组件后的效果:

  • Step7:运行代码(老师博客上也有对应的详细操作步骤)

    • 使用菜单 File -> Build Settings 打开 Build Settings 对话框。
    • 按下 “Add Open Scenes” 按钮,将当前场景添加到版本。
    • 按 “Build and Run” 按钮创建构建。这会提示输入可执行文件的名称,随便输入一个名称。
    • 译后的独立程序将启动,并显示分辨率选择对话框。
    • 选择 “windowed” 复选框和较低的分辨率,如640x480。
    • 从菜单中选择 “HOSTED” 作为主机启动。
    • 切换回编辑器并关闭 Build Settings 对话框,使用运行按钮进入运行模式。
    • 从 NetworkManagerHUD 用户界面中,选择 “LAN Client” 作为客户端连接到主机。
    • 应该出现两个坦克,一个在主机上的本地运行,另一个在该客户端的远程运行。
    • 效果图:

未解决的问题

  • 做的不好,还遗留一些问题:
    • 坦克只实现了移动同步,即客户端或服务端里其中一个坦克移动,另一个窗口里对应的坦克也会移动。
    • 坦克的射击功能还有bug,在客户端点击空格射击时服务端显示正常,客户端有时没显示子弹,有时显示的子弹运动路径诡异。由于时间关系,这部分暂时没处理,如果有解决方案的欢迎在评论区留言。

附言

  • 代码的传送门
  • 这次仅是自己的学习心得,想更好学习请移步到大神的博客。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity学习之路10——多人游戏与网络 的相关文章

  • 计算机图形学 3D渲染 笔记(一)

    1 坐标系 大多数计算机屏幕采用的坐标系是以左上角为原点 水平 右 为x轴 纵向 下 为y轴 3D图形学习中通常使用另一种坐标系 即 正中心为原点 水平 右 为x轴 纵向 上 为y轴 当前者坐标系转化到后者 需要进行简单的转化 Sx Sy为
  • IDEA2021.2安装与配置(持续更新)

    IDEA2021 2安装与配置 持续更新 一 下载 二 安装 三 配置 3 1 配置全局生效 3 2 首次启动 3 3 激活 3 4 字体 字体大小 3 5 配色方案 3 6 注解生效 3 7 自动导包移包 3 8 自动补全快捷键 3 9
  • vue-nginx刷新404问题

    文章目录 1 背景介绍 2 问题描述 2 1 问题一 2 2 问题二 3 原因分析 3 1 问题一 3 2 问题二 4 排查问题一原因 5 反思 6 nginx root与alias的使用 7 更优雅地解决vue网页浏览器刷新404 7 1
  • Mongodb——使用Mongodb对字段中字符串内容进行截取,并进行分组统计

    最近忙的厉害 除了发一发之前写的存货只能写一些简单的东西了 这里就简单分享下最近遇见针对数据进行指标统计遇见的问题 针对字段中某部分内容的指标统计 在使用mongodb进行指标统计的时候可能遇见下面的数据结构 1 id ObjectId 5
  • 短信备份到另一个手机android,旧手机的短信怎么转移到新手机上?三种方法总有一种适合你...

    手机短信一直以来都是我们和其他对象传输信息的工具 更是存储了大量重要的信息 如果我们更换手机需要保留下来这些短信该怎么办呢 有没有什么方法可以将这些短信转移到新手机中去 或者导出到电脑上进行保管呢 这里有三种方法 第一种方法用内存卡 可以打
  • C++仿函数

    1 仿函数的定义 仿函数简单说就是在类中定义的特殊函数 没有函数名 或者说函数名统一为 operation 或者可以认为是重载运算符 格式为 返回类型 operator 参数列表 定义了仿函数的对象 可以直接通过下面格式调用仿函数 对象名
  • 异步加载vue组件

    什么时候使用 组件较大 或者不是必用的 通常组件在script标签对中导入 而异步组件在component中使用 例如 components ForData gt import view Fordata
  • J2EE集合框架

    1 UML 二 集合的基本特点 list集合的特点 增删改查 有序 可重复 三 List集合的三种遍历方式 for foreath iterator 四 ArrayList LinkedList 的比较与分析 比较 1 ArrayList
  • 基于Matlab的灰狼算法优化LSTM风电功率预测

    基于Matlab的灰狼算法优化LSTM风电功率预测 随着可再生能源的快速发展 风能作为一种重要的清洁能源形式变得越来越受关注 风电功率预测在风电场的运营和调度中起着关键作用 然而 由于风速的不稳定性和不确定性 精确地预测风电功率仍然具有一定
  • SpringCloud Gateway:status: 503 error: Service Unavailable

    使用SpringCloud Gateway路由请求时 出现如下错误 yml配置如下 可能的一种原因是 yml配置了gateway discovery locator enabled true 此时gateway会使用负载均衡模式路由请求 但
  • Lim接口测试平台-接口测试功能详解

    一 接口测试 项目地址 Gitee Github 接口测试模块是整个Lim平台的核心 左侧是接口的模块树 右侧顶部是用例操作功能区 列表展示接口用例信息 文章目录 一 接口测试 二 维护接口用例 各步骤类型详解 1 执行步骤 1 接口步骤
  • Unity --- 触摸方法,以及灯光与烘培的使用

    触摸方法 1 首先触摸分为两大类 多点触摸和单点触摸 这两种方式的触摸通过下面这个触摸数来进行判断 当其等于1的时候 为单点触摸 当其大于1的时候为多点触摸 2 当我们在调用触摸方法的时候我们首先需要打开对应的多点 单点触摸 上面这个是开启
  • QObject的d_ptr成员——箭头符号的重载

    QObject中的d ptr是这样定义的 QScopedPointer
  • vscode cmake 编译32位程序

    vscode cmake 编译32位程序 为什么要用cmake vscode中的C C 插件直接支持的只是最简单的单文件编译 运行和调试 要管理大的项目 或者生成库 C C 插件不能直接支持 需要开发者利用vscode的task功能 结合脚
  • 【由浅入深】爬虫技术,值得收藏,来了解一下~

    爬虫技术 来了解一下 一 为什么需要爬虫技术 现在的互联网来说 包含着各种海量的信息 无孔不入 包罗万象 出于数据分析或产品需求 我们需要从某些网站 提取出我们感兴趣 有价值的内容 我们需要一种能自动获取网页内容并可以按照指定规则提取相应内

随机推荐

  • 关于两数交换的两种方法

    目录 前言 一 引入变量 这个方法也是最常用的方法 二 通过使用数学的方法相加或者相减从而得到两数运算 这种方法不常见 总结 前言 从键盘输入两个整数 并交换两位数字 这里小编用两种方法告诉大家 注意小编这里用的是VS2019 所以在代码的
  • STM32 --通用定时器输入捕获功能

    问题 开始的时候没有搞清楚 定时器时基 于 定时器溢出中断的概念 导致在计算频率的时候一直有问题 开始并没有怀疑是配置有问题 因为之前接触过定时器输入捕获功能 靠着自己的记忆配置了一下 认为 捕获功能 的定时是通过定时器设置的定时溢出频率来
  • 栈实现队列(继续细起来啊)

    生命不是要等待风暴过去 而是要学会在风暴中跳舞 卡莉尔 吉布朗目录 一 栈实现队列 二 使用两个栈实现队列的功能 1 在队列的结构体中创建两个栈 2 创建一个队列的结构体指针 3 myQueuePush入队列操作 4 myQueuePeek
  • SpringBoot项目实战(一)

    SpringBoot实战之系统架构 1 系统介绍 该实战项目 是一个B2C模式的职业技能在线教育系统 分为前台用户系统和后台运营平台 前台用户系统包括课程 问答 文章三大部分 后台运营平台包括会员管理 讲师管理 课程管理 文章资讯 统计分析
  • Gradle入门(二)尝试理解gralde编译项目

    前言 前面我们了解了如何通过groovy DSL转换为KTS 我也在尝试的证明可以看到源码和有代码提示对于入门的重要性 2022年11月12日 我发现最新的idea 有gradle的代码提示 点击也可以看到源码 学习Gradle还是建议整一
  • .NET框架和发展历史介绍

    NET框架知识 NET 框架是由微软开发的软件开发平台 其最主要的两个组成部分是公共语言运行时 CLR 和框架类库 FCL 基础类库 BCL 是框架类库的一个子集 NET框架的主要结构如下图所示 1 操作系统 最下层的无疑就是操作系统了 2
  • Linux内核之pid为0和pid为1【转】

    转自 https blog csdn net jingyilin2008 article details 7815508 ops request misc 257B 2522request 255Fid 2522 253A 25221592
  • 【Linux】Mint20.3系统安装Anaconda环境

    Anaconda是非常方便的python开发IDE环境 其中不仅包含了很多常用python库还有Spyder运行环境 Mint系统是近些年非常受欢迎的linux系统 易上手已操作特性使其普及非常快 本篇介绍在Mint20 3系统安装Anac
  • haclcon实现图像处理的傅里叶变换

    dev open file dialog read image default default Selection read image Image Selection mean image Image ImageMean 9 9 gaus
  • 多柱汉诺塔(Matrix上选做题)——递归与动态规划

    分析 对于三柱汉诺塔问题 我们已经熟知步骤数最优解为 2 i 1 2 i 1 2i 1 其中 i 为盘子个数 对于四柱以上的问题 我们将柱子分为三类 起点柱Start 辅助柱Buf
  • 侯捷系列:c++面向对象高级编程(上)

    文章目录 基于对象的程序设计 不带有指针成员变量的类 以复数类 Complex 为例 头文件的结构 访问级别 函数设计 内联函数 构造函数 常量成员函数 参数的值传递和引用传递 返回值的值传递和引用传递 友元 操作符重载 在类内声明 pub
  • sqli-labs (less-33)

    sqli labs less 33 进入33关 输入id 1 这里我们直接通过查看源代码查看这关是否也使用了GBK编码 可知确实使用了GBK编码 所以我们在单引号前面输入 df即可让单引号成功逃逸 http 127 0 0 1 sql1 L
  • nodejs后端相关知识总结

    1 koa koa执行逻辑代码 app use async ctx next gt await next ctx response type text html ctx response body h1 Hello koa2 h1 每收到一
  • 『Python基础-15』递归函数 Recursion Function

    什么是递归函数 一种计算过程 如果其中每一步都要用到前一步或前几步的结果 称为递归的 用递归过程定义的函数 称为递归函数 例如连加 连乘及阶乘等 凡是递归的函数 都是可计算的 即能行的 递归就是一个函数在它的函数体内调用它自身 编程语言中的
  • 基于Matlab实现图像拼接技术(附上完整源码+图像)

    图像拼接是数字图像处理中一个重要的问题 它的目标是将多张图像拼接成一张更大的图像 图像拼接技术在许多领域中都有广泛的应用 如全景图像拼接 医学图像拼接 遥感图像拼接等 本文将介绍一种基于Matlab实现的图像拼接技术 即基于特征匹配的图像拼
  • java快速获取mac地址的方法

    在开发中需要获取电脑的mac地址 记录一下java快速获取mac地址的方法 也可获取到ip地址 public static void main String args throws UnknownHostException SocketEx
  • Class类文件结构

    Class文件是一组以8位字节为基础单位的二进制流 各个数据项目严格按照顺序紧凑地排列在Class文件中 中间没有添加任何分隔符 这使得整个Class文件中存储的内容几乎全部都是程序运行的必要数据 没有空隙存在 根据Java虚拟机规范的规定
  • 解决QT连续发送数据的问题

    在QT的学习网络的学习中 最大的问题是服务器与客户端收发数据的问题 当一方连续发送几次数据给另一方时 容易出现好几种错误 1 收到的数据不全 只有第一个 2 收不到 3 收到的数据不对 readyRead在信号到达时 开始接收 我即使调用几
  • 微信小程序自动检测版本并提示更新新版本

    微信小程序自动检测版本并提示更新新版本 微信小程序开发过程中 我们在版本更新迭代后 微信小程序客户端并不能触发自动更新 需要用户手动清理小程序后重新搜索进入后才能获取到最新的小程序版本 但是这个是用户所不能感知到的操作 也很麻烦 故需要提醒
  • Unity学习之路10——多人游戏与网络

    Unity学习之路10 多人游戏与网络 作业要求 选择一个以前的作业或自己选择一个小游戏 设计成网络游戏 效果图 实现过程 在上一次作业的基础上 将AI小坦克改成双人对战坦克游戏 主要参考资料 老师的博客 Step1 为了简化 去掉了上次作