Unity Netcode如何实现网络射击

最近在准备《虚拟现实》这门课的期末作业,用Unity 3D实现一个课设,因为我和组员做的是基于Unity.Netcode的联网射击第三人称游戏,所以遇到了这个问题,小编也是忙活了2个星期才得以解决,特此分享哦

---------------------------------------------------------------------------------------------------------------------------------

参考了B站大佬的思路,【Unity联网游戏教程】创建服务器端子弹_哔哩哔哩_bilibili

不过他做的是2D游戏,我的是3D,整体思路就是

1.做两个子弹的变体

2.将这两个子弹变体运用起来

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using System;

public class BulletLaunch : NetworkBehaviour
{
    
    [SerializeField] private GameObject serverBullet;
    [SerializeField] private GameObject clientBullet;
    [SerializeField] private Transform BulletSpawn;
    [SerializeField] private float BulletSpeed=20;
    // Start is called before the first frame update
    public AudioClip clip;
    //关联换子弹音效
    public AudioClip check;

    
    // 子弹个数
    private int bulletCount = 10;

    //声音
    private AudioSource Gunplayer;
   
    void Start()
    {
        Gunplayer = GetComponent<AudioSource>();
        
    }

    // Update is called once per frame
    void Update()
    {
        
        if(Input.GetKeyDown(KeyCode.Mouse0) && bulletCount > 0)
        {
           if(IsLocalPlayer)
           {
                clientFire();
                bulletCount --;
                Gunplayer.PlayOneShot(clip);
                if (bulletCount == 0)
                {
                    
                    Gunplayer.PlayOneShot(check);
                    Invoke("Reload", 1.5f);
                }
                
            

                if(Input.GetKeyDown(KeyCode.R))
                {
                    
                    Gunplayer.PlayOneShot(check);
                    Invoke("Reload",1.5f);
                }
           }
        }
    }

    [ClientRpc]
    private void clientFireClientRpc(Vector3 Bposition, Quaternion Brotation)
    {
        GameObject ctemp = Instantiate(clientBullet,Bposition, Brotation);
        ctemp.GetComponent<Rigidbody>().velocity = ctemp.transform.forward *BulletSpeed; // 速度
       
    }
    
    [ServerRpc]
    private void FireServerRpc(Vector3 Bposition, Quaternion Brotation)
    {
        GameObject temp = Instantiate(serverBullet,Bposition, Brotation);
        temp.GetComponent<Rigidbody>().velocity = temp.transform.forward *BulletSpeed; // 速度

        clientFireClientRpc(Bposition,Brotation);  // 通知
    }

    private void clientFire()
    {
        
        if(IsServer){
           //客户端生成假子弹
            GameObject stemp = Instantiate(serverBullet,BulletSpawn.transform.position, BulletSpawn.transform.rotation);
            stemp.GetComponent<Rigidbody>().velocity = stemp.transform.forward * BulletSpeed; // 速度
            clientFireClientRpc(BulletSpawn.transform.position, BulletSpawn.transform.rotation);  // 通知
        }
        else{
        
            GameObject ctemp = Instantiate(clientBullet,BulletSpawn.transform.position, BulletSpawn.transform.rotation);
            ctemp.GetComponent<Rigidbody>().velocity = ctemp.transform.forward * BulletSpeed; // 速度

            //请求服务端生成子弹
            FireServerRpc(BulletSpawn.transform.position, BulletSpawn.transform.rotation);
        }

        

    }

     void Reload()
    {
        bulletCount=10;
    }
}

3.然后再给玩家添加一个受到伤害的脚本

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

public class DamageToPlayer : MonoBehaviour
{
    [SerializeField] private int damage = 20;

    private void OnTriggerEnter(Collider coll)
    {
        if (coll.tag == "Player")
        {
            //如果子弹碰撞到的是玩家
            //那就获取被碰撞玩家的health组件
            if(coll.attachedRigidbody.TryGetComponent<playerHealth>(out playerHealth health))
            {
                health.TakeDamage(damage);
                Destroy(this);
            }
        }
        
    }
}

4.给玩家添加的生命值脚本需要网络变量来实现,他会自动更新在服务器的,这样当玩家生命值为

0 的时候,大家都知道,便于后面的逻辑

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using TMPro;

public class playerHealth : NetworkBehaviour
{
    [field: SerializeField] public int MaxHealth { get; private set; } = 100;
    public NetworkVariable<int> CurrentHealth = new NetworkVariable<int>();
    public NetworkVariable<bool> IsDead = new NetworkVariable<bool>(); // 同步玩家是否死亡状态

    [SerializeField] private TextMeshProUGUI textField;
    Animator _selfAnim; // 获取动画

    public override void OnNetworkSpawn()
    {
        if (!IsServer) return;
        CurrentHealth.Value = MaxHealth;
        IsDead.Value = false; // 初始化时玩家不死亡
        _selfAnim = GetComponent<Animator>(); // 获取动画
    }

    public void TakeDamage(int damage)
    {
        ModifyHealth(-damage);
    }

    public void RestoreHealth(int damage)
    {
        ModifyHealth(damage);
    }

    public void ModifyHealth(int value)
    {
        if (IsDead.Value) {
            
            _selfAnim.SetTrigger("isdead"); // 死亡动画
            
            return;
        }
        var newHealth = CurrentHealth.Value + value;
        CurrentHealth.Value = Mathf.Clamp(newHealth, 0, MaxHealth);

        if (CurrentHealth.Value == 0)
        {
            IsDead.Value = true; // 更新玩家死亡状态
        }
    }

    void Update()
    {
        // 根据玩家死亡状态更新 TextMeshPro 组件的显示
        textField.enabled = IsDead.Value;
    }
}

结尾:只要大家不放弃,有问题都能解决的,加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值