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;
}
}
現在我們可以運行測試了,測試效果如下圖所示: