unity3d网络游戏开发API
从 Unity 5.0 开始,提供了全新的 UNet 开发网络游戏,面向两种类型的用户:
- 使用 Unity 开发简单多人游戏,应该从高阶 API 开始
- 使用 “NetworkManager” 管理网络,控制游戏对象网络状态
- 从客户端调用服务器函数 或 从服务器调用客户端函数
- 使用网络组件,可视化编辑程序
- nternet 服务支持
- 用户自定义网络基础设施或高级多人游戏,应该从 NetworkTransport API 开始
- 使用 UDP 等
- 自建复杂的网络结构
本篇博客使用的是高级API。
unity3d开发网络多人游戏
- 新建 NetworkManager对象:
- 首先创建一个空对象,将其命名为NetworkManager;
- 为该对象添加组件:NetworkManager,NetworkManagerHUB。
- 制作玩家预制:
- 本次实验使用的是巡逻兵那篇博客的人物素材,需要删除玩家预制下的摄像机,命名为player;
- 为玩家预制添加组件:NetworkIdentity(Local Player Authority需要设置为true,使客户端可以控制玩家),NetworkTransform(为服务器提供玩家位置等信息)。
- 注册玩家预制:
将玩家预制拖入NetworkManager的swap info的Player Prefab插槽。 - 注册子弹预制:
- 新建球体对象,命名为Bullet,scale设置为0.2;
- 给子弹rigidbody组件,取消重力;
- 添加新脚本bullet.cs,bullet.cs用来处理子弹的碰撞事件;
- 用 Add 按钮添加一个新的 spawn 预制件,将 Bullet 预制件拖入新的 spawn 预制插槽。
- 玩家控制脚本:
- 新建名为Network.cs的玩家控制脚本;
- Network.cs脚本中,控制玩家的移动和攻击,控制摄像机跟随。
- 新建Combat.cs,改脚本控制玩家血条值;
- 添加场景控制:
新建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;
}
}
更多内容请戳:传送门