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

发布于:2024-04-16 ⋅ 阅读:(39) ⋅ 点赞:(0)

目录

💣一、准备工作

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

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


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



网站公告

今日签到

点亮在社区的每一天
去签到