您的位置:首页 > 移动开发 > Unity3D

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

2016-03-29 17:08 861 查看
猴子原创,欢迎转载。转载请注明: 转载自Cocos2Der-CSDN,谢谢!

原文地址: http://blog.csdn.net/cocos2der/article/details/51007512

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

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

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

7. 在网络中控制Player移动

上一篇中,玩家操作移动会同时控制同屏内的所有Player,且只有自己的屏幕生效。因为咱们还没有同步Transform信息。

下面我们通过UnityEngine.Networking组件来实现玩家控制各自Player

打开PlayerController脚本

添加命名空间UnityEngine.Networking

using UnityEngine.Networking;


修改MonoBehaviour为NetworkBehaviour

public class PlayerController : NetworkBehaviour


在Update函数中添加如下方法

if (!isLocalPlayer)
{
return;
}


最后你的PlayerController内容如下:

using UnityEngine;
using UnityEngine.Networking;

public class PlayerController : NetworkBehaviour
{
void Update()
{
if (!isLocalPlayer) { return; }

var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
}
}


保存脚本

回到Unity中

选中Player prefab在Project面板中

保持Player prefab为选中状态

添加组件Network > NetworkTransform

保存工程



NetworkTransform用于在网络中同步所有Client信息。加上isLocalPlayer判断,只让当前客户端操作。

8. 测试网络中多玩家移动

同样Build一个Mac standalone application作为主机运行

点击LAN Host作为主机开始游戏

运行Unity,点击LAN Client作为另一个客户端加入游戏

点击各自的WASD移动各自Player

9. 区分各自的Player

上面中两个Player外观一致,我们修改自己Player的颜色

打开PlayerController脚本

添加OnStartLocalPlayer方法

public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}


最终PlayerController:

using UnityEngine;
using UnityEngine.Networking;

public class PlayerController : NetworkBehaviour
{
void Update()
{
if (!isLocalPlayer) { return; }

var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
}

public override void OnStartLocalPlayer() { GetComponent<MeshRenderer>().material.color = Color.blue; }
}


Build新的Mac版本,测试效果



关闭Mac版本,停止运行Unity,回到编辑状态

10. 给Player添加射击武器

创建子弹

创建一个Sphere GameObject

修改名称为“Bullet”

选中Bullet对象

修改Transform (0.2, 0.2, 0.2)

添加组件Physics > Rigidbody

在Rigidbody属性中取消Use Gravity

拖拽Bullet到Project面板中,制作为Prefab

删除场景中Bullet

保存场景

下面修改PlayerController添加发射子弹

打开PlayerController脚本

添加public变量bulletPrefab

public GameObject bulletPrefab;


添加子弹local发射点

public Transform bulletSpawn;


在Update中加入输入源

if (Input.GetKeyDown(KeyCode.Space))
{
Fire();
}


添加Fire方法

void Fire()
{
// Create the Bullet from the Bullet Prefab
var bullet = (GameObject)Instantiate (
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);

// Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;

// Destroy the bullet after 2 seconds
Destroy(bullet, 2.0f);
}


最终PlayerController如下:

using UnityEngine;
using UnityEngine.Networking;

public class PlayerController : NetworkBehaviour
{
public GameObject bulletPrefab;
public Transform bulletSpawn;

void Update()
{
if (!isLocalPlayer) { return; }

var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);

if (Input.GetKeyDown(KeyCode.Space)) { Fire(); }
}

void Fire()
{
// Create the Bullet from the Bullet Prefab
var bullet = (GameObject)Instantiate(
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);

// Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;

// Destroy the bullet after 2 seconds
Destroy(bullet, 2.0f);
}

public override void OnStartLocalPlayer ()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
}


保存脚本

回到Unity

下面开始针对变化过的PlayerController修改Player Prefab

将Player Prefab拖拽到场景中

保持Player prefab选中

创建一个Cylinder圆柱体作为其Child

修改Cylinder名称为“Gun”

保持Gun被选中

移除Capsule Collider组件

设置Transform Position (0.5, 0.0, 0.5)

设置Transform Rotation (90.0, 0.0, 0.0)

设置Transform Scale (0.25, 0.5, 0.25)

设置Material为Black Material

最后Player效果:



保持Player选中状态

创建一个empty GameObject作为Child

修改empty GameObject名称为“Bullet Spawn”

设置Bullet Spawn Position (0.5, 0.0, 1.0)

主要是将子弹发射点Bullet Spawn设置到枪口处



保持Player Prefab选中

将Bullet prefab拖到PlayerController中的Bullet Prefab 框

将Player的Child Bullet Spawn拖到PlayerController中的Bullet Spawn 框

保存工程

Build新的Mac版本,并测试

你会发现空格键可以在各自场景中发射子弹,但是子弹没有出现在对方场景中。

关闭Mac版本

停止Unity,回到编辑模式

11. 增加多人射击

下面我们会将Bullet prefab注册到NetworkManager

选中Bullet prefab在Project面板中

保存Bullet prefab选中

添加组件Network > NetworkIdentity

添加组件Network > NetworkTransform

设置NetworkTransform中Network Send Rate为0

子弹不会中途改变方向,所以我们不需要每帧更新位置,每个客户端自己计算Bullet坐标信息,所以将Network Send Rate设置为0,网络不需要同步坐标信息。



选中NetworkManager在Hierarchy面板中

保持NetworkManager选中

展开Spawn Info

点击Registered Spawnable Prefabs右下角+

将Bullet Prefab加入到Registered Spawnable Prefabs中



打开PlayerController脚本

注意[Command]可以声明一个函数可以本客户端调用,但是会在服务端(主机)执行。

添加[Command]给Fire函数

修改Fire函数名称为“CmdFire”

[Command]
void CmdFire()


Update函数中修改调用为CmdFire

CmdFire();


在CmdFire函数中添加NetworkServer.Spawn方法来创建bullet

NetworkServer.Spawn(bullet);


最终PlayerController如下:

using UnityEngine;
using UnityEngine.Networking;

public class PlayerController : NetworkBehaviour
{
public GameObject bulletPrefab;
public Transform bulletSpawn;

void Update()
{
if (!isLocalPlayer) { return; }

var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);

if (Input.GetKeyDown(KeyCode.Space))
{
CmdFire();
}
}

// This [Command] code is called on the Client …
// … but it is run on the Server!
[Command] void CmdFire()
{
// Create the Bullet from the Bullet Prefab
var bullet = (GameObject)Instantiate(
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);

// Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;

// Spawn the bullet on the Clients
NetworkServer.Spawn(bullet);

// Destroy the bullet after 2 seconds
Destroy(bullet, 2.0f);
}

public override void OnStartLocalPlayer ()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
}


保存脚本

回到Unity

Build新版本Mac,测试

此时应该可以看到子弹同步到了每个玩家场景中

关闭Mac版本

停止运行Unity,回到编辑模式

添加玩家生命值

给Bullet Prefab添加一个新脚本“Bullet”

打开Bullet脚本

添加碰撞函数

using UnityEngine;
using System.Collections;

public class Bullet : MonoBehaviour {

void OnCollisionEnter(Collision collision)
{
Destroy(gameObject);
}
}


此时子弹碰撞到Player之后自动销毁

添加玩家生命值

- 给Player prefab添加一个新脚本“Health”

Health脚本如下:

using UnityEngine;

public class Health : MonoBehaviour
{
public const int maxHealth = 100;
public int currentHealth = maxHealth;

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


保存脚本

在Bullet中增加击中受伤

修改Bullet中的OnCollisionEnter函数

using UnityEngine;
using System.Collections;

public class Bullet : MonoBehaviour {

void OnCollisionEnter(Collision collision)
{
var hit = collision.gameObject;
var health = hit.GetComponent<Health>();
if (health  != null)
{
health.TakeDamage(10);
}

Destroy(gameObject);
}
}


添加一个简易的玩家头顶血条

在场中中创建一个UI Image

修改Canvas名称为“Healthbar Canvas”

修改Image名称为“Background”

保存Background选中

设置RectTransform Width 100

设置RectTransform Height 10

修改Source Image 为 built-in InputFieldBackground

修改 Image Color 为红色

不要修改Background的中心点和锚点

复制一份Background

修改复制出来的Background名称为Foreground

将Foreground设置为Background的Child

将Player prefab拖到场景中

将Healthbar Canvas拖到Player中作为Child

整个Player结构如下:



选中Foreground

设置Foreground Image为绿色

将Foreground 中心点和锚点修改为Middle Left(用于血条从左到右填充)



选中Healthbar Canvas

点击RectTransform设置按钮(小齿轮)中的Reset

设置RectTransform Scale (0.01, 0.01, 0.01)

设置RectTransform Position (0.0, 1.5, 0.0)

选中Player,点击apply,保存Player Prefab

保存场景

修改Health脚本,控制血条

最终Health脚本如下:

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

public class Health : MonoBehaviour {

public const int maxHealth = 100;
public int currentHealth = maxHealth;
public RectTransform healthBar;

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

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


保存脚本

回到Unity

保持Player选中

将Foreground拖到Healthbar输入框中



apply Player prefab

删除场景中的Player

保存场景

最后,修改Healthbar永远朝向主摄像机

- 给Player prefab中的Healthbar Canvas添加新脚本“Billboard”

Billboard脚本如下:

using UnityEngine;
using System.Collections;

public class Billboard : MonoBehaviour {

void Update () {
transform.LookAt(Camera.main.transform);
}
}


编译新Mac版本,测试

你会发现血条只在本地变化了,没有同步到所有玩家。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息