Unity 高级知识
<一>NetworkManager 类创建服务器和客户端
<1>NetworkServer类负责创建服务器监听接口,管理客户端的连接
它也负责处理游戏相关的一些特性 :玩家管理 ,监听,卵生对象和消息处理
Server方法
静态方法 功能
Listen 根据指定端口开启服务器
RegisterHandler 注册回调函数 (接受客户端连接请求)
Spawn 在所有已准备的客户端上实例化物体
SpawnWithClientAuthority 跟Spawn() 方法一样 并且设置客户端权限
Destroy 在所有客户端上删除物体
AddPlayerForConnection 将卵生的物体与客户端建立关系
Server属性
静态变量 功能
active 检查服务器是否开启
connections 当前所有连接的客户端列表
handles 以字典形式返回服务器注册的所有回调方法
listenPort 服务器监听端口
localClientActive 在服务器上的客户端,即为主机是返回true
maxDelay 连接之间发送数据的最大延迟
创建服务器
需要引入using UnityEngine.NetWorking ; 系统
Button StartServerButton;
void OnEnable(){
Application.runInBackground=true;
StartServerButton=GetComponent<Button>();
StartServerButton.onClick.RemoveAllListeners;
StartServerButton.onClick.AddListener(StartServer);
}
void StartServer(){
//服务器是否打开
if(!NetworkServer.active){
//根据指定端口 开启服务器
NetworkServer.Listen(7777);
}
//接受客户端连接请求
}
<二>NetworkClient该类对象负责连接服务器,并与服务器通信(即收到服务器消息和发送消息给服务器)
Client方法
对象方法 功能
Connect 根据指定IP和Port连接服务器
RegisterHandler 注册回调函数
创建客户端
需要引入using UnityEngine.Networking;系统
Button clientButton;
NetworkClient client;
void OnEnable(){
clientButton=GetComponent<Button>();
clientButton.onClick.AddListener(Connect);
}
void Connect(){
//创建了一个客户端对象
client=new NetworkClient();
//注册回调函数
client.RegisterHandler(MsgType.Connect,OnClientConnect);
//连接服务器
client.Connect("127.0.0.1",7777);
}
//成功连接服务器之后
void OnClientConnect(NetworkMessage msg){
print("连接服务器成功");
}
****完整代码****
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking ;
using UnityEngine.UI ;
public class NetworkMangerScr : MonoBehaviour {
// 1.创建服务器按钮
Button iButton;
//8.连接服务器按钮
Button CButton;
//12.客户端对象
NetworkClient m_client;
//17.网络预设体
public GameObject m_prefab;
void Awake(){
m_client = new NetworkClient ();
Application.runInBackground = true;
iButton = GameObject.Find ("IButton").GetComponent <Button > ();
CButton = GameObject.Find ("CButton").GetComponent <Button > ();
//2.移除
iButton.onClick.RemoveAllListeners ();
//3.绑定
iButton.onClick.AddListener (InitServerAction);
//9.移除
CButton.onClick.RemoveAllListeners ();
//10.绑定
CButton.onClick.AddListener (ConnectSever );
}
//11连接服务器的点击事件
void ConnectSever(){
//13.连接服务器
m_client.Connect("127.0.0.1",3456);
//14.注册连接成功的回调方法
m_client.RegisterHandler (MsgType.Connect ,OnConnectSever );
}
//15.连接成功的回调方法
void OnConnectSever(NetworkMessage msg){
print ("连接服务器成功");
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking ;
using UnityEngine.UI ;
public class NetworkMangerScr : MonoBehaviour {
// 1.创建服务器按钮
Button iButton;
//8.连接服务器按钮
Button CButton;
//12.客户端对象
NetworkClient m_client;
//17.网络预设体
public GameObject m_prefab;
void Awake(){
m_client = new NetworkClient ();
Application.runInBackground = true;
iButton = GameObject.Find ("IButton").GetComponent <Button > ();
CButton = GameObject.Find ("CButton").GetComponent <Button > ();
//2.移除
iButton.onClick.RemoveAllListeners ();
//3.绑定
iButton.onClick.AddListener (InitServerAction);
//9.移除
CButton.onClick.RemoveAllListeners ();
//10.绑定
CButton.onClick.AddListener (ConnectSever );
}
//11连接服务器的点击事件
void ConnectSever(){
//13.连接服务器
m_client.Connect("127.0.0.1",3456);
//14.注册连接成功的回调方法
m_client.RegisterHandler (MsgType.Connect ,OnConnectSever );
}
//15.连接成功的回调方法
void OnConnectSever(NetworkMessage msg){
print ("连接服务器成功");
//16.场景已经准备好 客户端场景准备进入Game窗口 conn 客户端连接准备
ClientScene.Ready (msg.conn);
//18.向服务器注册玩家预设体
ClientScene.RegisterPrefab (m_prefab );
//19.添加一个玩家 使用该方法之后 服务器端的MsgType.AddPlayer 注册方法就会调用
ClientScene.AddPlayer (0);
}
//4.创建服务器的点击事件
void InitServerAction(){
//根据指定端口 开启服务器
NetworkServer.Listen (3456);
//6.接受客户端连接请求
NetworkServer.RegisterHandler (MsgType.AddPlayer ,OnServerAddPlayer);
//23.
m_client =ClientScene.ConnectLocalServer ();
m_client.RegisterHandler (MsgType.Connect ,OnConnectSever);
}
//7.玩家在服务器创建玩家对象的回调方法
void OnServerAddPlayer(NetworkMessage msg){
//20.在服务器端 实例化网络对象
//18.向服务器注册玩家预设体
ClientScene.RegisterPrefab (m_prefab );
//19.添加一个玩家 使用该方法之后 服务器端的MsgType.AddPlayer 注册方法就会调用
ClientScene.AddPlayer (0);
}
//4.创建服务器的点击事件
void InitServerAction(){
//根据指定端口 开启服务器
NetworkServer.Listen (3456);
//6.接受客户端连接请求
NetworkServer.RegisterHandler (MsgType.AddPlayer ,OnServerAddPlayer);
//23.
m_client =ClientScene.ConnectLocalServer ();
m_client.RegisterHandler (MsgType.Connect ,OnConnectSever);
}
//7.玩家在服务器创建玩家对象的回调方法
void OnServerAddPlayer(NetworkMessage msg){
//20.在服务器端 实例化网络对象
GameObject obj=Instantiate (m_prefab ,Vector3.zero ,Quaternion.identity );
//21. 将创建的游戏对象与某个玩家建立联系,表示该obj由客户端生成
NetworkServer.AddPlayerForConnection (msg.conn,obj,0);
//22.将游戏对象卵生到所有客户端
NetworkServer.Spawn (obj);
}
void Start () {
}
// Update is called once per frame
void Update () {
}
//22.将游戏对象卵生到所有客户端
NetworkServer.Spawn (obj);
}
void Start () {
}
// Update is called once per frame
void Update () {
}
}
<二>Unity网络卵生
网络中 ,所有网络对象都应该由服务器产生
客户端玩家对象生成步骤:
1.客户端发请求
2.服务器接收请求后实例化客户端对象
卵生对象步骤
1.新建预设体,添加NetworkIdentity组件 标示为网络物体
2.客户端调用ClientScene.Ready() 方法告知服务器自己已准备好
3.客户端调用ClientScene.RegisterPrefab()提前 注册网络预设体
4.客户端调用ClientScene.AddPlayer()方法告诉服务器执行卵生对象的程序,参数即给将要产生卵生对象贴一个IP
5.服务器RegisterHandler-->MsgType.AddPlayer的回调AddPlayer
6.服务器在AddPlayer方法实例化物体,调用Spawn方法卵生
<三>Unity状态同步
1.NetworkIdentity组件是网络的核心 用NetworkServer.Spawn卵生的物体都必须具备该组件
该组件在卵生的时候会自动分配assetld和权限
2.NetworkBehaviour组件是一个特殊组件,它依赖NetworkIdentity组件,用来实现RPC技术和状态同步属性.
我们想实现状态同步 则网络物体的控制脚本必须继承自NetworkBehaviour
NetworkBehaviour组件包含的常用特性[Attribute]
特性 功能
[SyncVar] 用于标识序列化变量,实现变量同步
[Client] 表示只能在客户端调用
[ClientCallback] 表示客户端执行的回调
[Command] 表示客户端向服务端发送的命令,在服务端执行
[ClientRpc] 表示服务端向客户端发送的命令,在客户端执行
***特别注意动画同步中 ,参数为Trigger的最为特殊 服务端不能直接执行该动画 因此需要先在客户端执行然后再在服务端执行
完整代码 (续上面代码)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking ;
using UnityEngine.UI ;
public class PlayerScript : NetworkBehaviour {
//血量 客户端执行服务端调用
[SyncVar]
float hp=100f;
public GameObject bullet;
Slider hpSlider;
void Awake(){
hpSlider = transform.Find ("Canvas/HpSlider").GetComponent <Slider >();
}
// Use this for initialization
void Start () {
//卵生到客户端
ClientScene.RegisterPrefab (bullet );
}
// Update is called once per frame
void Update () {
//实时更新血条
hpSlider.value =hp/100f;
//判断是不是本地客户端
if (!isLocalPlayer) {
return;
}
//控制移动
float hor=Input.GetAxis ("Horizontal");
float ver = Input.GetAxis ("Vertical");
if (ver!=0 ||hor!=0) {
transform.position += new Vector3 (hor, ver, 0f) * 5f*Time.deltaTime ;
}
if (Input.GetKeyDown (KeyCode.Space )) {
//发射子弹
CmdFire ();
}
}
//发射子弹
//由[Command]修饰的方法 表示客户端调用 服务器执行 方法的名字必须以Cmd开头
[Command]
void CmdFire(){
GameObject obj = Instantiate (bullet, transform.position+transform.right, Quaternion.identity);
obj.GetComponent <Rigidbody > ().AddForce (transform.right *1000f);
NetworkServer.Spawn (obj);
}
void OnTriggerEnter(Collider other){
CmdDemage ();
Destroy (other.gameObject );
}
[Command ]
void CmdDemage(){
hp -= 20f;
}
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking ;
using UnityEngine.UI ;
public class PlayerScript : NetworkBehaviour {
//血量 客户端执行服务端调用
[SyncVar]
float hp=100f;
public GameObject bullet;
Slider hpSlider;
void Awake(){
hpSlider = transform.Find ("Canvas/HpSlider").GetComponent <Slider >();
}
// Use this for initialization
void Start () {
//卵生到客户端
ClientScene.RegisterPrefab (bullet );
}
// Update is called once per frame
void Update () {
//实时更新血条
hpSlider.value =hp/100f;
//判断是不是本地客户端
if (!isLocalPlayer) {
return;
}
//控制移动
float hor=Input.GetAxis ("Horizontal");
float ver = Input.GetAxis ("Vertical");
if (ver!=0 ||hor!=0) {
transform.position += new Vector3 (hor, ver, 0f) * 5f*Time.deltaTime ;
}
if (Input.GetKeyDown (KeyCode.Space )) {
//发射子弹
CmdFire ();
}
}
//发射子弹
//由[Command]修饰的方法 表示客户端调用 服务器执行 方法的名字必须以Cmd开头
[Command]
void CmdFire(){
GameObject obj = Instantiate (bullet, transform.position+transform.right, Quaternion.identity);
obj.GetComponent <Rigidbody > ().AddForce (transform.right *1000f);
NetworkServer.Spawn (obj);
}
void OnTriggerEnter(Collider other){
CmdDemage ();
Destroy (other.gameObject );
}
[Command ]
void CmdDemage(){
hp -= 20f;
}
}
(动画状态同步重点)
完整代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking ;
public class PlayerController : NetworkBehaviour {
Animator ani;
// Use this for initialization
void Start () {
ani = GetComponent <Animator > ();
}
void Update () {
if (!isLocalPlayer ) {
return;
}
float ver = Input.GetAxis ("Vertical");
float hor = Input.GetAxis ("Horizontal");
transform.position += new Vector3 (hor,ver,0)*5f*Time.deltaTime ;
if (Input.GetKeyDown (KeyCode.Alpha1 )) {
//攻击
ani.SetBool ("Attack",!ani.GetBool ("Attack"));
}
if (Input.GetKeyDown (KeyCode.Alpha2 )) {
//跳跃
CmdJump ();
}
}
[Command ]
void CmdJump(){
//告诉服务器要执行代码 服务器去通知其他客户端执行Trigger控制的动画
RpcJump ();
}
[ClientRpc ]
void RpcJump(){
ani.SetTrigger ("Jump");
}
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking ;
public class PlayerController : NetworkBehaviour {
Animator ani;
// Use this for initialization
void Start () {
ani = GetComponent <Animator > ();
}
void Update () {
if (!isLocalPlayer ) {
return;
}
float ver = Input.GetAxis ("Vertical");
float hor = Input.GetAxis ("Horizontal");
transform.position += new Vector3 (hor,ver,0)*5f*Time.deltaTime ;
if (Input.GetKeyDown (KeyCode.Alpha1 )) {
//攻击
ani.SetBool ("Attack",!ani.GetBool ("Attack"));
}
if (Input.GetKeyDown (KeyCode.Alpha2 )) {
//跳跃
CmdJump ();
}
}
[Command ]
void CmdJump(){
//告诉服务器要执行代码 服务器去通知其他客户端执行Trigger控制的动画
RpcJump ();
}
[ClientRpc ]
void RpcJump(){
ani.SetTrigger ("Jump");
}
}
<四>RPC(远程过程调用)技术
需要引入Using UnityEngine.Networking; 系统
网络系统可以实现客户端和服务器的通信,则称之为:远程调用Remote Procedure Calls 即RPC
RPC框架可以方便实现方法调用
Unity中有俩种类型: 客户端调用服务器方法(Command)
服务器调用客户端方法(ClientRpc)
<完整代码看上面>
<五>Unity网络管理器
重点
网络管理器(NetworkManager)是Unity新版网络HLAPI中的一个核心组件 ,该组件封装了网络创建,运行和Debug等各种方法
初级开发者,不需要写一行代码,即可实现简单的网络游戏