Unity3D学习笔记(10) 多人游戏与网络

width="640" height="363" src="https://v.qq.com/iframe/player.html?vid=j07028fza9c&tiny=0&auto=0" allowfullscreen="">

用Unet改造Tanks! Tutorial

设计

第一步是在项目中创建 NetworkManager 对象,Game Object -> Create Empty,添加NetworkManager组件来管理游戏的网络状态,添加NetworkManagerHUD组件得到了控制网络状态的用户界面。

给坦克预制加入相机作为子对象,并先在组件面板将相机对象的勾选取消使其失效。

在坦克预制加上NetworkIdentity组件,用于标识服务器和客户端之间的对象,将 NetworkIdentity 上的 “Local Player Authority” 复选框设置为 true允许客户端控制玩家对象的移动,加上NetworkTransform组件使对象在网络中同步它的位置。

在NetworkManager的NetworkManager组件面板打开 “Spawn Info” 折叠找到 “Player Prefab” 插槽,将坦克预制件拖入。

给坦克移动代码加上using UnityEngine.Networking;,将MonoBehaviour更改为NetworkBehaviour,在Update()中加入

if (!isLocalPlayer)
    return;

以便只有本地程序处理输入。添加

public override void OnStartLocalPlayer()
        {
            // Get all of the renderers of the tank.
            MeshRenderer[] renderers = GetComponentsInChildren<MeshRenderer> ();

            // Go through all the renderers...
            for (int i = 0; i < renderers.Length; i++)
            {
                // ... set their material color to the color specific to this tank.
                renderers[i].material.color = Color.red;
            }

            playerCamera.SetActive (true);
        }

识别玩家使本地玩家变红并使玩家自己的相机生效。

给子弹预制加上NetworkIdentity组件和NetworkTransform组件,将NetworkTransform组件将发送速率设置为零。子弹在射击后不会改变方向或速度,因此不需要发送移动更新。

在NetworkManager的NetworkManager组件面板打开 “Spawn Info” 折叠用 Add 按钮添加一个新的spawn预制件将子弹预制拖入。

改写坦克射击代码。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;

namespace Complete
{
    public class TankShooting : NetworkBehaviour
    {
        ...
        public GameObject m_Shell;                   // Prefab of the shell.
        ...
        private void Update ()
        {
            if (!isLocalPlayer)
                return;

            // The slider should have a default value of the minimum launch force.
            m_AimSlider.value = m_MinLaunchForce;

            // If the max force has been exceeded and the shell hasn't yet been launched...
            if (m_CurrentLaunchForce >= m_MaxLaunchForce && !m_Fired)
            {
                // ... use the max force and launch the shell.
                m_CurrentLaunchForce = m_MaxLaunchForce;
                CmdFire ();
            }
            // Otherwise, if the fire button has just started being pressed...
            else if (Input.GetButtonDown (m_FireButton))
            {
                // ... reset the fired flag and reset the launch force.
                m_Fired = false;
                m_CurrentLaunchForce = m_MinLaunchForce;

                // Change the clip to the charging clip and start it playing.
                m_ShootingAudio.clip = m_ChargingClip;
                m_ShootingAudio.Play ();
            }
            // Otherwise, if the fire button is being held and the shell hasn't been launched yet...
            else if (Input.GetButton (m_FireButton) && !m_Fired)
            {
                // Increment the launch force and update the slider.
                m_CurrentLaunchForce += m_ChargeSpeed * Time.deltaTime;

                m_AimSlider.value = m_CurrentLaunchForce;
            }
            // Otherwise, if the fire button is released and the shell hasn't been launched yet...
            else if (Input.GetButtonUp (m_FireButton) && !m_Fired)
            {
                // ... launch the shell.
                CmdFire ();
            }
        }

        [Command]
        private void CmdFire ()
        {
            // Set the fired flag so only Fire is only called once.
            m_Fired = true;

            // Create an instance of the shell and store a reference to it's rigidbody.
            GameObject shellInstance =
                Instantiate (m_Shell, m_FireTransform.position, m_FireTransform.rotation);

            // Set the shell's velocity to the launch force in the fire position's forward direction.
            shellInstance.GetComponent<Rigidbody>().velocity = m_CurrentLaunchForce * m_FireTransform.forward; 

            // Spawn the bullet on the clients.
            NetworkServer.Spawn (shellInstance);

            // When the bullet is destroyed on the server it will automaticaly be destroyed on clients.
            Destroy(shellInstance, 2.0f);

            // Change the clip to the firing clip and play it.
            m_ShootingAudio.clip = m_FireClip;
            m_ShootingAudio.Play ();

            // Reset the launch force.  This is a precaution in case of missing button events.
            m_CurrentLaunchForce = m_MinLaunchForce;
        }
    }
}

改写坦克健康代码。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;

namespace Complete
{
    public class TankHealth : NetworkBehaviour
    {
        ...
        [SyncVar]
        private float m_CurrentHealth;                      // How much health the tank currently has.

        public void TakeDamage (float amount)
        {
            if (!isServer)
                return;
            ...
            if (m_CurrentHealth <= 0f && !m_Dead)
            {
                RpcOnDeath ();
            }
        }

        private void Update ()
        {
            // Set the slider's value appropriately.
            m_Slider.value = m_CurrentHealth;

            // Interpolate the color of the bar between the choosen colours based on the current percentage of the starting health.
            m_FillImage.color = Color.Lerp (m_ZeroHealthColor, m_FullHealthColor, m_CurrentHealth / m_StartingHealth);
        }

        [ClientRpc]
        private void RpcOnDeath ()
        {
            // Set the flag so that this function is only called once.
            m_Dead = true;
            ...
            Destroy(gameObject);
        }
    }
}

相关代码

https://github.com/Ernie1/unity3d/tree/hw10/hw10/Assets/_Completed-Assets/Scripts/Tank

要点

  • [Command] :本地玩家对象执行的代码,调用服务器执行的函数
  • [ClientRpc] :服务器执行的代码,调用所有客户端执行函数
  • [SyncVar]:服务器授权变量,Spwan 自动同步到客户端

机制

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值