国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

局域網(wǎng)多人對戰(zhàn)飛行棋的實現(xiàn)

2019-11-17 03:05:34
字體:
供稿:網(wǎng)友

局域網(wǎng)多人對戰(zhàn)飛行棋的實現(xiàn)

在項目之間有段“空項期”,上個項目剛剛完成,下個項目還沒落實,時間比較充裕。去年9月份就經(jīng)歷了這么一次短暫的“空項期”,那時偶還是一名前端工作者,C#使用起來毫不含糊,還自己整過一個類SCSF的MVP框架AngelFrame(詳見之前博客:http://m.survivalescaperooms.com/wgp13x/p/99c2adc52d8f0dff30a038841ac32872.html)。在那段“空項期”之前,有位朋友托我做個小游戲,偶也滿口的答應(yīng),只可惜之前項目太忙沒時間做,就一直耽擱了,正好有這段“空項期”,所以做了一下,現(xiàn)在回想起來,做這個小游戲的過程中還是學(xué)習(xí)到了不少東西的,因為做游戲跟做項目的常用技術(shù)不同,于是在這里總結(jié)一下,別把這么寶貴的經(jīng)驗給弄丟了。

這個小游戲的需求很簡單,就是在局域網(wǎng)的環(huán)境里能夠自組織一個飛行棋平臺,多個玩家在里面你一步我一步的玩,看誰先飛完全程。在做這個游戲之前,偶連什么是飛行棋,飛行棋怎么玩的都不懂,就先在網(wǎng)上試玩了一小把,查了查飛行棋的規(guī)則。會玩兒了,就要想想怎么做了,規(guī)則實現(xiàn)肯定要有,用戶交互是個問題。在網(wǎng)上搜索了一下現(xiàn)成的C#飛行棋實現(xiàn)例子,發(fā)現(xiàn)不是給自家女兒做的就是給自家兒子做的,單機版的,手機版的,就是沒有局域網(wǎng)版的。好吧,只有看我來創(chuàng)造了。關(guān)鍵詞:飛行棋, C#, 局域網(wǎng), 多人對戰(zhàn)摘要:很久之前就有個朋友托我做個游戲了,這個游戲的需求很簡單,就是在局域網(wǎng)的環(huán)境里能夠自組織一個飛行棋平臺,多個玩家在里面你一步我一步的玩。游戲規(guī)則有了,實現(xiàn)的難點在于自建多人對戰(zhàn)平臺,C#飛行棋實現(xiàn)例子有很多,可就是沒有局域網(wǎng)版的,下面就是我抽出時間寫的一個局域網(wǎng)多人對戰(zhàn)飛行棋,在這里總結(jié)一下。
先看一下我做的游戲的運行界面,網(wǎng)上有個單機版本的飛行棋,我借鑒了它的界面及游戲邏輯,由于它是開源的,也不知道源代碼提供者是誰,這里就不做相關(guān)鏈接了。解釋一下,打開主界面就是上面這個樣子,如果局域網(wǎng)內(nèi)同時在線的游戲客戶端多,那么在當(dāng)前在線列表中會顯示同時在線的客戶端ip和用戶名,這時你先選擇要進(jìn)行游戲的客戶端,再點擊創(chuàng)建游戲,就可以開創(chuàng)一輪新游戲了,游戲者在兩到四之間。如果你要添加跨網(wǎng)段的客戶端,那就要點擊邀請好友按鈕,填寫IP,如果它們在線就會添加到當(dāng)前在線列表中,這時你再選擇它們,點擊創(chuàng)建游戲,就能夠在開創(chuàng)的新游戲里跟他們玩了。創(chuàng)建游戲成功后,在左下角處會出現(xiàn)一個色子,游戲面板上會出現(xiàn)各類顏色的飛機,每個游戲者對應(yīng)一類顏色。由一個游戲者先擲色子,擲到6后才能夠起飛,其它的游戲者輪循著來,每個游戲者的動作都能夠被其它游戲者收到,在下方文字欄中,會作出說明。網(wǎng)絡(luò)版的游戲,要做只能做成一個Server和多個Client,每個Client的每一步都要通知Server,由Server來運行游戲邏輯,指導(dǎo)Client的運行流程;或只是多個Client,每個Client都要維護(hù)其它的Client信息,Client的運行流程都要通知其它所有的Client,每個Client都運行游戲邏輯。我這里陰差陽錯的選擇了第二種,每個Client都是平等的,沒有Server。通知用的是UDP,局域網(wǎng)的用戶交互就全靠它了,下面是網(wǎng)絡(luò)通知相關(guān)的代碼,使用單例模式,它是局域網(wǎng)游戲運行起來的核。
publicclassNetwork{GhostName;publicstaticIPAddressIpAddress;privatestaticThreadlistener;publiceventEventHandler<GameMsg>ReceivedMsg;publicstaticNetworkInstance{get{if(_instace==null)_instace=newNetwork();return_instace;}}privateNetwork(){UdpClient=newUdpClient(Port);HostName=Dns.GetHostName();foreach(IPAddressipinDns.GetHostAddresses(HostName)){if(ip.AddressFamily==AddressFamily.InterNetwork){IpAddress=ip;break;}}}//局域網(wǎng)內(nèi)廣播,在上線時調(diào)用,通知其它Client有人上線了publicvoidBroadcast(GameMsgmsg){IPEndPointipEndPoint=newIPEndPoint(IPAddress.Broadcast,Port);byte[]bytes=Tools.Serialize(msg);UdpClient.Send(bytes,bytes.Length,ipEndPoint);}//接收消息線程入口,收到消息后觸發(fā)各類事件publicvoidReceiveMsg(){IPEndPointipEndPoint=newIPEndPoint(IPAddress.Broadcast,Port);while(true){byte[]bytes=null;try{bytes=UdpClient.Receive(refipEndPoint);}catch(SocketExceptionex){return;}GameMsgmsg=(GameMsg)Tools.Deserialize(bytes);if(ReceivedMsg!=null&&!msg.IpAddress.Equals(IpAddress))ReceivedMsg(this,msg);}}//向某IP定向發(fā)送消息publicvoidSend(IPAddressip,GameMsgmsg){IPEndPointipEndPoint=newIPEndPoint(ip,Port);byte[]bytes=Tools.Serialize(msg);UdpClient.Send(bytes,bytes.Length,ipEndPoint);}//向一些IP定向發(fā)送消息publicvoidSend(IPAddress[]ips,GameMsgmsg){foreach(IPAddressipAddressinips){if(!ipAddress.Equals(IpAddress))Send(ipAddress,msg);}}}
下面是游戲中,Client之間需要交互的一些消息體定義。GameMsg是消息體,里面包含消息類型,IP地址,消息內(nèi)容,消息內(nèi)容有可能是LandGameMsg對象,也有可能是CreateGameMsg對象...
[Serializable]publicclassGameMsg:EventArgs{publicMsgTypeEnumMsgType;publicIPAddressIpAddress;publicobjectMsgContent;}[Serializable]publicclassLandGameMsg//OnlineReply,Hello{publicstringHostName;publicstringUserName;}[Serializable]publicclassCreateGameMsg{publicstringCreaterHostName;publicstringCreaterUserName;publicIPAddress[]SelectedIpAddresses;publicstring[]SelectedHostNames;}......
在主界面中,有些對接收到的消息共同的處理邏輯,在這里也列出來給大家看一下吧。
publicpartialclassMainForm:Form{publicstaticThreadListener=newThread(newThreadStart(Network.Instance.ReceiveMsg)){Name="receiveMsg",Priority=ThreadPriority.Highest};publicstaticCurrStatEnumCurrStat=CurrStatEnum.Idle;privatestaticreadonlyMsgTypeEnum[]interestMsgTypes=newMsgTypeEnum[]{MsgTypeEnum.QuitGame}; publicMainForm(){Listener.Start();Network.Instance.ReceivedMsg+=newEventHandler<GameMsg>(_network_ReceivedMsg);Network.Instance.Broadcast(newGameMsg(){MsgType=MsgTypeEnum.LandGame,IpAddress=Network.IpAddress,MsgContent=newLandGameMsg(){HostName=Network.HostName}});} privatedelegatevoidDelegate_ReceivedMsg(GameMsgmsg);void_network_ReceivedMsg(objectsender,GameMsge){Delegate_ReceivedMsgmyDelegate=newDelegate_ReceivedMsg(handleReceivedMsg);if(interestMsgTypes.Contains(e.MsgType))Invoke(myDelegate,e);}voidhandleReceivedMsg(GameMsgmsg){switch(msg.MsgType){caseMsgTypeEnum.QuitGame://收到某人退出游戲請求MessageBox.Show("有小伙伴要求退出游戲");ucUsersInGame_QuitGame(null,null);break;}}}
如上所示,在主界面中主要是對用戶退出游戲請求做出一些邏輯處理,這里的線程監(jiān)控網(wǎng)絡(luò)發(fā)來的所有消息,但只對退出游戲請求感興趣,提示用戶,本局游戲結(jié)束。在其它界面也是類似的過程,下面再列出邀請好友界面里的,對其它游戲者的反饋信息做出邏輯處理的代碼段。
publicpartialclassInviteOthers:Form{privatestaticreadonlyMsgTypeEnum[]interestMsgTypes=newMsgTypeEnum[]{MsgTypeEnum.OnlineReply};publicList<GameMsg>OnlineReplys=newList<GameMsg>(); void_network_ReceivedMsg(objectsender,GameMsgmsg){if(interestMsgTypes.Contains(msg.MsgType)){switch(msg.MsgType){caseMsgTypeEnum.OnlineReply: OnlineReplys.Add(msg);break;}}} }
游戲引擎,游戲邏輯處理在這里就不多列了,那是在單機飛行棋里的實現(xiàn)了的。游戲的基本功能實現(xiàn)了后,還實現(xiàn)了一些添喜的功能,比如隱藏到桌面上方、下方、旁邊,就是你可以把游戲窗口拖動到屏幕的最上方,然后松鼠標(biāo),游戲會縮到屏幕上方,當(dāng)你再把鼠標(biāo)移動到屏幕上方時,它還會出來,就跟掛QQ的功能一樣。它是這樣實現(xiàn)的,在主界面中添加3個Windows.Forms.Timer,timer1的Enabled=True,Interval=100;timer2、timer3的Enabled=False,Interval=1,再各自添加如下事件處理邏輯。
///監(jiān)控鼠標(biāo)和窗口位置privatevoidtimer1_Tick(objectsender,EventArgse){intmouse_x=Cursor.Position.X,mouse_y=Cursor.Position.Y;intwindow_x=this.Location.X,window_y=this.Location.Y;intwindow_width=this.Size.Width,window_height=this.Size.Height;if(isHiding==false&&window_y==0){if(window_x-mouse_x>10||mouse_x-window_x-window_width>10||mouse_y-window_y-window_height>10){timer1.Enabled=false;timer2.Enabled=true;}}if(isHiding==true&&mouse_y<=1&&mouse_x>window_x&&mouse_x<window_x+window_width){timer1.Enabled=false;timer3.Enabled=true;}}///隱藏界面privatevoidtimer2_Tick(objectsender,EventArgse){intwindow_height=this.Size.Height;startY+=window_height/8;if(startY<window_height){this.Location=newPoint(this.Location.X,-startY);}else{this.Location=newPoint(this.Location.X,1-window_height);isHiding=true;timer2.Enabled=false;timer1.Enabled=true;}}///顯示界面privatevoidtimer3_Tick(objectsender,EventArgse){intwindow_height=this.Size.Height;startY-=window_height/8;if(startY>0){this.Location=newPoint(this.Location.X,-startY);}else{this.Location=newPoint(this.Location.X,0);isHiding=false;timer3.Enabled=false;timer1.Enabled=true;}}
就這樣把局域網(wǎng)多人對戰(zhàn)飛行棋給實現(xiàn)了,回看這次的編程設(shè)計經(jīng)歷,覺得這種P2P式的,無Server式的游戲設(shè)計是個問題。這種設(shè)計影響到游戲編碼方式,使得游戲編碼雜亂無章,沒有一個主心骨來對游戲步驟進(jìn)行統(tǒng)一管理,這樣如若數(shù)據(jù)在網(wǎng)絡(luò)中丟失,很容易導(dǎo)致多客戶端不同步的現(xiàn)象。應(yīng)該在選取完游戲伙伴創(chuàng)建新游戲時,自主選擇一個Server來處理游戲邏輯,這樣,8個人、10個人、更多的人同時在線都可以自組織游戲平臺了,不同步也可以避免了。其它的一些收獲:1、System.Windows.Forms.application.DoEvents();可以督促主線程處理當(dāng)前在消息隊列中的所有Windows消息。2、朋友機器上的操作系統(tǒng)是WinXP,自帶的沒有.net4.0,自帶.net3.0,剛開始運行不起來,后來全部換到.net3.0調(diào)試、改代碼,才運行得起來。3、做完后,在家里跟老婆兩個人打?qū)?zhàn),玩了一晚上這個游戲都不累,還挺好玩的。好久沒來博客園更新博客了,最近新項目來了。新項目做完,又有好多新知識可以總結(jié)嘍!

來自為知筆記(Wiz)


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 翼城县| 湘乡市| 巢湖市| 孝感市| 南召县| 内江市| 廊坊市| 屏东市| 屯昌县| 阿巴嘎旗| 阿拉善左旗| 广州市| 安庆市| 海晏县| 汤原县| 湘阴县| 淳化县| 木里| 塔河县| 新绛县| 富阳市| 金坛市| 离岛区| 宁国市| 鄂尔多斯市| 无锡市| 九寨沟县| 松潘县| 仙桃市| 全州县| 宁远县| 深泽县| 临桂县| 门头沟区| 桐柏县| 怀化市| 遂平县| 河源市| 光泽县| 南汇区| 肥西县|