游戏开发之Unity学习(十一)——多人游戏与网络

unity3d网络游戏开发API

从 Unity 5.0 开始,提供了全新的 UNet 开发网络游戏,面向两种类型的用户:

  • 使用 Unity 开发简单多人游戏,应该从高阶 API 开始
    1. 使用 “NetworkManager” 管理网络,控制游戏对象网络状态
    2. 从客户端调用服务器函数 或 从服务器调用客户端函数
    3. 使用网络组件,可视化编辑程序
    4. nternet 服务支持
  • 用户自定义网络基础设施或高级多人游戏,应该从 NetworkTransport API 开始
    1. 使用 UDP 等
    2. 自建复杂的网络结构

本篇博客使用的是高级API。

演示视频地址

unity3d开发网络多人游戏

  1. 新建 NetworkManager对象:
    • 首先创建一个空对象,将其命名为NetworkManager;
    • 为该对象添加组件:NetworkManager,NetworkManagerHUB。
  2. 制作玩家预制:
    • 本次实验使用的是巡逻兵那篇博客的人物素材,需要删除玩家预制下的摄像机,命名为player;
    • 为玩家预制添加组件:NetworkIdentity(Local Player Authority需要设置为true,使客户端可以控制玩家),NetworkTransform(为服务器提供玩家位置等信息)。
  3. 注册玩家预制:
    将玩家预制拖入NetworkManager的swap info的Player Prefab插槽。
  4. 注册子弹预制:
    • 新建球体对象,命名为Bullet,scale设置为0.2;
    • 给子弹rigidbody组件,取消重力;
    • 添加新脚本bullet.cs,bullet.cs用来处理子弹的碰撞事件;
    • 用 Add 按钮添加一个新的 spawn 预制件,将 Bullet 预制件拖入新的 spawn 预制插槽。
  5. 玩家控制脚本:
    • 新建名为Network.cs的玩家控制脚本;
    • Network.cs脚本中,控制玩家的移动和攻击,控制摄像机跟随。
    • 新建Combat.cs,改脚本控制玩家血条值;
  6. 添加场景控制:
    新建FirstSceneController.cs,该脚本加载摄像机和地图;

各cs文件代码:

/* *
 * Network.cs
 * 该脚本中控制玩家移动、攻击,控制摄像机跟随
 * */

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

public class Network : NetworkBehaviour {
    public GameObject bulletPrefab;
    public Color color = Color.red;
    private float speed = 3;
    private float rspeed = 90;
    private Camera myCamera;

    public override void OnStartLocalPlayer()
    {
        color = Color.green;
        myCamera = Camera.main;
        gameObject.GetComponent<Rigidbody>().freezeRotation = true;
    }
    // Update is called once per frame
    void Update () {
        if(isLocalPlayer)
        {
            float translationX = Input.GetAxis("Horizontal");
            float translationZ = Input.GetAxis("Vertical");
            if (translationX != 0 || translationZ != 0)
            {
                gameObject.GetComponent<Animator>().SetBool("running", true);
            }
            else
            {
                gameObject.GetComponent<Animator>().SetBool("running", false);
            }
            gameObject.transform.Translate(translationX * speed * Time.deltaTime * 0.1f, 0, translationZ * speed * Time.deltaTime);
            gameObject.transform.Rotate(0, translationX * rspeed * Time.deltaTime, 0);
            if (gameObject.transform.localEulerAngles.x != 0 || gameObject.transform.localEulerAngles.z != 0)
            {
                gameObject.transform.localEulerAngles = new Vector3(0, gameObject.transform.localEulerAngles.y, 0);
            }
            if (gameObject.transform.position.y != 0)
            {
                gameObject.transform.position = new Vector3(gameObject.transform.position.x, 0, gameObject.transform.position.z);
            }
            myCamera.transform.position = transform.position + transform.forward * -3 + new Vector3(0, 4, 0);
            myCamera.transform.forward = transform.forward + new Vector3(0, -0.5f, 0);
            if (Input.GetKeyDown(KeyCode.Space))
            {
                gameObject.GetComponent<Animator>().SetBool("shoot", true);
                CmdFire();
                gameObject.GetComponent<Animator>().SetBool("shoot", false);
            }
        }
    }
    [Command]
    void CmdFire()
    {
        // This [Command] code is run on the server!

        // create the bullet object locally
        var bullet = (GameObject)Instantiate(bulletPrefab,transform.position + transform.forward + new Vector3(0,1,0),Quaternion.identity);

        bullet.GetComponent<Rigidbody>().velocity = transform.forward * 4;

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

        // when the bullet is destroyed on the server it will automaticaly be destroyed on clients
        Destroy(bullet, 2.0f);
    }
}
/***
 * Bullet.cs
 * 该脚本处理子弹的碰撞
 * */

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

public class Bullet : MonoBehaviour {
    void OnCollisionEnter(Collision collision)
    {
        var hit = collision.gameObject;
        var hitPlayer = hit.GetComponent<Network>();

        if (hitPlayer != null)
        {
            var combat = hit.GetComponent<Combat>();
            combat.TakeDamage(30);
        }
        Destroy(gameObject);
    }
}
/***
 * Combat.cs
 * 该脚本控制人物血量和人物死亡的重生
 * */

using UnityEngine;
using UnityEngine.Networking;

public class Combat : NetworkBehaviour
{
    public const int maxHealth = 100;
    [SyncVar]
    public int health = maxHealth;

    public void TakeDamage(int amount)
    {
        if (!isServer)
            return;

        health -= amount;
        if (health <= 0)
        {
            health = 100;
            GetComponent<Animator>().SetBool("death", true);
            GetComponent<Animator>().SetBool("death", false);
            RpcRespawn();
        }
    }

    [ClientRpc]
    void RpcRespawn()
    {
        if (isLocalPlayer)
        {
            // move back to zero location
            transform.position = Vector3.zero;
        }
    }
}
/***
 * HealthBar.cs
 * 该脚本用于控制玩家血条显示,区分敌我
 * */

using UnityEngine;
using System.Collections;

public class HealthBar : MonoBehaviour
{
    GUIStyle healthStyle;
    GUIStyle backStyle;
    Combat combat;
    Color barColor;

    private void Start()
    {
        combat = GetComponent<Combat>();
        barColor = GetComponent<Network>().color;
    }

    void OnGUI()
    {
        InitStyles();

        // Draw a Health Bar

        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);

        // draw health bar background
        GUI.color = Color.grey;
        GUI.backgroundColor = Color.grey;
        GUI.Box(new Rect(pos.x - 26, Screen.height - pos.y + 20, Combat.maxHealth / 2, 7), ".", backStyle);

        // draw health bar amount
        GUI.color = color;
        GUI.backgroundColor = color;
        GUI.Box(new Rect(pos.x - 25, Screen.height - pos.y + 21, combat.health / 2, 5), ".", healthStyle);
    }

    void InitStyles()
    {
        if (healthStyle == null)
        {
            healthStyle = new GUIStyle(GUI.skin.box);
            healthStyle.normal.background = MakeTex(2, 2, color);
        }

        if (backStyle == null)
        {
            backStyle = new GUIStyle(GUI.skin.box);
            backStyle.normal.background = MakeTex(2, 2, new Color(0f, 0f, 0f, 1.0f));
        }
    }

    Texture2D MakeTex(int width, int height, Color col)
    {
        Color[] pix = new Color[width * height];
        for (int i = 0; i < pix.Length; ++i)
        {
            pix[i] = col;
        }
        Texture2D result = new Texture2D(width, height);
        result.SetPixels(pix);
        result.Apply();
        return result;
    }
}

更多内容请戳:传送门

猜你喜欢

转载自blog.csdn.net/JC2474223242/article/details/80821342