Unity官方内置网络NetWork官方实例教程(一)Unity官方内置网络NetWork官方实例教程(二) 本篇是接上篇unet的基础篇的一些功能的拓展主要为以下:
- 代码自定义生成玩家。
- 数据的同步问题。
0x00 简介
- OnServerReady:当有客户端准备(Ready)时调用
- OnServerAddPlayer:当生成对象到客户端时调用
- OnServerRemovePlayer:当玩家从客户端销毁时调用
- OnServerDisconnect:当有客户端断开时调用
- OnServerConnect:当有客户端连接时调用
- OnServerError:当服务器发生错误时调用
- OnClientConnect:当连接到服务器时调用
- OnClientDisconnect:当断开服务器时调用
- OnClientError:当网络问题时调用
- OnClientNotReady:告诉服务器没准备好时调用
- OnMatchCreate:当有一个比赛创建
- OnMatchList:当接收到比赛列表时调用
- OnMatchJoined:当假如比赛时调用
0X01 自定义生成玩家(位置)
自定义生成玩家即自定义位置,颜色,标签等不同的玩家。如果我们想做一些对战的小游戏可以参考。
- 在Hierarchy中创建一个空物体用来放玩家出生点,自定义命名(例子为:SpawnPoints)。
- 在SpawnPoints中添加相应的点(自定义命名,自定义位置)并添加NetworkStartPosition组件。如图所示:
- 重写了NetworkManager脚本,代码如下:
public class MyNetWorkManager : NetworkManager
{
#region 字段
private short _tempIdCount = 1;
//private int _tempCamDepthCount = 4;
private NetworkStartPosition[] _spawnPoints;
#endregion
#region 系统方法
// Use this for initialization
void Start()
{
_spawnPoints = FindObjectsOfType<NetworkStartPosition>();
#region 测试
//foreach (var item in _spawnPoints)
//{
// Debug.Log(item.name);
//}
#endregion
}
#endregion
#region NetWork方法
/// <summary>
/// 添加玩家
/// </summary>
/// <param name="conn">连接方式</param>
/// <param name="playerControllerId">玩家id</param>
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
playerControllerId = _tempIdCount;
GameObject player = (GameObject)Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
player.name = "Player_" + playerControllerId;
if (_spawnPoints != null)
{
player.transform.position = _spawnPoints[playerControllerId - 1].transform.position;
player.transform.rotation = _spawnPoints[playerControllerId - 1].transform.rotation;
}
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
_tempIdCount += 1;
// _tempCamDepthCount -= 1;
}
#endregion
#region 私有方法
/// <summary>
/// 设置同步变量初始化值
/// </summary>
/// <param name="tempObj">实例的物体</param>
/// <param name="_syncColor">颜色</param>
/// <param name="layerInt">j20父物体层</param>
/// <param name="layerInt_Collider">雷达碰撞层</param>
/// <param name="layerInt_Receive">雷达接收层</param>
/// <param name="tagStr">j20父物体标签</param>
/// <param name="missileStr">导弹池对应字符串</param>
/// <param name="fireStr">开火池对应字符串</param>
void SetSyncVariable(GameObject tempObj, Color _syncColor, int layerInt, int layerInt_Collider, int layerInt_Receive, string tagStr, string missileStr, string fireStr)
{
tempObj.GetComponent<FighterSyncControl>()._syncColor = _syncColor;
tempObj.GetComponent<FighterSyncControl>()._syncLayerInt = layerInt;
tempObj.GetComponent<FighterSyncControl>()._syncLayerInt_Collider = layerInt_Collider;
tempObj.GetComponent<FighterSyncControl>()._syncLayerInt_Receive = layerInt_Receive;
tempObj.GetComponent<FighterSyncControl>()._syncTagStr = tagStr;
tempObj.GetComponentInChildren<FighterSyncControl>()._syncMissilePoolStr = missileStr;
tempObj.GetComponentInChildren<FighterSyncControl>()._syncFilePoolStr = fireStr;
}
#endregion
}
在每次加入玩家的时候都会根据位置点,自定义初始位置,效果如图所示:
0X03 自定义其他变量
自定义颜色,标签,层
修改上面自定义玩家的脚本,新增一些内容,如下:
/// <summary>
/// 添加玩家
/// </summary>
/// <param name="conn">连接方式</param>
/// <param name="playerControllerId">玩家id</param>
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
playerControllerId = _tempIdCount;
GameObject player = (GameObject)Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
switch (playerControllerId)
{
case 1:
SetSyncVariable(player, Color.red, 11, 14, 19, "Friendly", "missile_Instantiate_f", "Particle_missile_fire_f");
break;
case 2:
SetSyncVariable(player, Color.blue, 15, 13, 17, "Enemy", "missile_Instantiate_e", "Particle_missile_fire_e");
break;
case 3:
SetSyncVariable(player, Color.blue, 15, 13, 17, "Enemy", "missile_Instantiate_e", "Particle_missile_fire_e");
break;
case 4:
SetSyncVariable(player, Color.red, 11, 14, 19, "Friendly", "missile_Instantiate_f", "Particle_missile_fire_f");
break;
default:
break;
}
player.name = "Player_" + playerControllerId;
if (_spawnPoints != null)
{
player.transform.position = _spawnPoints[playerControllerId - 1].transform.position;
player.transform.rotation = _spawnPoints[playerControllerId - 1].transform.rotation;
}
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
_tempIdCount += 1;
// _tempCamDepthCount -= 1;
}
效果如图所示:如图可见已经修改成功,下一步就是测试数据是否同步。
0X04 数据同步
- 首先写一个飞机接收同步数据的脚本,并且并挂载在飞机身上,自定义命名(例子名称:FighterSyncControl)代码如下:
public class FighterSyncControl : NetworkBehaviour
{
#region 变量
private Transform[] allObj;
private GameObject curFighter;
#region 飞机同步变量
[SyncVar] [HideInInspector] public Color _syncColor; // 颜色
// 同步标签和层
[SyncVar] [HideInInspector] public int _syncLayerInt;
[SyncVar] [HideInInspector] public int _syncLayerInt_Collider;
[SyncVar] [HideInInspector] public int _syncLayerInt_Receive;
[SyncVar] [HideInInspector] public string _syncTagStr;
[SyncVar] [HideInInspector] public int _syncDefTagStr;
[SyncVar] [HideInInspector] public string _syncDefLayerInt;
// 脚本变量
[SyncVar] [HideInInspector] public string _syncMissilePoolStr;
[SyncVar] [HideInInspector] public string _syncFilePoolStr;
#endregion
#endregion
#region 系统方法
private void Awake()
{
curFighter = gameObject.GetComponentInChildren<UI_show_info_a>().gameObject;
}
// Use this for initialization
void Start()
{
allObj = curFighter.GetComponentsInChildren<Transform>(true);
foreach (Transform item in allObj)
{
SetRedOrBule(_syncLayerInt, _syncTagStr, _syncLayerInt_Collider, _syncLayerInt_Receive, _syncMissilePoolStr, _syncFilePoolStr);
}
SetScriptVariable(_syncColor);
}
// Update is called once per frame
void Update()
{
#region 测试
if (Input.GetMouseButtonDown(0))
{//判断鼠标是否按下
// 从摄像机开始,到屏幕触摸点,发出一条射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// 撞击到了哪个3D物体
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.transform.tag);//打印出碰撞到的节点的名字
}
}
#endregion
}
#endregion
/// <summary>
/// 设置红蓝
/// </summary>
/// <param name="layerInt">层值</param>
/// <param name="tagStr">标签值</param>
private void SetRedOrBule(int j20_layerInt, string tagStr, int radaCollider_layerInt, int radaRec_layerInt, string missileStr, string fireStr)
{
foreach (Transform item in allObj)
{
// 测试:单独给某个赋值
if (item.name.Equals("J20_beta"))
{
item.gameObject.tag = tagStr;
item.gameObject.layer = j20_layerInt;
}
if (item.name.Equals("rada_scan_collider"))
{
item.gameObject.layer = radaCollider_layerInt;
}
if (item.name.Equals("rada_receive_collider"))
{
item.gameObject.layer = radaRec_layerInt;
}
}
curFighter.GetComponent<UI_show_info_a>().missile_inpool = missileStr;
curFighter.GetComponent<UI_show_info_a>().fire_inpool = fireStr;
}
/// <summary>
/// 给固定的脚本变量赋值(同步变量)
/// </summary>
private void SetScriptVariable(Color tempColor)
{
curFighter.transform.Find("fighter_blue_type_f22").GetComponent<MeshRenderer>().material.color = tempColor;
}
}
现在我们可以运行测试了,测试效果如下图所示: