Unity之PUN实现多人联机射击游戏的优化(Section 2)
目录
🎮一、准备工作
🎮二、实现手雷投掷动作
🎮三、手雷投掷同步
💤3.1 photonView.RPC
🎮四、同步手雷伤害
这几周都给我布置任务了,最近可忙。现在终于有机会更新了,也谢谢大家的阅读,我们一起进步。如果前面两篇大家有没有看到的可以在本篇文章末尾点击链接查看,资源包也在博客里有链接。

今天就来兑现诺言:有天我查看这个游戏包的资源,居然发现了手雷和其他很多武器,而且手雷的爆炸脚本是写好的,那就试着加一个手雷功能。看一下效果

手雷爆炸的原理呢就像小编之前写的物理系统里面的小实例一样:
Unity之物理系统_unity 物理系统-CSDN博客文章浏览阅读1.3k次,点赞22次,收藏20次。专栏的上一篇角色控制器控制角色移动跳崖,这一篇来说说Unity的物理系统。本篇小编还要带大家做一个碰撞检测效果实例,先放效果图:流星撞击地面产生爆炸效果。_unity 物理系统https://blog.csdn.net/qq_48512649/article/details/135600857
手雷扔出去爆炸手雷的预设体会销毁对应的则生成爆炸特效的预设体。给爆炸特效加上碰撞组件,爆炸特效生成的一瞬间就会产生把玩家击飞的效果,随后爆炸特效预设体跟着消失。这个资源里边自带的脚本已经帮我们实现好了。
放在单击游戏上实现起来很简单,但是对于小编来说最难的是数据同步,没办法既然想实现这个功能就试着去摸索。
看一下踩过的坑,比如下面的图片,其中一个玩家画面里就会看到一个尸体在动,还会打人!!!!这就是数据同步没有做好,就会很搞笑

修改之后,就小编目前的测试来说可以实现同步了(在公司只能开小窗口测试doge.jpg)

一、准备工作
首先来看资源包中手雷预设体的位置,这里所挂载的组件和数值大家可以进行参考

这是爆炸特效预设体的位置以及其挂载的组件:

玩家预设体上有一个手雷生成点,当我们按下投手雷时就设定在这个点生成手雷。缺点是只能朝着这个角度进行投掷。

二、实现手雷投掷动作
在前面两期代码的基础上,我们在PlayerController脚本来添加按下Q键实现投掷手雷的功能,这里做了一个设定是每隔5秒可以投一次手雷。
//定义布尔值判断手雷是否可以进行投掷
private bool boolHandGrenade = false;//角色操作:在判断为本机玩家操作的前提下
public void InputCtl()
{//按ESC退出游戏// if (Input.GetKeyDown(KeyCode.Escape))// {// Application.Quit();// }if (Input.GetKeyDown(KeyCode.Q)){if (boolHandGrenade == false){boolHandGrenade = true;//每隔5秒才可以扔一次Invoke("boolThrowHandGrenade", 5f);//播放投掷手雷动作动画ani.Play("Grenade_Throw");StopAllCoroutines();//开启协程同步手雷的生成,在三部分讲StartCoroutine(AttHandGrenade());}}
}//更改判断手雷是否可以进行投掷的布尔值
void boolThrowHandGrenade()
{boolHandGrenade = false;
}
上面这个代码块只实现了玩家投掷手雷时所做的动作,但是要生成手雷要在所有玩家画面上都要进行同步生成,我们接着往下看。
三、手雷投掷同步
手雷预设体生成的代码小编写在Gun脚本里了,和子弹生成的逻辑差不多。代码写好后我们按准备工作中的内容把手雷生成点和手雷预设体设置好。
//枪的脚本
public class Gun : MonoBehaviour
{public int BulletCount = 10;public GameObject bulletPrefab;public GameObject casingPreafab;public Transform bulletTf;public Transform casingTf;//手雷public GameObject handGrenadePrefab;//手雷生成点public Transform handGrenadeTf;void Start(){}public void Attack(){//实例化一个子弹GameObject bulletObj = Instantiate(bulletPrefab);bulletObj.transform.position = bulletTf.transform.position;bulletObj.GetComponent<Rigidbody>().AddForce(transform.forward * 500, ForceMode.Impulse); //子弹速度 让中心点跟枪口位置可自行调整摄像机的偏移值GameObject casingObj = Instantiate(casingPreafab);casingObj.transform.position = casingTf.transform.position;}public void AttGrenade(){//实例化一个手雷GameObject handGrenadeObj = Instantiate(handGrenadePrefab,handGrenadeTf.transform.position,handGrenadeTf.transform.rotation);handGrenadeObj.GetComponent<Rigidbody>().AddForce(transform.forward * 1,ForceMode.Impulse); //投掷速度 让中心点跟枪口位置可自行调整摄像机的偏移值}
}
手雷生成的代码写好后我们来设置同步。在之前第二部分中,我们现在来讲
//开启协程同步手雷的生成,在三部分讲
StartCoroutine(AttHandGrenade());//协程方法实现
IEnumerator AttHandGrenade()
{yield return new WaitForSeconds(0.5f);// 3.1 photonView.RPC 中讲解photonView.RPC("throwHandGrenade", RpcTarget.All); //所有玩家执行 AttackRpc 函数
}[PunRPC]
public void throwHandGrenade()
{gun.AttGrenade(); //这里会执行Gun脚本中的AttGrenade()方法
}
3.1 photonView.RPC
进入源代码我们来看这一方法:参数有三个(方法名、目标群体、参数)

这句代码的意思是所标注的目标群体一块执行我们自己写的方法,下图是目前群体的枚举类型:

第三个参数 params object[] parameters 小编看到它最终是存到一个 Hashtable 类型里,我们现在只用到了前两个参数。
![]()

对应到我们的代码中意思就是当前房间所有玩家同步其中一个人所生成的手雷。
四、同步手雷伤害
依然在PlayerController脚本里,我们给爆炸特效一个Boom的图层标签,用来检测它是否与玩家发生碰撞。
//监听发生碰撞: 只监听发生碰撞的一瞬间
private void OnCollisionEnter(Collision collision) //参数 collision 就是你碰撞到的物体的碰撞信息
{//给地面一个图层"Ground" collision.collider.tag == "Ground" 可以判断物体是否踩在地面上if (collision.collider.tag == "Boom"){GetHit(localPlayer,3,2);}
}
如果发生碰撞了就执行GetHit方法,这里我们给GetHit方法加了参数,因为爆炸和枪击的伤害值和得分是不同设定的,我们通过参数来进行区分。伤害值大家可以根据自己的想法设定。

上图是枪击执行的GetHit方法。
//同步所有角色受伤: p 本机玩家,addScore 获得的分, AttackHp 不同武器的伤害值不同public void GetHit(Player p,int addScore,int AttackHp){if (isDie == true){return;}switch (AttackHp){case 1://同步所有角色受伤:枪伤photonView.RPC("GetGunHitRPC", RpcTarget.All); break;case 2://同步所有角色受伤:爆炸伤photonView.RPC("GetBoomHitRPC", RpcTarget.All); break;default:Debug.Log("------------ERROR");break;}Score += addScore;p.SetScore(Score);}[PunRPC]public void GetGunHitRPC(){CurHp -= 1; //扣血if (CurHp <= 0){CurHp = 0;isDie = true;}if (photonView.IsMine){Game.uiManager.GetUI<FightUI>("FightUI").UpdateHp(CurHp, MaxHp);Game.uiManager.GetUI<FightUI>("FightUI").UpdateBlood();if (CurHp == 0){Invoke("gameOver", 3); //3秒后显示失败界面 }}}[PunRPC]public void GetBoomHitRPC(){CurHp -= 3; //扣血if (CurHp <= 0){CurHp = 0;isDie = true;}if (photonView.IsMine){Game.uiManager.GetUI<FightUI>("FightUI").UpdateHp(CurHp, MaxHp);Game.uiManager.GetUI<FightUI>("FightUI").UpdateBlood();if (CurHp == 0){Invoke("gameOver", 3); //3秒后显示失败界面 }}}
GetGunHitRPC 和 GetBoomHitRPC 除了伤害值不同其他逻辑都相同,小编本来想合成一个共用的方法奈何没成功,目前只能shi山堆积了。如果大家有更好的写法小编还要虚心向大家请教。
前面两篇博客的链接:
Unity之PUN2插件实现多人联机射击游戏_unity pun2-CSDN博客文章浏览阅读1.3k次,点赞20次,收藏24次。周五的下午永远要比周六幸福,周五好啊大家有在认真摸鱼吗。前两天我突发奇想想做联机游戏,就去找教程,肝了一天终于做出来了。先说一下搜寻资料过程中找到的实现游戏联机暂时就记录了这11个,做的这个实例是通过PUN2实现的,先看一下效果:个人感觉这套模型和这个教程泰裤辣,能跟着做完这个游戏Demo也是很开心的,下面依然以博客的形式记录实现这个游戏的过程。_unity pun2https://blog.csdn.net/qq_48512649/article/details/136249522Unity之PUN实现多人联机射击游戏的优化(Section 1)_unity pun2 角色名称-CSDN博客文章浏览阅读1.5k次,点赞23次,收藏28次。关于优化了哪几个小点:点击开始游戏玩家可以输入自己的昵称;进入到房间后玩家对应的昵称也会同步显示到房间列表上;和朋友一起玩的时候他说会卡进房间的模型里建议我加上跳跃功能,我就给加上了,顺便加了一个按住Shift和方向键进行加速跑;同时按住Tab键会显示出计分板,这个计分板是按照射击命中次数来计分的。_unity pun2 角色名称
https://blog.csdn.net/qq_48512649/article/details/136615629今天先到这里,拜拜┏(^0^)┛

相关文章:
Unity之PUN实现多人联机射击游戏的优化(Section 2)
目录 🎮一、准备工作 🎮二、实现手雷投掷动作 🎮三、手雷投掷同步 💤3.1 photonView.RPC 🎮四、同步手雷伤害 这几周都给我布置任务了,最近可忙。现在终于有机会更新了,也谢谢大家的阅读&a…...
多叉树题目:N 叉树的层序遍历
文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题:N 叉树的层序遍历 出处:429. N 叉树的层序遍历 难度 4 级 题目描述 要求 给定一个 N 叉树的根结点 root \texttt{root} root…...
时序数据库IoTDB:功能详解与行业应用
一文读懂时序数据库 IoTDB。 01 为什么需要时序数据库 解释时序数据库前,先了解一下何谓时序数据。 时序数据,也称为时间序列数据,是指按时间顺序记录的同一统计指标的数据集合。这类数据的来源主要是能源、工程、交通等工业物联网强关联行业…...
信息系统项目管理师——第18章项目绩效域管理(一)
本章节内容属于第四版新增知识,为PMBOK第七版专有,选择、案例、论文都会考,属于比较重要的章节。 选择题,稳定考3分左右,新教材基本考课本原话,需要多读课本,多刷题。 案例题,考的概…...
WebSocket用户验证
在WebSocket中,如何携带用户的验证信息 一、在OnMessage中进行验证 客户端在连接到服务器后,客户端通过发送消息,服务器端在OnMessage方法中,进行信息验证,这种方式需要将用户身份验证及接收用户消息进行混合处理&am…...
NOSQL(非关系型数据库)的优缺点有哪些?
优点: 高度灵活且可扩展:NoSQL数据库不受固定数据模型的限制,可以根据应用需求灵活设计数据结构,轻松应对大规模数据集。此外,它支持分布式架构,具有出色的水平扩展能力,能够高效地处理大量数据…...
个人推荐Redis比较好的一种使用规范
随着对个人项目的不断开发、迭代和重构,博主在这个过程中总结出了一套使用redis的较好的规范。主要包含Redis的key命名规范和Redis代码规范。 主要内容 主要包含以下几个内容: 同一应用的key在最前面添加统一的前缀,如应用名; 案…...
【教程】宝塔default.db占用空间几十g解决方法|宝塔占用磁盘空间特别大解决方法|宝塔磁盘被占满怎么清理
目录 一、前言二、排查问题三、解决方法 一、前言 用过宝塔创建网站,大家应该都非常熟悉,但是用随着用的时间越来越多,宝塔所占用的空间也越来越多,不停的加大数据盘都没有用,我原先买了30G够用了,随着时间…...
Unity类银河恶魔城学习记录11-15 p117 Ice and Fire item Effect源代码
Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili IceAndFire_Controller.cs using System.Collections; using System.Coll…...
Qt QML的枚举浅用
QML的枚举用法 序言概念命名规则在QML定义枚举的规范 用法QML的枚举定义方法供QML调用的,C的枚举定义方法 序言 概念 QML的枚举和C的其实差不多,但是呢,局限比较多,首先不能在main.qml里定义,也不能在子项中定义。 …...
设计模式:单例模式六种实现
单例模式有多种实现方式,每种方式都有其设计思想、优缺点以及适用的使用场景。以下是一些常见的单例实现方式: 1. 懒汉式(线程不安全) 设计思想 这种实现方式采用了类加载的懒加载机制来保证单例只在第一次使用时被创建。 实现代码 public class Singleton {private s…...
Mybatis-Plus05(分页插件)
分页插件 MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能 1. 添加配置类 Configuration MapperScan("com.atguigu.mybatisplus.mapper") //可以将主类中的注解移到此处 public class MybatisPlusConfig {Bean public MybatisPlusIntercepto…...
python爬取B站视频
参考:https://cloud.tencent.com/developer/article/1768680 参考的代码有点问题,请求头需要修改,上代码: import requests import re # 正则表达式 import pprint import json from moviepy.editor import AudioFileClip, Vid…...
深度学习500问——Chapter05: 卷积神经网络(CNN)(2)
文章目录 5.6 有哪些池化方法 5.7 1x1卷积作用 5.8 卷积层和池化层有什么区别 5.9 卷积核是否一定越大越好 5.10 每层卷积是否只能用一种尺寸的卷积核 5.11 怎样才能减少卷积层参数量 5.12 在进行卷积操作时,必须同时考虑通道和区域吗 5.13 采用宽卷积的好处有什么 …...
基于单片机的测时仪系统设计
**单片机设计介绍,基于单片机的测时仪系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的测时仪系统设计是一个结合了单片机技术与测时技术的综合性项目。该设计的目标是创建一款精度高、稳定性强且…...
鸿蒙原生应用开发-网络管理Socket连接(三)
应用通过TLS Socket进行加密数据传输 开发步骤 客户端TLS Socket流程: 1.import需要的socket模块。 2.绑定服务器IP和端口号。 3.双向认证上传客户端CA证书及数字证书;单向认证只上传CA证书,无需上传客户端证书。 4.创建一个TLSSocket连接…...
【Java EE】关于Maven
文章目录 🎍什么是Maven🌴为什么要学Maven🌲创建⼀个Maven项目🌳Maven核心功能🌸项目构建🌸依赖管理 🍀Maven Help插件🎄Maven 仓库🌸本地仓库🌸私服 ⭕总结 …...
每日一题:C语言经典例题之反转数
题目描述 给定一个整数,请将该数各个数位上的数字反转得到一个新数。新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零。 题目描述 给定一个整数,请将该数各个数位上的数字反转得到一个…...
RESTfull接口访问Elasticsearch
【数据库的健康值】 curl -X GET "ip:9200/_cat/health" 【查看所有索引】 curl -X GET "ip:9200/_cat/indices?v" 【查看索引index_name】 curl -X GET "ip:9200/索引?pretty" 【创建索引/文档】 PUT "ip:9200/索引/文档id" {请…...
NoSQL之Redis
目录 一、关系型数据库与非关系型数据库 1.关系数据库 2.非关系数据库 2.1非关系型数据库产生背景 3.关系型数据库与非关系型数据区别 (1)数据存储方式不同 (2)扩展方式不同 (3)对事物性的支持不同 …...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
在Zenodo下载文件 用到googlecolab googledrive
方法:Figshare/Zenodo上的数据/文件下载不下来?尝试利用Google Colab :https://zhuanlan.zhihu.com/p/1898503078782674027 参考: 通过Colab&谷歌云下载Figshare数据,超级实用!!࿰…...
网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...
