使用Multiplayer Networking做一个简单的多人游戏例子-1/3

使用Multiplayer Networking做一个简单的多人游戏例子-2/3

使用Multiplayer Networking做一个简单的多人游戏例子-3/3

上一篇中血条还没有同步到所有客户端,下面添加血条同步。主要用到[SyncVar]同步变量。

13. 网络同步血条

  • 打开Health脚本
  • 添加命名空间UnityEngine.Networking
using UnityEngine.Networking;
  • 添加继承关系为NetworkBehaviour
public class Health : NetworkBehaviour
  • 为currentHealth添加[SyncVar]
[SyncVar]
public int currentHealth = maxHealth;
  • 在TakeDamage函数中增加仅在Server端执行
if (!isServer)
{
    return;
}

最终Health脚本如下:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;

    [SyncVar]
    public int currentHealth = maxHealth;
    public RectTransform healthBar;

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

        currentHealth -= amount;
        if (currentHealth <= 0)
        {
            currentHealth = 0;
            Debug.Log("Dead!");
        }

        healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
    }
}

此时运行测试,你会发现只有客户端的血条会变化,所以我们需要修改血条变化方法

  • 打开Health脚本
  • 将血条修改的代码移到新函数OnChangeHealth中
void OnChangeHealth (int currentHealth)
{
    healthBar.sizeDelta = new Vector2(health, currentHealth.sizeDelta.y);
}
  • 修改currentHealth的SyncVar属性
[SyncVar(hook = "OnChangeHealth")]

最终Health代码:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;

    [SyncVar(hook = "OnChangeHealth")]
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

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

        currentHealth -= amount;
        if (currentHealth <= 0)
        {
            currentHealth = 0;
            Debug.Log("Dead!");
        }
    }

    void OnChangeHealth (int health)
    {
        healthBar.sizeDelta = new Vector2(health, healthBar.sizeDelta.y);
    }
}

14. 死亡和再出生

这里会用到[ClientRpc],让函数在服务端调用,执行却在客户端

  • 打开Health脚本
  • 添加出生函数Respawn
[ClientRpc]
void RpcRespawn()
{
    if (isLocalPlayer)
    {
        // move back to zero location
        transform.position = Vector3.zero;
    }
}
  • 修改TakeDamage函数中,currentHealth = maxHealth;
  • 在服务端执行RpcRespawn();

    最终Health代码如下:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;

    [SyncVar(hook = "OnChangeHealth")]
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

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

        currentHealth -= amount;
        if (currentHealth <= 0)
        {
            currentHealth = maxHealth;

            // called on the Server, but invoked on the Clients
            RpcRespawn();
        }
    }

    void OnChangeHealth (int currentHealth )
    {
        healthBar.sizeDelta = new Vector2(currentHealth , healthBar.sizeDelta.y);
    }

    [ClientRpc]
    void RpcRespawn()
    {
        if (isLocalPlayer)
        {
            // move back to zero location
            transform.position = Vector3.zero;
        }
    }
}
  • 保存脚本
  • Build新版本,测试

15. 增加敌人

增加敌人发射器用于创建系统玩家

  • 创建一个empty GameObject
  • 修改名称为“Enemy Spawner”
  • 保持Enemy Spawner选中
  • 添加组件Network > NetworkIdentity
  • 勾选NetworkIdentity中the Server Only选中,仅在服务端中执行
  • 给Enemy Spawner添加新脚本“EnemySpawner”

    EnemySpawner内容如下:
using UnityEngine;
using UnityEngine.Networking;

public class EnemySpawner : NetworkBehaviour {

    public GameObject enemyPrefab;
    public int numberOfEnemies;

    public override void OnStartServer()
    {
        for (int i=0; i < numberOfEnemies; i++)
        {
            var spawnPosition = new Vector3(
                Random.Range(-8.0f, 8.0f),
                0.0f,
                Random.Range(-8.0f, 8.0f));

            var spawnRotation = Quaternion.Euler(
                0.0f,
                Random.Range(0,180),
                0.0f);

            var enemy = (GameObject)Instantiate(enemyPrefab, spawnPosition, spawnRotation);
            NetworkServer.Spawn(enemy);
        }
    }
}
  • 保存脚本
  • 回到Unity

下面开始利用Player Prefab创建Enemy

  • 将Player prefab拖到场景中
  • 修改Player名称为“Enemy”
  • 将Enemy拖到Project面板中创建一个新的Enemy prefab预制体
  • 选中Enemy
  • 删除Enemy中的Gun,点击继续
  • 选中Enemy
  • 删除Bullet Spawn
  • 移除PlayerController组件
  • 修改Enemy材质为Black Material
  • 修改Enemy Visor的材质为Default-Material
  • Apply Enemy Prefab
  • 删除场景中的Enemy Prefab
  • 保存场景

将 Enemy prefab 注册到NetworkManager中

  • 选中NetworkManager
  • 展开Spawn Info foldout
  • Registered Spawnable Prefabs点击+号
  • 将Enemy prefab添加到Registered Spawnable Prefabs list
  • 选中场景中的Enemy Spawner
  • 将Enemy prefab拖到Enemy prefab输入框中
  • 设置Number Of Enemies为4

  • 保存工程

build新版本,测试

16. 销毁死亡Enemy

  • 打开Health脚本
  • 添加destroyOnDeath变量
  • TakeDamage中判断销毁或者respawning

    代码如下:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;

    public bool destroyOnDeath;

    [SyncVar(hook = "OnChangeHealth")]
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

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

        currentHealth -= amount;
        if (currentHealth <= 0)
        {
            if (destroyOnDeath)
            {
                Destroy(gameObject);
            }
            else
            {
                currentHealth = maxHealth;

                // called on the Server, will be invoked on the Clients
                RpcRespawn();
            }
        }
    }

    void OnChangeHealth (int currentHealth)
    {
        healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
    }

    [ClientRpc]
    void RpcRespawn()
    {        if (isLocalPlayer)
        {
            // Set the player’s position to origin
            transform.position = Vector3.zero;
        }
    }
}
  • 保存脚本,回到Unity
  • 选中Enemy prefab
  • 将Health中Destroy On Death 属性勾选

增加出身点位置

由于Player每次出生位置一样,我们用NetworkStartPosition来增加一个出身点

  • 创建一个empty GameObject
  • 修改名称为“Spawn Position 1”
  • 选中Spawn Position 1
  • 增加组件Network > NetworkStartPosition
  • 设置Transform Position (3, 0, 0)
  • 复制一份Spawn Position 1 GameObject
  • 将复制这份修改名称为“Spawn Position 2”
  • 选中Spawn Position 2
  • 设置Transform Position (-3, 0, 0)
  • 选中Network Manager
  • 展开Spawn Info foldout
  • 修改Player Spawn Method 为 Round Robin

设置出生点位置

  • 打开Health脚本
  • 增加NetworkStartPosition变量
private NetworkStartPosition[] spawnPoints;
  • 增加Start方法
void Start ()
{
    if (isLocalPlayer)
    {
        spawnPoints = FindObjectsOfType<NetworkStartPosition>();
    }
}
  • 修改RpcRespawn中出生点坐标

    最终Health代码如下:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;
    public bool destroyOnDeath;

    [SyncVar(hook = "OnChangeHealth")]
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

    private NetworkStartPosition[] spawnPoints;

    void Start ()
    {
        if (isLocalPlayer)
        {
            spawnPoints = FindObjectsOfType<NetworkStartPosition>();
        }
    }

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

        currentHealth -= amount;
        if (currentHealth <= 0)
        {
            if (destroyOnDeath)
            {
                Destroy(gameObject);
            }
            else
            {
                currentHealth = maxHealth;

                // called on the Server, invoked on the Clients
                RpcRespawn();
            }
        }
    }

    void OnChangeHealth (int currentHealth )
    {
        healthBar.sizeDelta = new Vector2(currentHealth , healthBar.sizeDelta.y);
    }

    [ClientRpc]
    void RpcRespawn()
    {
        if (isLocalPlayer)
        {
            // Set the spawn point to origin as a default value
            Vector3 spawnPoint = Vector3.zero;

            // If there is a spawn point array and the array is not empty, pick one at random
            if (spawnPoints != null && spawnPoints.Length > 0)
            {
                spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)].transform.position;
            }

            // Set the player’s position to the chosen spawn point
            transform.position = spawnPoint;
        }
    }
}

Download sample code on github

OK,以上就是全部内容。关于详细的使用请看 Networking Overview

使用Multiplayer Networking做一个简单的多人游戏例子-3/3(Unity3D开发之二十七)的更多相关文章

  1. 使用Multiplayer Networking做一个简单的多人游戏例子-2/3(Unity3D开发之二十六)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/51007512 ...

  2. 使用Multiplayer Networking做一个简单的多人游戏例子-1/3(Unity3D开发之二十五)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/51006463 ...

  3. 使用Multiplayer Networking做一个简单的多人游戏例子-1/2

    原文地址: http://blog.csdn.net/cocos2der/article/details/51006463 本文主要讲述了如何使用Multiplayer Networking开发多人游 ...

  4. 使用Multiplayer Networking做一个简单的多人游戏例子-1/2(换一种方法)

    SynMove.cs using UnityEngine; using System.Collections; using UnityEngine.Networking; public class S ...

  5. 【Bugly干货分享】一起用 HTML5 Canvas 做一个简单又骚气的粒子引擎

    Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 前言 好吧,说是“粒子引擎”还是大言不 ...

  6. 使用React并做一个简单的to-do-list

    1. 前言 说到React,我从一年之前就开始试着了解并且看了相关的入门教程,而且还买过一本<React:引领未来的用户界面开发框架 >拜读.React的轻量组件化的思想及其virtual ...

  7. 【 D3.js 入门系列 --- 3 】 做一个简单的图表!

    前面说了几节,都是对文字进行处理,这一节中将用 D3.js 做一个简单的柱形图. 做柱形图有很多种方法,比如用 HTML 的 div 标签,或用 svg . 推荐用 SVG 来做各种图形.SVG 意为 ...

  8. 一起用HTML5 canvas做一个简单又骚气的粒子引擎

    前言 好吧,说是"粒子引擎"还是大言不惭而标题党了,离真正的粒子引擎还有点远.废话少说,先看demo 本文将教会你做一个简单的canvas粒子制造器(下称引擎). 世界观 这个简单 ...

  9. Jmeter初步使用二--使用jmeter做一个简单的性能测试

    经过上一次的初步使用,我们懂得了Jmeter的安装与初步使用的方法.现在,我们使用Jmeter做一个简单的性能测试.该次测试,提交的参数不做参数化处理,Jmeter各元件使用将在介绍在下一博文开始介绍 ...

随机推荐

  1. Python 3 智能发音

    真是十分神奇.. import win32com.client import time s = win32com.client.Dispatch("SAPI.SpVoice") s ...

  2. pipeline(管道)设计模式

  3. 2.关于QT中数据库操作,简单数据库连接操作,数据库的增删改查,QSqlTableModel和QTableView,事务操作,关于QItemDelegate 代理

     Linux下的qt安装,命令时:sudoapt-get install qt-sdk 安装mysql数据库,安装方法参考博客:http://blog.csdn.net/tototuzuoquan ...

  4. Dynamics CRM2011 MspInstallAction failed when installing an Update Rollup

    今天在给客户做环境迁移,安装包完成后按惯例打补丁,但在打补丁的时候却报错了,错误如下 最开始怀疑第一个打6是不是不对,毕竟N久没碰2011了忘的差不多了,后来下了个rollup1居然也打不上,根据这个 ...

  5. Dynamics CRM2015 The plug-in type does not exist in the specified assembly问题的解决方法

    在用插件工具PluginProfiler调试时,报"The plug-in type  xxxx  does not exist in the specified assembly" ...

  6. Android简易实战教程--第十一话《获取手机所有应用信息Engine类详解》

    如果想要获取系统手机应用的详细信息,那么下边代码可以直接作为模板使用.笔者对每一行代码都做了注解,供您参考.直接上代码: package com.example.itydl.engines; impo ...

  7. tomcat集群的failover机制

    集群要提供高可用性就必须要有某种机制去保证,常用的机制为failover(故障转移),简单说就是通过一定的heartbeat检测是否有故障,一旦故障发生备份节点则接管故障节点的工作. tomcat使用 ...

  8. Android性能优化之Splash页应该这样设计

    目前SplashActivity的设计 目前市场上的应用在启动时基本上都会先启动一个SplashActivity,作为一个欢迎界面,为什么这样设计呢? 个人总结有三个优点: 1.可以给用户更好的体验 ...

  9. A*寻路算法入门(六)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  10. 关于js校验,检验常见的比如:电话,数字,邮箱,手机号等等

     /**  验证数字:^[0-9]*$  验证n位的数字:^\d{n}$  验证至少n位数字:^\d{n,}$  验证m-n位的数字:^\d{m,n}$  验证零和非零开头的数字:^(0|[1-9 ...