Unity之PUN实现多人联机射击游戏的优化(Section 3)

news2024/11/27 21:55:48

目录

💣一、准备工作

💣二、生成弹头脚本的编写

💣三、实现发射和伤害同步 


手雷都加了在给狗剩加个火箭筒不过分吧。效果看GIF动图,分别是单机和联机的效果。

添加火箭筒依旧是在原有的基础上更改,我查看火箭筒模型的时候资源里把关于弹头爆炸的脚本也都实现好了。实现了手雷的同步功能后再去写火箭筒就感觉简单多了。


 一、准备工作

先在素材中找到火箭筒模型,名字是 Rocket_Launcher_01

弹头的模型,名称是 Rocket_Launcher_01_Projectile 。把碰撞组件和刚体组件加好,并且把弹头和爆炸特效的标签设置为 “Boom”,用来做伤害检测,和手雷的伤害检测共用一套逻辑。

把火箭筒装到玩家 Player 模型上,我们通过武器组件的激活来实现武器切换的效果。

这里是单个武器组件的切换,如果武器多的话就把所有武器放进一个数组里,通过数组下标进行切换。

二、生成弹头脚本的编写

我把前边的手雷脚本单独拎出来了,handGrenade,然后把手持类武器放进了同一个脚本中用于归类。

public class handGrenade : MonoBehaviour
{
    //手雷
    public GameObject handGrenadePrefab;
    //手雷生成点
    public Transform handGrenadeTf;
    
    void Start()
    {
        
    }
    
    public void AttGrenade()
    {
        //实例化一个手雷
        GameObject handGrenadeObj = Instantiate(handGrenadePrefab,handGrenadeTf.transform.position,handGrenadeTf.transform.rotation);
        handGrenadeObj.GetComponent<Rigidbody>().AddForce(transform.forward * 1,ForceMode.Impulse);  //投掷速度   让中心点跟枪口位置可自行调整摄像机的偏移值
    }

Gun 脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//枪的脚本
public class Gun : MonoBehaviour
{

    public int BulletCount = 15;

    public GameObject bulletPrefab;
    public GameObject casingPreafab;

    public Transform bulletTf;
    public Transform casingTf;
    
    //火箭筒弹药数量
    public int RocketBulletCount = 1;

    //弹头预设体
    public GameObject rocketBulletPrefab;

    //火箭筒发射点
    public Transform RocketBulletTf;
    
    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 RocketAttack()
    {
        //实例化一个火箭筒弹头
        GameObject bulletObj = Instantiate(rocketBulletPrefab);
        bulletObj.transform.position = RocketBulletTf.transform.position;
        bulletObj.GetComponent<Rigidbody>().AddForce(transform.forward * 300, ForceMode.Impulse);  //子弹速度   让中心点跟枪口位置可自行调整摄像机的偏移值
    }
    
}

三、实现发射和伤害同步 

PlayerController 脚本中我们要做的事:

  • 实现武器的切换
  • 生成弹头的同步
  • 实现伤害同步 
  • 换弹药的逻辑(枪换弹药和火箭筒换弹药)

换枪的动画暂时就先用换弹的动画代替了。


下面代码有些和之前是重复的,不过火箭筒都用到这些的 

伤害、得分和爆炸范围(爆炸范围是修改爆炸特效的半径)大家可以自己调整,我这里火箭筒和手雷的伤害检测得分共用同一个逻辑 —— 都是爆炸伤害。

//角色控制器 
public class PlayerController : MonoBehaviourPun,IPunObservable
{
   public Gun gun; //枪的脚本

   public handGrenade HandGrenade; //手雷的脚本

   //装载火箭筒、枪的预设体
   public GameObject RocketObject;
   public GameObject GunObject;
   //目标变量用来切换武器,1为枪  0为火箭筒
   int RocketFlag = 1;


    void Start()
    {
        gun = GetComponentInChildren<Gun>();
        HandGrenade = GetComponentInChildren<handGrenade>();
    }

    void Update()
    {
        //Debug.Log(photonView.Owner.NickName);
        //判断是否是本机玩家  只能操作本机角色
        if (photonView.IsMine)
        {
            if (isDie == true)
            {
                return;
            }
            UpdatePosition();
            UpdateRotation();
            InputCtl();
        }
        else
        {
            UpdateLogic();
        }
    }


    //角色操作
    public void InputCtl()
    {
        switch (RocketFlag)
        {
            case 0:
                //火箭筒
                if (Input.GetMouseButtonDown(0))
                {
                    //判断子弹个数
                    if (gun.RocketBulletCount > 0)
                    {
                        //如果正在播放填充子弹的动作不能开枪
                        if (ani.GetCurrentAnimatorStateInfo(1).IsName("Reload"))
                        {
                            return;
                        }
                        RocketShell.SetActive(false);
                        gun.RocketBulletCount--;
                        Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.RocketBulletCount);
                        //播放开火动画
                        ani.Play("Fire", 1, 0);

                        StopAllCoroutines();
                        StartCoroutine(RocketAttack());
                    }
                }
                //火箭筒
                if (Input.GetKeyDown(KeyCode.R))
                {
                    //填充子弹
                    AudioSource.PlayClipAtPoint(reloadClip, transform.position); //播放填充子弹的声音
                    ani.Play("Reload");
                    RocketShell.SetActive(true);
                    gun.RocketBulletCount = 1;
                    Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.RocketBulletCount);
                }
                break;
            case 1:
                if (Input.GetMouseButtonDown(0))
                {
                    //判断子弹个数
                    if (gun.BulletCount > 0)
                    {
                        //如果正在播放填充子弹的动作不能开枪
                        if (ani.GetCurrentAnimatorStateInfo(1).IsName("Reload"))
                        {
                            return;
                        }
        
                        gun.BulletCount--;
                        Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.BulletCount);
                        //播放开火动画
                        ani.Play("Fire", 1, 0);
        
                        StopAllCoroutines();
                        StartCoroutine(AttackCo());
                    }
                }
                if (Input.GetKeyDown(KeyCode.R))
                {
                    //填充子弹
                    AudioSource.PlayClipAtPoint(reloadClip, transform.position); //播放填充子弹的声音
                    ani.Play("Reload");
                    gun.BulletCount = 15;
                    Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.BulletCount);
                }
                break;
            default:
                Debug.Log("------------error");
                break;
        }

        //按ESC退出游戏
        // if (Input.GetKeyDown(KeyCode.Escape))
        // {
        //     Application.Quit();
        // }
        
        //持续按下按键,查看计分板
        if (Input.GetKey(KeyCode.Tab))
        {
            Game.uiManager.ShowUI<ScoreboardUI>("ScoreboardUI");
            Game.uiManager.ShowUI<ScoreboardUI>("ScoreboardUI").UpDateScore();
        }
        else if(Input.GetKeyUp(KeyCode.Tab))
        {
            Game.uiManager.CloseUI("ScoreboardUI");
        }

        if (Input.GetKeyDown(KeyCode.Q))
        {
            if (boolHandGrenade == false)
            {
                boolHandGrenade = true;
                //每隔5秒才可以扔一次
                Invoke("boolThrowHandGrenade", 5f);
                //播放投掷手雷动作动画
                ani.Play("Grenade_Throw");
                
                StopAllCoroutines();
                StartCoroutine(AttHandGrenade());
            }
        }
        
        //按E切换枪和火箭筒
        if (Input.GetKeyDown(KeyCode.E))
        {
            ani.Play("Reload");
            if (RocketFlag == 1)
            {
              RocketObject.SetActive(true);
              GunObject.SetActive(false);
              Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.RocketBulletCount);
              RocketFlag = 0;
            }
            else
            {
                RocketObject.SetActive(false);
                GunObject.SetActive(true);
                Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.BulletCount);
                RocketFlag = 1;
            }
        }
    }


    //火箭筒攻击协程
    IEnumerator RocketAttack()
    {
        //延迟0.1秒才发射子弹
        yield return new WaitForSeconds(0.1f);
        //播放射击音效
        AudioSource.PlayClipAtPoint(shootClip, transform.position);

        photonView.RPC("AttackRocketRpc", RpcTarget.All);  //所有玩家执行 AttackRpc 函数
    }
    
    //执行火箭筒同步
    [PunRPC]
    public void AttackRocketRpc()
    {
        gun.RocketAttack();
    }

    //监听发生碰撞: 只监听发生碰撞的一瞬间 —— 火箭筒和手雷共用
    private void OnCollisionEnter(Collision collision)  //参数 collision 就是你碰撞到的物体的碰撞信息
    {
        //给地面一个图层"Ground"   collision.collider.tag == "Ground"   可以判断物体是否踩在地面上
        if (collision.collider.tag == "Boom")
        {
            GetHit(localPlayer,3,2);
        }
    }


   //同步所有角色受伤: 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);
    }
}

缺点:火箭筒弹道很偏,可能和人物模型的呼吸晃动有关,小弟暂时无能为力。日后改进

祝大家周五愉快,拜拜┏(^0^)┛ 


狗剩的成长日记:

Unity之PUN2插件实现多人联机射击游戏_unity pun2-CSDN博客文章浏览阅读1.5k次,点赞21次,收藏29次。周五的下午永远要比周六幸福,周五好啊大家有在认真摸鱼吗。前两天我突发奇想想做联机游戏,就去找教程,肝了一天终于做出来了。先说一下搜寻资料过程中找到的实现游戏联机暂时就记录了这11个,做的这个实例是通过PUN2实现的,先看一下效果:个人感觉这套模型和这个教程泰裤辣,能跟着做完这个游戏Demo也是很开心的,下面依然以博客的形式记录实现这个游戏的过程。_unity pun2https://blog.csdn.net/qq_48512649/article/details/136249522Unity之PUN实现多人联机射击游戏的优化(Section 1)_unity pun2 角色名称-CSDN博客文章浏览阅读1.5k次,点赞24次,收藏29次。关于优化了哪几个小点:点击开始游戏玩家可以输入自己的昵称;进入到房间后玩家对应的昵称也会同步显示到房间列表上;和朋友一起玩的时候他说会卡进房间的模型里建议我加上跳跃功能,我就给加上了,顺便加了一个按住Shift和方向键进行加速跑;同时按住Tab键会显示出计分板,这个计分板是按照射击命中次数来计分的。_unity pun2 角色名称https://blog.csdn.net/qq_48512649/article/details/136615629Unity之PUN实现多人联机射击游戏的优化(Section 2)_unity photon 多人射击游戏-CSDN博客文章浏览阅读1k次,点赞21次,收藏34次。这几周都给我布置任务了,最近可忙。今天就来兑现诺言:有天我查看这个游戏包的资源,居然发现了手雷和其他很多武器,而且手雷的爆炸脚本是写好的,那就试着加一个手雷功能。看一下效果手雷爆炸的原理呢就像小编之前写的物理系统里面的小实例一样:Unity之物理系统_unity 物理系统-CSDN博客专栏的上一篇角色控制器控制角色移动跳崖,这一篇来说说Unity的物理系统。本篇小编还要带大家做一个碰撞检测效果实例,先放效果图:流星撞击地面产生爆炸效果。_unity 物理系统。_unity photon 多人射击游戏https://blog.csdn.net/qq_48512649/article/details/137267066


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1590441.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能测试-数据库优化二(SQL的优化、数据库拆表、分表分区,读写分离、redis)

数据库优化 explain select 重点&#xff1a; type类型&#xff0c;rows行数&#xff0c;extra SQL的优化 在写on语句时&#xff0c;将数据量小的表放左边&#xff0c;大表写右边where后面的条件尽可能用索引字段&#xff0c;复合索引时&#xff0c;最好按复合索引顺序写wh…

如何解决Uniapp更新数据不重新渲染组件

办法就是在修改数据的函数里面&#xff0c;用let thatthis&#xff0c;再给that用赋值。 原因是给数据赋值的函数没用箭头函数&#xff0c;this是函数自己的this。比如success&#xff08;res&#xff09;{} 或者用箭头函数&#xff0c;比如success&#xff08;res&#xff0…

2024年mathorcup数学建模C题思路分析-物流网络分拣中心货量预测及人员排班

# 1 赛题 C 题 物流网络分拣中心货量预测及人员排班 电商物流网络在订单履约中由多个环节组成&#xff0c;图 ’ 是一个简化的物流 网络示意图。其中&#xff0c;分拣中心作为网络的中间环节&#xff0c;需要将包裹按照不同 流向进行分拣并发往下一个场地&#xff0c;最终使包裹…

数学杂谈之四:学习数学的方法

数学杂谈之四&#xff1a;学习数学的方法 数学杂谈之一&#xff1a;数学的形态 https://blog.csdn.net/cnds123/article/details/137437208 数学杂谈之二&#xff1a;数学中的概念和理解 https://blog.csdn.net/cnds123/article/details/137500537 数学杂谈之三&#xff1a;…

【MVCC】深入浅出彻底理解MVCC

MVCC概述 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;即多版本并发控制。主要是为了提高数据库的并发性能而提供的&#xff0c;采用了不加锁的方式处理读-写并发冲突&#xff0c;确保了任何时刻的读操作都是非阻塞的。只需要很小的开销&#xff0c;就可以…

机器学习和深度学习 -- 李宏毅(笔记与个人理解)Day 13

Day13 Error surface is rugged…… Tips for training :Adaptive Learning Rate critical point is not the difficult Root mean Square --used in Adagrad 这里为啥是前面的g的和而不是直接只除以当前呢? 这种方法的目的是防止学习率在训练过程中快速衰减。如果只用当前的…

文心一言

文章目录 前言一、首页二、使用总结 前言 今天给大家带来百度的文心一言,它基于百度的文心大模型,是一种全新的生成式人工智能工具。 一、首页 首先要登录才能使用,左侧可以看到以前的聊天历史 3.5的目前免费用,但是4.0的就需要vip了 二、使用 首先在最下方文本框输入你想要搜…

PostgreSQL15 + PostGis + QGIS安装教程

目录 下载1、PostgreSQL安装1.1、环境变量配置 2、PostGIS安装2.1、安装插件 3、QGIS下载3.1、安装3.2、测试 下载 PostgreSQL15安装&#xff1a;下载地址 PostGIS安装&#xff1a;下载地址&#xff08;倒数第二个&#xff09; 1、PostgreSQL安装 下载安装包之后一直点下一步…

Redis从入门到精通(十五)Redis分布式缓存(三)Redis分片集群的搭建和原理分析

文章目录 前言5.4 分片集群5.4.1 搭建分片集群5.4.2 散列插槽5.4.3 集群伸缩5.4.3.1 需求分析5.4.3.2 创建新的Redis实例5.4.3.3 添加新节点到Redis集群5.4.3.4 转移插槽 5.4.4 故障转移5.4.4.1 自动故障转移5.4.4.2 手动故障转移 5.4.5 RedisTemplate 5.5 小结 前言 Redis分布…

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇8基于stm32的RFID校园门禁系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 -----------…

[Python图像识别] 五十二.水书图像识别 (2)基于机器学习的濒危水书古文字识别研究

该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。目前我进入第二阶段Python图像识别,该部分主要以目标检测、图像…

亚远景科技-ASPICE 4.0-HWE硬件过程的范围 The Technical Scope of HW process

ASPICE 4.0中的HWE process是电气和电子硬件的技术范畴&#xff0c;涵盖了硬件工程中的需求分析、设计和验证活动&#xff0c;但不包括以下活动&#xff1a; 1. 系统级工程过程。既不包括机电一体MECHATRONIC&#xff0c;也不包括ECU特定电子控制单元的开发。 2. 硬件采购过程…

Redis 与 MySQL 数据一致性问题

1. 什么是数据库与缓存一致性 数据一致性指的是&#xff1a; 缓存中存有数据&#xff0c;缓存的数据值 数据库中的值&#xff1b;缓存中没有该数据&#xff0c;数据库中的值 最新值。 反推缓存与数据库不一致&#xff1a; 缓存的数据值 ≠ 数据库中的值&#xff1b;缓存或…

什么是One-Class SVM

1. 简介 单类支持向量机&#xff0c;简称One-Class SVM(One-Class Support Vector Machine)&#xff0c;是一种用于异常检测的监督学习算法。其主要目标是找出数据集中的异常或罕见样本&#xff0c;而不需要大量的正常样本用于训练。这使其在处理高维数据和非常稀疏的异常检测问…

AutoCAD之DWF三维信息提取---linux编译篇

1. 权限 1.1 给文件添加执行权限 chmod x autogen.sh1.2.给当前文件下的所有文件改变为读写执行权限 chmod 777 * -R 2.环境安装 2.1安装automake 1.4.1 安装链接 安装中遇到的问题及解决 2.2安装autoconf 2.3 安装libtool 2.4 安装Cmake(CMake包含) cmake安装在cent…

GMSSL-通信

死磕GMSSL通信-C/C++系列(一) 最近再做国密通信的项目开发,以为国密也就简单的集成一个库就可以完事了,没想到能有这么多坑。遂写下文章,避免重复踩坑。以下国密通信的坑有以下场景 1、使用GMSSL guanzhi/GmSSL进行通信 2、使用加密套件SM2-WITH-SMS4-SM3 使用心得 ​…

影响小程序SSL证书收费标准的因素有哪些?

在当今互联网时代&#xff0c;移动应用发展日新月异&#xff0c;小程序逐渐成为广大企业和个人开发者的心仪之选。然而&#xff0c;伴随小程序的广泛应用&#xff0c;安全问题和用户信任显得尤为关键。为了确保小程序的信息传输安全&#xff0c;SSL证书成为了一项基础配置。那么…

【C++题解】1028 - 输入一个三位数,把个位和百位对调后输出

问题&#xff1a;1028 - 输入一个三位数&#xff0c;把个位和百位对调后输出 类型&#xff1a;基础问题 题目描述&#xff1a; 输入一个三位自然数&#xff0c;然后把这个数的百位数与个位数对调&#xff0c;输出对调后的数。 输入&#xff1a; 输入一行&#xff0c;只有一…

独一无二:探索单例模式在现代编程中的奥秘与实践

设计模式在软件开发中扮演着至关重要的角色&#xff0c;它们是解决特定问题的经典方法。在众多设计模式中&#xff0c;单例模式因其独特的应用场景和简洁的实现而广受欢迎。本文将从多个角度详细介绍单例模式&#xff0c;帮助你理解它的定义、实现、应用以及潜在的限制。 1. 什…

C++格式化输出开源库fmt入手教程

fmt项目快速上手指南 1. cmake环境配置 include(FetchContent) FetchContent_Declare(fmtGIT_REPOSITORY https://github.com/fmtlib/fmtGIT_TAG 10.0.0GIT_SHALLOW TRUE) # 1. 下载fmt库 FetchContent_MakeAvailable(fmt)add_executable(fmt_guide main.cpp) # 2. 链接fmt库…