本文是解釋鷹大的多人聯網執行個體example1思路,由于自己了解的問題,不足地方請斧正。。。
------------------------------------------華麗的分割線--------------------------------------------
主線流程
1. awake 【設計遊戲視窗 擷取玩家名字】
function Awake(){
//開辟聊天的視窗
window = Rect(Screen.width/2-width/2, Screen.height-height+5, width, height);
//We get the name from the masterserver example, if you entered your name there ;).
//**********************************************masterserver不了解;[14.3.30
playerName = PlayerPrefs.GetString("playerName", "");
if(!playerName || playerName==""){
playerName = "RandomName"+Random.Range(1,999);
}
}
2. ongui 【判斷是否顯示聊天視窗 建立聊天視窗 處理回車[擷取輸入焦點]】
function OnGUI ()
{
//顯示聊天視窗時【連接配接到伺服器的用戶端,初始化後的伺服器】才繪制聊天視窗
if(!showChat){
return;
}
GUI.skin = skin;
//目前處理的事件如果是按鍵按下 并且按下的按鍵是Enter鍵 并且未有輸入值【沒輸入時按Enter鍵】
if (Event.current.type == EventType.keyDown && Event.current.character == "\n" && inputField.Length <= 0)
{
//如果上次釋放螢幕到現在超過0.25秒
if(lastUnfocusTime+0.25<Time.time){
usingChat=true;
//5号視窗【聊天視窗】鎖定為活動視窗
GUI.FocusWindow(5);
//焦點放到輸入框
GUI.FocusControl("Chat input field");
}
}
//建立5号彈出視窗【聊天視窗】 标題為空
window = GUI.Window (5, window, GlobalChatWindow, "");
}
3. 建立聊天視窗 【建立滾動條 滾動條中從對話表中逐句讀取對話處理回車[傳出對話]以及滑鼠左鍵[失焦并停止對話顯示]效果】
//建立視窗的函數
function GlobalChatWindow (id : int) {
//【垂直方向留白10像素】-----不留沒滾動條 不太懂;]
GUILayout.BeginVertical();
GUILayout.Space(10);
GUILayout.EndVertical();
// Begin a scroll view. All rects are calculated automatically -
// it will use up any available screen space and make sure contents flow correctly.
// This is kept small with the last two parameters to force scrollbars to appear.
//建立一個自動布局的滾動視圖,最後兩個參數确定了強制出現滾動條的範圍
scrollPosition = GUILayout.BeginScrollView (scrollPosition);
//在存儲的對話清單中讀取對話
for (var entry : ChatEntry in chatEntries)
{
//建立水準組用以顯示姓名,輸入内容
GUILayout.BeginHorizontal();
//姓名不存在即輸出遊戲的資訊而非對話
if(entry.name==""){//Game message
GUILayout.Label (entry.text);
}else{
GUILayout.Label (entry.name+": "+entry.text);
}
GUILayout.EndHorizontal();
//下邊的範圍 3像素空隙【不加沒有滾動條顯示】
GUILayout.Space(3);
}
// End the scrollview we began above.
GUILayout.EndScrollView ();
//如果輸入值後按下空格鍵
if (Event.current.type == EventType.keyDown && Event.current.character == "\n" && inputField.Length > 0)
{
//把輸入的值傳出
HitEnter(inputField);
}
//為輸入控件命名
GUI.SetNextControlName("Chat input field");
inputField = GUILayout.TextField(inputField);
//滑鼠左鍵按下時
if(Input.GetKeyDown("mouse 0")){
//當正在聊天時單擊左鍵,失去焦點并且标記為停止聊天
if(usingChat){
usingChat=false;
GUI.UnfocusWindow ();//Deselect chat
lastUnfocusTime=Time.time;
}
}
}
4. 傳出對話 【消除換行 将對話加入到對話表 初始化會話資訊】
function HitEnter(msg : String){
//将輸入的換行取消
msg = msg.Replace("\n", "");
//将目前的聊天對象和打入的話以RPC傳出
networkView.RPC("ApplyGlobalChatText", RPCMode.All, playerName, msg);
//将行中内容清除
inputField = ""; //Clear line
//使目前視窗【聊天視窗】失去焦點
GUI.UnfocusWindow ();//Deselect chat
//設定釋放焦點時間
lastUnfocusTime=Time.time;
//标記停止聊天
usingChat=false;
}
連接配接(connect):
1. 用戶端OnConnectedToServer()
l 辨別顯示對話框
l 通知伺服器将此用戶端資訊傳入玩家清單
function OnConnectedToServer() {
//用戶端連接配接到伺服器或者伺服器初始化時初始化聊天視窗
ShowChatWindow();
//傳輸連接配接玩家名字用以顯示
networkView.RPC ("TellServerOurName", RPCMode.Server, playerName);
// //We could have also announced ourselves:
// addGameChatMessage(playerName" joined the chat");
// //But using "TellServer.." we build a list of active players which we can use for other stuff as well.
}
2. 伺服器OnServerInitialized()
l 辨別顯示對話框
l 直接将伺服器資訊存入玩家清單[當伺服器也作為一個玩家存在]
l 通知顯示伺服器加入對話【系統通知】
function OnServerInitialized() {
ShowChatWindow();
//I wish Unity supported sending an RPC on the server to the server itself :(
// If so; we could use the same line as in "OnConnectedToServer();"
var newEntry : PlayerNode = new PlayerNode();
newEntry.playerName=playerName;
newEntry.networkPlayer=Network.player;
playerList.Add(newEntry);
//伺服器也作為一個聊天的玩家
addGameChatMessage(playerName+" joined the chat");
}
伺服器OnPlayerConnected(player: NetworkPlayer)
l 傳遞顯示加入玩家加入遊戲的資訊【系統通知】
function OnPlayerConnected(player: NetworkPlayer) {
//玩家連接配接到伺服器時,伺服器廣播玩家資訊
addGameChatMessage("Player connected from: " + player.ipAddress +":" + player.port);
}
掉線(disconnect)
1. 用戶端OnDisconnectedFromServer()
l 标記隐藏對話框
function OnDisconnectedFromServer(){
//從伺服器斷開後,用戶端關閉聊天視窗
CloseChatWindow();
}
2. 伺服器OnPlayerDisconnected(player: NetworkPlayer)
l 傳遞顯示玩家掉線的資訊【系統通知】
l 在玩家清單删除掉線玩家資訊[依賴networkplayer擷取具體玩家資訊]
function OnPlayerDisconnected(player: NetworkPlayer) {
//玩家掉線時,伺服器調用,删除清單中的玩家
addGameChatMessage("Player disconnected from: " + player.ipAddress+":" + player.port);
//Remove player from the server list
playerList.Remove( GetPlayerNode(player) );
}
封裝函數
1. RPC函數
l 通知伺服器将用戶端的資訊傳入玩家清單【将傳入的資訊加入玩家清單通知顯示該玩家加入對話】
@RPC
//Sent by newly connected clients, recieved by server
//伺服器獲得用戶端傳輸的玩家資訊,并廣播
function TellServerOurName(name : String, info : NetworkMessageInfo){
var newEntry : PlayerNode = new PlayerNode();
newEntry.playerName=name;
newEntry.networkPlayer=info.sender;
playerList.Add(newEntry);
addGameChatMessage(name+" joined the chat");
}
l 将對話加入到對話表
@RPC
function ApplyGlobalChatText (name : String, msg : String)
{
//将傳入的對話存儲到對話清單中
var entry = new ChatEntry();
entry.name = name;
entry.text = msg;
chatEntries.Add(entry);
//Remove old entries
//當對話清單中内容超過4條時銷毀第一條對話
if (chatEntries.Count > 4){
chatEntries.RemoveAt(0);
}
//将滾動條y軸數值設定極大,使得每次輸入後螢幕上都顯示最後一次輸入的内容
scrollPosition.y = 1000000;
}
2. 普通函數
l 依賴networkplayer擷取具體玩家資訊【逐條從玩家清單取出資訊比對】
function GetPlayerNode(networkPlayer : NetworkPlayer){
for(var entry : PlayerNode in playerList){
if(entry.networkPlayer==networkPlayer){
return entry;
}
}
Debug.LogError("GetPlayerNode: Requested a playernode of non-existing player!");
return null;
}
l 辨別顯示對話框【辨別顯示對話框輸入值、對話清單初始化】
function ShowChatWindow ()
{
showChat = true;
inputField = "";
chatEntries = new ArrayList();
}
l 辨別隐藏對話框【辨別隐藏對話框輸入值、對話清單初始化】
function CloseChatWindow ()
{
showChat = false;
inputField = "";
chatEntries = new ArrayList();
}
l 遊戲資訊的通知【系統通知】
//輸出遊戲資訊【**登入等等】伺服器的通知
function addGameChatMessage(str : String){
ApplyGlobalChatText("", str);//通知自己
if(Network.connections.length>0){
//通知其他玩家
networkView.RPC("ApplyGlobalChatText", RPCMode.Others, "", str);
}
}