赞
踩
UNet官方文档:https://docs.unity3d.com/Manual/UNet.html
创建一个新场景,命名为Offline,在场景中创建一个空GameObject,添加NetworkManager、NetworkManagerHUD两个组件
网络管理器功能包括:
这是用来配合NetworkManager的组件,只是一个功能展示UI,控制NetworkManager的基本功能。如StartHost()启动为主机,StartClient()启动为客户端等,一般只有测试的时候才用这个组件
新建场景,命名为Game,创建Scroll View作为聊天信息显示区域,创建InputField作为消息输入框,创建一个发送Button。
1.创建一个Panel,添加VerticalLayoutGroup、ContentSizeFitter组件,并做一下设置,用于根据文字多少消息框自适应大小
2.在Panel下创建一个Text,用于显示用户发送的文字消息
3.保存成Prefab,用于在代码中动态创建消息框
1.新建空GameObject,添加NetworkIdentify组件,并勾选Local Player Authority,只允许本地客户端控制。NetworkIdentify是网络物体必须要有的组件,用于网络身份识别
2.新建脚本命名为Speaker,用于将客户端输入的消息发送给服务端,然后由服务端发给所有客户端以实现消息同步.
代码如下:
- using UnityEngine;
- using UnityEngine.Networking;
- using UnityEngine.UI;
- public class Speaker : NetworkBehaviour
- {
- public GameObject itemPrefab;
- private Transform content;
- private InputField inputBox;
- private Button sendButton;
- //[SyncVar(hook = "OnValueChanged")]
- [SyncVar]
- private int onlineNum = 0;
- void Start()
- {
- content = GameObject.Find("Canvas/Scroll View/Viewport/Content").transform;
- inputBox = GameObject.Find("Canvas/InputField").GetComponent<InputField>();
- sendButton = GameObject.Find("Canvas/SendButton").GetComponent<Button>();
- sendButton.onClick.AddListener(SendButtonCallback);
- }
- /// <summary>
- /// 显示在线人数
- /// </summary>
- private void OnGUI()
- {
- if (!isLocalPlayer)
- return;
- GUI.Label(new Rect(new Vector2(10, 10), new Vector2(150, 50)),
- string.Format("在线人数:{0}", onlineNum));
- }
- /// <summary>
- /// 更新Serve端在线人数
- /// </summary>
- private void Update()
- {
- if(isServer)
- onlineNum = NetworkManager.singleton.numPlayers;
- }
- /// <summary>
- /// 发送按钮响应事件
- /// 将用户输入消息发送给服务端
- /// </summary>
- void SendButtonCallback()
- {
- if (!isLocalPlayer)
- return;
- if (inputBox.text.Length > 0)
- {
- string str = string.Format("{0}:{1}{2}", Network.player.ipAddress, System.Environment.NewLine, inputBox.text);
- CmdSend(str);
- inputBox.text = string.Empty;
- }
- }
- /// <summary>
- /// 使用Command修饰的函数表示在客户端调用,在服务端执行
- /// </summary>
- /// <param name="str"></param>
- [Command]
- void CmdSend(string str)
- {
- RpcShowMessage(str);
- }
- /// <summary>
- /// ClientRpc修饰的函数 表示由服务端调用,在所有客户端执行
- /// </summary>
- /// <param name="str"></param>
- [ClientRpc]
- void RpcShowMessage(string str)
- {
- GameObject item = Instantiate(itemPrefab, content);
- item.GetComponentInChildren<Text>().text = str;
- }
- }
代码非常简单,没有写发包收包却实现了客户端和服务端的消息同步,这就是UNet的强大之处,UNet的口号是让网络游戏开发就像开发单机游戏一样,最重要的是UNet Server端与客户端运行的是同样的代码,也就是说Server端有Unity所有的功能(物理引擎、网格导航等),这些信息直接在Server端计算出来同步给Clients,而用其它网络引擎就需要在Server端自己写碰撞和导航系统。不过UNet也有很多不足,例如Server和Client执行的是同样的代码,一旦有客户端被反编译那么Server端的逻辑也就暴露了。
代码中有几个UNet重要的关键字:
自动同步:
[SyncVar]或[SyncVar(hook="FuncName")]: 用于自动同步Server端变量,当Server端SyncVar修饰的变量发生改变时就会自动同步给所有Clients, 第二种写法是当此变量改变时会自动调用FuncName函数,这种同步方法通常用于变化比较频繁的变量。
手动同步:
[Command]:函数名必须以Cmd开头,Command修饰的函数表示在客户端调用,在服务端执行。如代码中在客户端调用CmdSend(string message), 把当前客户端用户输入消息作为参数传进去,该函数在客户端调用时传入了消息,然后此函数会在服务端执行,这样服务端就得到了客户端传递进来的消息。
[ClientRpc]:函数名必须以Rpc开头,ClientRpc修饰的函数 表示由服务端调用,在所有客户端执行。服务端执行了CmdSend()方法,而此方法又调用了RpcShowMessage(string str),把从客户端传来的消息又直接传入了RpcShowMessage(), 而[ClientRpc]修饰的函数是服务端调用客户端执行,服务端又将从客户端收到的消息转发给了所有客户端,这样就实现了消息的同步。
如图,把Offline和Game场景以及Speaker预制体拖入
想要使用Unity Cloud的在线游戏房间匹配系统需要在Unity开启MultiPlayer服务
Build项目,然后运行两个,一个启动为Host,一个启动为Client,启动后NetworkManager会自动切换至Online场景:
测试图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。