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

目录

💣一、准备工作

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

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


手雷都加了在给狗剩加个火箭筒不过分吧。效果看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


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于STC12C5A60S2系列1T 8051单片机的LCD1602显示中文英文数字小数字库字符自定义字符的应用

基于STC12C5A60S2系列1T 8051单片机的LCD1602显示中文英文数字小数字库字符自定义字符的应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍LCD1602字符型液晶显示器介…

策略模式:灵活调整算法的设计精髓

在软件开发中&#xff0c;策略模式是一种行为型设计模式&#xff0c;它允许在运行时选择算法的行为。通过定义一系列算法&#xff0c;并将每个算法封装起来&#xff0c;策略模式使得算法可以互换使用&#xff0c;这使得算法可以独立于使用它们的客户。本文将详细介绍策略模式的…

算法——栈

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享关于栈相关的算法 如果有不足的或者错误的请您指出! 目录 1.删除字符中的所有相邻重复项1.1解析1.2题解 2.比较含退格的字符串2.1解析2.2题解 3.基本计算器II3.1解析3.2题解 4.…

清明美食制作|“心灵护航,增能培力”残疾人职业能力提升培养

为提高残疾人的动手能力&#xff0c;提升个人的自身素质和自主就业创业能力&#xff0c;弘扬中华民族传统文化&#xff0c;临近清明之际&#xff0c;淳安县从益舍社会工作服务中心于浪川乡展开了以“品尝春天味道 制作清明粿 清明美食制作”为主题的清明节活动。 【清明粿制作】…

【C语言__函数__复习篇1】

目录 前言&#xff1a; 一、C语言中函数的概念 二、库函数 2.1 库函数的概念 2.2 怎样自学库函数——以sqrt函数为例 三、自定义函数 3.1 自定义函数的概念 3.2 自定义函数的语法形式 3.3 函数的实参 3.4 函数的形参 3.5 实参与形参的关系 3.6 return语句 3.7 数组传参 …

O2OA开发平台如何查看数据表结构?

在访问后端api地址&#xff0c;页面最下方有列示平台的各个服务&#xff0c;点击进入可查看具体的表内容 后端api地址&#xff1a; http://{hostIP}/x_program_center/jest/list.html 其中&#xff1a;{hostIP}为中心服务器所在域名或者IP地址 如下图&#xff1a;

RA4000CE为汽车动力传动系统提供解决方案

目前汽车电气化的水平越来越高&#xff0c;其中比较显著的一个发展方向就是将发动机管理系统和自动变速器控制系统&#xff0c;集成为动力传动系统的综合控制(PCM)。作为汽车动力的核心部件&#xff0c;通过电子系统的运用&#xff0c;将外部多个传感器和执行环节的数据进行统一…

Go 自定义14位时间类型 yyyyMMddHHmmss

目录 功能 代码 功能 数据库或者接口时间类型&#xff0c;经常会使用14位的时间格式。每次都转换有点麻烦。可以自定义一个时间类型。 自定义类型需要实现json接口中的MarshalJSON与UnmarshalJSON两个函数&#xff0c;这样在做json编码解码时就会自动转为14位的时间格式了。…

基于flutter3.x+window_manager+getx桌面端仿macOS系统

flutter3_macui桌面端仿macOS系统实战项目完结啦&#xff01; 原创研发flutter3.19dart3.3window_managergetx等技术构建桌面版macOS系统。支持自定义毛玻璃虚化背景、Dock菜单多级嵌套自由拖拽排序、可拖拽弹窗等功能。 支持macOS和windows11两种风格。 使用技术 编辑器&…

【c++】优先级队列|反向迭代器(vector|list)

优先级队列的常用函数的使用 #include<iostream> #include<queue> using namespace std;int main() {priority_queue<int>st;st.push(1);st.push(7);st.push(5);st.push(2);st.push(3);st.push(9);while (!st.empty()){cout << st.top() << &qu…

【vue】watch 侦听器

watch&#xff1a;可监听值的变化&#xff0c;旧值和新值 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

openstack之neutron介绍

核心组件 neutron-server&#xff1a;提供API接口&#xff0c;把对应的api请求传给plugin进&#xff1b; neutron-plugin&#xff1a;管理逻辑网络状态&#xff0c;调用agent&#xff1b; neutron-agent&#xff1a;在provider network上创建网络对象&#xff1b; neutron-…

【Vue】实现仿微信输入@出现选择框

<div style"padding: 10px 10px" class"editor"><el-inputresizetype"textarea":rows"4"clearableplaceholder"请输入您的问题.."v-model"requestParams.prompt"input"handleInput"keydown.na…

C# WinForm —— 项目目录结构

1. WinForm 应用程序项目 Properties&#xff1a;属性文件夹存放了一个自动生成的类文件AssemblyInfo.cs&#xff0c;保存了一些应用程序集的一些信息引用存放了一些为应用程序提供所需的&#xff0c;某些功能的一些程序集&#xff08;dll文件&#xff09;等添加引用&#xff…

Html网页小游戏源代码

Html网页小游戏源代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Jello Jumping Game</title><meta name"viewport" content"widthdevice-width, initial-scale1"&…

【安全】挖矿木马自助清理手册

一、什么是挖矿木马 挖矿木马会占用CPU进行超频运算&#xff0c;从而占用主机大量的CPU资源&#xff0c;严重影响服务器上的其他应用的正常运行。黑客为了得到更多的算力资源&#xff0c;一般都会对全网进行无差别扫描&#xff0c;同时利用SSH爆破和漏洞利用等手段攻击主机。 …

【AR】使用深度API实现虚实遮挡

遮挡效果 本段描述摘自 https://developers.google.cn/ar/develop/depth 遮挡是深度API的应用之一。 遮挡&#xff08;即准确渲染虚拟物体在现实物体后面&#xff09;对于沉浸式 AR 体验至关重要。 参考下图&#xff0c;假设场景中有一个Andy&#xff0c;用户可能需要放置在包含…

2024年蓝桥杯40天打卡总结

2024蓝桥杯40天打卡总结 真题题解其它预估考点重点复习考点时间复杂度前缀和二分的两个模板字符串相关 String和StringBuilderArrayList HashSet HashMap相关蓝桥杯Java常用算法大数类BigInteger的存储与运算日期相关考点及函数质数最小公倍数和最大公约数排序库的使用栈Math类…

牛客周赛 Round 39(A,B,C,D,E,F,G)

比赛链接 官方题解&#xff08;视频&#xff09; B题是个贪心。CD用同余最短路&#xff0c;预处理的完全背包&#xff0c;多重背包都能做&#xff0c;比较典型。E是个诈骗&#xff0c;暴力就完事了。F是个线段树。G是个分类大讨论&#xff0c;出题人钦定的本年度最佳最粪 题目…

14届蓝桥杯 C/C++ B组 T6 岛屿个数 (BFS,FloodFill,填色)

首先拿到这道题不要想着去直接判断环里面的岛屿&#xff0c;这样太困难了&#xff0c;我们可以使用之前做过的题的经验&#xff0c;在输入加入一圈海水&#xff0c;然后从(0,0)点开始BFS&#xff0c;这里进行八向搜索&#xff0c;搜到的0全部都染色成2&#xff0c;假如2能够蔓延…