項(xiàng)目7實(shí)現(xiàn)戰(zhàn)場(chǎng)同步模塊課件_第1頁(yè)
項(xiàng)目7實(shí)現(xiàn)戰(zhàn)場(chǎng)同步模塊課件_第2頁(yè)
項(xiàng)目7實(shí)現(xiàn)戰(zhàn)場(chǎng)同步模塊課件_第3頁(yè)
項(xiàng)目7實(shí)現(xiàn)戰(zhàn)場(chǎng)同步模塊課件_第4頁(yè)
項(xiàng)目7實(shí)現(xiàn)戰(zhàn)場(chǎng)同步模塊課件_第5頁(yè)
已閱讀5頁(yè),還剩52頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、騰訊云游戲應(yīng)用開(kāi)發(fā)位置同步01任務(wù)攻擊同步02任務(wù)命中同步03任務(wù)實(shí)現(xiàn)戰(zhàn)場(chǎng)同步模塊項(xiàng)目7勝負(fù)判斷04任務(wù)玩家退出05任務(wù)學(xué)習(xí)目標(biāo) 實(shí)現(xiàn)游戲戰(zhàn)斗部分的同步邏輯 掌握位置同步的基本方法 掌握利用網(wǎng)絡(luò)同步來(lái)控制角色行為的方法1位置同步玩家需要及時(shí)地獲取其他玩家的最新位置信息,包括移動(dòng)、跳躍、方向。這需要客戶端定期地向服務(wù)端報(bào)告自己的位置,再由服務(wù)端廣播出去??蛻舳藙?chuàng)建專門(mén)的方法來(lái)處理這些信息。位置同步功能主要由以下3個(gè)步驟構(gòu)成:(1)玩家每隔一段時(shí)間向服務(wù)端發(fā)送位置同步協(xié)議。(2)服務(wù)端將協(xié)議廣播轉(zhuǎn)發(fā)給其他玩家。(3)其他玩家接收到協(xié)議,調(diào)用對(duì)應(yīng)ID的角色的NetCtrl方法。1位置同步1.設(shè)計(jì)協(xié)議

2、玩家定期地向服務(wù)端報(bào)考自己的位置信息,其中包括坐標(biāo)、身體的旋轉(zhuǎn)、頭部的旋轉(zhuǎn),因?yàn)橹鹘堑纳眢w只能進(jìn)行Y軸的旋轉(zhuǎn),而頭部只能進(jìn)行X軸的旋轉(zhuǎn),所以只需要將兩個(gè)軸的旋轉(zhuǎn)角寫(xiě)進(jìn)協(xié)議里。協(xié)議格式如下:服務(wù)端收到協(xié)議后,在協(xié)議名后面補(bǔ)充發(fā)送者的ID,然后廣播出去。其他玩家收到協(xié)議后,在客戶端里找到發(fā)送者對(duì)應(yīng)的角色,利用預(yù)測(cè)法更新其位置和旋轉(zhuǎn)。1位置同步2.客戶端發(fā)送位置同步消息在PlayerCtrl中添加字段/*上一次發(fā)送位置同步協(xié)議的時(shí)間*/privatefloatlastSendInfoTime; 1位置同步2.客戶端發(fā)送位置同步消息在PlayerCtrl中添加SendUnitInfo方法/*發(fā)送位移和

3、旋轉(zhuǎn)協(xié)議*/voidSendUnitInfo()/*構(gòu)建協(xié)議*/ProtocolStrproto=newProtocolStr();proto.AddString(updateunitinfo);/當(dāng)前位置Vector3pos=transform.position;proto.AddFloat(pos.x);proto.AddFloat(pos.y);proto.AddFloat(pos.z);/當(dāng)前旋轉(zhuǎn)proto.AddFloat(transform.eulerAngles.y);proto.AddFloat(head.eulerAngles.x);/*發(fā)送協(xié)議*/NetMgr.instan

4、ce.Send(proto);Debug.Log(發(fā)送位移同步); 1位置同步2.客戶端發(fā)送位置同步消息因?yàn)槲恢猛叫枰婚g斷地定期上報(bào),所以在Update方法中調(diào)用它,在Update方法的最后添加如下代碼/*每隔100ms發(fā)送一次位置同步信息*/if(Time.time-lastSendInfoTime0.1f)SendUnitInfo();lastSendInfoTime=Time.time; 1位置同步3.服務(wù)端廣播位置同步消息服務(wù)端收到客戶端發(fā)來(lái)的位置同步信息,然后再?gòu)V播出去。在HandlePlayerMsg中添加Msgupdateunitinfo處理方法,代碼如下。/*位置同步協(xié)議*

5、/publicvoidMsgupdateunitinfo(Playerplayer,ProtocolBaseprotoBase)/*獲取數(shù)值*/ProtocolStrprotocol=(ProtocolStr)protoBase;stringprotoName=protocol.GetString(0);floatposX=protocol.GetFloat(1);floatposY=protocol.GetFloat(2);floatposZ=protocol.GetFloat(3);floatrotY=protocol.GetFloat(4);floatheadRotX=protocol.

6、GetFloat(5);/*獲取房間*/if(player.tempData.status!=PlayerTempData.Status.Fight)return;Roomroom=player.tempData.room;/*構(gòu)建返回協(xié)議*/ProtocolStrprotocolRet=newProtocolStr();protocolRet.AddString(updateunitinfo);protocolRet.AddString(player.id);protocolRet.AddFloat(posX);protocolRet.AddFloat(posY);protocolRet.A

7、ddFloat(posZ);protocolRet.AddFloat(rotY);protocolRet.AddFloat(headRotX);/*廣播*/room.Broadcast(protocolRet); 1位置同步4.客戶端接收位置同步消息 BattleManager負(fù)責(zé)戰(zhàn)斗時(shí)的邏輯,在BattleManager腳本的StartBattle方法最底部注冊(cè)監(jiān)聽(tīng),代碼如下/*更新單位狀態(tài)協(xié)議*/NetMgr.instance.msgDist.AddListener(updateunitinfo,RecvUpdateUnitInfo);并實(shí)現(xiàn)返回協(xié)議方法RecvUpdateUnitInfo

8、,代碼如下。/*接收UpdateUnitInfo協(xié)議回發(fā)*/publicvoidRecvUpdateUnitInfo(ProtocolBaseprotocol)/*解析協(xié)議*/ProtocolStrproto=(ProtocolStr)protocol;stringid=proto.GetString(1);Vector3nPos=newVector3();Vector3nRot=Vector3.zero;Vector3nHeadRot=Vector3.zero;nPos.x=proto.GetFloat(2);nPos.y=proto.GetFloat(3);nPos.z=proto.Get

9、Float(4);nRot.y=proto.GetFloat(5);nHeadRot.x=proto.GetFloat(6);1位置同步5.服務(wù)端廣播位置同步消息/*排除自身*/if(id=GameMgr.instance.id)return;/*查找角色*/if(!list.ContainsKey(id)Debug.LogError(RecvUpdateUnitInfo ba = null “+id);return;BattleArcherba=listid;/*同步*/NetCtrlctrl=ba.archer.GetComponent();if(ctrl!=null)ctrl.NetFo

10、recastInfo(nPos,nRot,nHeadRot);elseDebug.LogError(RecvUpdateUnitInfonetctrl=null); 1位置同步6.客戶端實(shí)現(xiàn)位置同步/*變量*/上次接收位置同步的時(shí)間floatlastRecvInfoTime=float.MinValue;/網(wǎng)絡(luò)延遲floatdelta;/上次同步的位置和旋轉(zhuǎn)Vector3lPos,lRot,lHeadRot;/預(yù)測(cè)的位置和旋轉(zhuǎn)Vector3fPos,fRot,fHeadRot; /*引用*/HeadTransformhead;/ArcherArcherarcher; /動(dòng)畫(huà)控制器Animato

11、ranim; NetCtrl是用來(lái)控制其他角色行為的腳本,它根據(jù)服務(wù)端發(fā)送的同步協(xié)議來(lái)處理角色的行為。在NetCtrl中添加字段,代碼如下1位置同步6.客戶端實(shí)現(xiàn)位置同步voidAwake()/*初始化*/head=transform.Find(Body).Find(Head);fPos=transform.position;lPos=transform.position;lRot=transform.eulerAngles;fRot=transform.eulerAngles;fHeadRot=Vector3.zero;lHeadRot=Vector3.zero;archer=GetComp

12、onent();anim=GetComponent(); 在Awake方法中初始化,代碼如下。1位置同步6.客戶端實(shí)現(xiàn)位置同步/*預(yù)測(cè)移動(dòng)*/publicvoidNetForecastInfo(Vector3nPos,Vector3nRot,Vector3nHeadRot)/*預(yù)測(cè)位置和旋轉(zhuǎn)*/fPos=lPos+(nPos-lPos)*2;fRot=lRot+(nRot-lRot)*2;fHeadRot=lHeadRot+(nHeadRot-lHeadRot)*2;/*如果發(fā)送者發(fā)生網(wǎng)絡(luò)延遲,則不進(jìn)行預(yù)測(cè)*/if(Time.time-lastRecvInfoTime0.3f)fPos=nPo

13、s;fRot=nRot;fHeadRot=nHeadRot;/時(shí)間delta=Time.time-lastRecvInfoTime;/*動(dòng)畫(huà)控制*/如果發(fā)生跳躍就停止跑步動(dòng)畫(huà)if (nPos.y - lPos.y) != 0)if(!anim.GetBool(die)anim.speed = 0;創(chuàng)建NetForecastInfo方法,代碼如下。1位置同步6.客戶端實(shí)現(xiàn)位置同步else/*根據(jù)移動(dòng)設(shè)置跑步動(dòng)畫(huà)*/Vector3vel=(newVector3(nPos.x-lPos.x,0,nPos.z-lPos.z)/0.1f;anim.SetFloat(moveSpeed,vel.magni

14、tude);/如果沒(méi)有移動(dòng)就停止跑步動(dòng)畫(huà)if(vel.magnitude!=0)anim.speed=1; else if(!anim.GetBool(die)anim.speed = 0;/*更新變量*/lPos=nPos;lRot=nRot;lHeadRot=nHeadRot;lastRecvInfoTime=Time.time; 1位置同步6.客戶端實(shí)現(xiàn)位置同步voidUpdate()if(!archer.alive)return;/*更新移動(dòng)狀態(tài)*/當(dāng)收到新的位置同步消息時(shí),更新位置if(delta0)/更新位置transform.position=Vector3.Lerp(trans

15、form.position,fPos,Time.deltaTime/delta);/更新身體旋轉(zhuǎn)transform.rotation=Quaternion.Lerp(Quaternion.Euler(transform.eulerAngles),Quaternion.Euler(fRot),Time.deltaTime/delta);/更新頭部旋轉(zhuǎn)head.localRotation=Quaternion.Lerp(Quaternion.Euler(head.localEulerAngles),Quaternion.Euler(fHeadRot),Time.deltaTime/delta);

16、得到了預(yù)測(cè)的位置過(guò)后,需要在Update方法中讓角色朝著目標(biāo)位置移動(dòng),代碼如下。2攻擊同步1.蓄力協(xié)議為了看到其他玩家蓄力的動(dòng)作,需要在玩家蓄力時(shí)提醒其他玩家,而不用多余的參數(shù),協(xié)議名hold,協(xié)議格式如下:服務(wù)端收到協(xié)議后,在協(xié)議名后面補(bǔ)充發(fā)送者的ID,廣播給其他玩家。其他玩家收到協(xié)議后,在客戶端里找到發(fā)送者對(duì)應(yīng)的角色,使對(duì)應(yīng)角色執(zhí)行蓄力動(dòng)作,并記錄蓄力時(shí)間。2攻擊同步2.射擊協(xié)議玩家蓄力一段時(shí)候后發(fā)出箭矢,發(fā)出箭矢的瞬間向服務(wù)端報(bào)告箭矢的速度向量,因?yàn)橄蛄孔銐虮硎舅俣鹊拇笮『头较颍赴l(fā)出的位置取決于蓄力的時(shí)間,所以不需要額外參數(shù)。協(xié)議格式如下:服務(wù)端收到協(xié)議后,在協(xié)議名后面補(bǔ)充發(fā)送者的

17、ID,廣播給其他玩家。其他玩家收到協(xié)議后,在客戶端里找到發(fā)送者對(duì)應(yīng)的角色,使對(duì)應(yīng)角色執(zhí)行發(fā)射動(dòng)作,使箭矢以協(xié)議里的速度發(fā)射出去。2攻擊同步3.發(fā)送蓄力協(xié)議在PlayerCtrl中添加SendHoldInfo方法,代碼如下。/*發(fā)送蓄力協(xié)議*/voidSendHoldInfo()/*構(gòu)建協(xié)議*/ProtocolStrproto=newProtocolStr();proto.AddString(hold);/*發(fā)送協(xié)議*/NetMgr.instance.Send(proto);Debug.Log(發(fā)送蓄力同步); 2攻擊同步3.發(fā)送蓄力協(xié)議修改LeftAttack方法,在蓄力的第一幀發(fā)送協(xié)議的方法

18、,代碼如下。/*鼠標(biāo)保持按下則進(jìn)入蓄力狀態(tài)*/if(Input.GetMouseButton(0)/在按下的第一幀發(fā)送蓄力協(xié)議if(leftHoldtime=0)SendHoldInfo();/累計(jì)蓄力時(shí)間leftHoldtime+=Time.deltaTime;/*播放蓄力動(dòng)作,箭矢往后收回*/holdArrow.transform.localPosition=Vector3.Lerp(holdArrow.transform.localPosition,newVector3(0,0,-0.1f),Time.deltaTime);lastArrowPosition=holdArrow.tran

19、sform.localPosition; 2攻擊同步4.發(fā)送射擊協(xié)議在PlayerCtrl中添加SendShootInfo方法,代碼如下。/*發(fā)送發(fā)射協(xié)議*/voidSendShootInfo(floatx,floaty,floatz)ProtocolStrproto=newProtocolStr();proto.AddString(shoot);proto.AddFloat(x);proto.AddFloat(y);proto.AddFloat(z);NetMgr.instance.Send(proto);Debug.Log(發(fā)送發(fā)射同步); 2攻擊同步4.發(fā)送射擊協(xié)議修改LeftAttac

20、k方法,在發(fā)射的瞬間發(fā)送協(xié)議的方法,代碼如下。/*當(dāng)鼠標(biāo)抬起則執(zhí)行發(fā)射動(dòng)作*/if(Input.GetMouseButtonUp(0)if(leftHoldtime0)/添加剛體Rigidbodyharb=holdArrow.AddComponent();harb.useGravity=false;harb.constraints=RigidbodyConstraints.FreezeRotation;/發(fā)送協(xié)議SendShootInfo(rb.velocity.x,rb.velocity.y,rb.velocity.z);/脫離父物體holdArrow.transform.SetParent

21、(null);/添加速度holdArrow.GetComponent().Launch(this.gameObject,leftHoldtime,rb.velocity);/重置箭矢裝填lastLAttTime=Time.time;holdArrow=null; 2攻擊同步5.服務(wù)端廣播攻擊同步消息服務(wù)端收到客戶端發(fā)來(lái)的蓄力協(xié)議和射擊協(xié)議后,在協(xié)議中添加發(fā)送者的ID,然后再?gòu)V播出去。在HandlePlayerMsg中添加Msghold和Msgshoot方法,代碼如下。/*蓄力同步協(xié)議*/publicvoidMsghold(Playerplayer,ProtocolBaseprotoBase)/

22、*獲取房間*/if(player.tempData.status!=PlayerTempData.Status.Fight)return;Roomroom=player.tempData.room;/*構(gòu)建返回協(xié)議*/ProtocolStrprotocolRet=newProtocolStr();protocolRet.AddString(hold);protocolRet.AddString(player.id);/*廣播*/room.Broadcast(protocolRet);2攻擊同步5.服務(wù)端廣播攻擊同步消息/*射擊同步協(xié)議*/publicvoidMsgshoot(Playerpla

23、yer,ProtocolBaseprotoBase)/*獲取數(shù)值*/ProtocolStrprotocol=(ProtocolStr)protoBase;stringprotoName=protocol.GetString(0);floatposX=protocol.GetFloat(1);floatposY=protocol.GetFloat(2);floatposZ=protocol.GetFloat(3);/*獲取房間*/if(player.tempData.status!=PlayerTempData.Status.Fight)return;Roomroom=player.tempDa

24、ta.room;/*構(gòu)建返回協(xié)議*/ProtocolStrprotocolRet=newProtocolStr();protocolRet.AddString(shoot);protocolRet.AddString(player.id);protocolRet.AddFloat(posX);protocolRet.AddFloat(posY);protocolRet.AddFloat(posZ);/*廣播*/room.Broadcast(protocolRet); 2攻擊同步6.客戶端接收攻擊同步消息在BattleManager腳本的StartBattle方法最底部注冊(cè)監(jiān)聽(tīng),代碼如下。/*蓄

25、力協(xié)議*/NetMgr.instance.msgDist.AddListener(hold,RecvHold);/*發(fā)射協(xié)議*/NetMgr.instance.msgDist.AddListener(shoot,RecvShoot); 2攻擊同步6.客戶端接收攻擊同步消息實(shí)現(xiàn)RecvHold方法,代碼如下。publicvoidRecvHold(ProtocolBaseprotocol)ProtocolStrproto=(ProtocolStr)protocol;stringid=proto.GetString(1);/*排除自身*/if(id=GameMgr.instance.id)retur

26、n;/*查找角色*/if(!list.ContainsKey(id)Debug.LogError(RecvHold ba = null “+id);return;BattleArcherba=listid;/*同步*/NetCtrlctrl=ba.archer.GetComponent();if(ctrl!=null)ctrl.NetHold();elseDebug.LogError(RecvHoldnetctrl=null);2攻擊同步6.客戶端接收攻擊同步消息實(shí)現(xiàn)RecvShoot方法,代碼如下。publicvoidRecvShoot(ProtocolBaseprotocol)Protoc

27、olStrproto=(ProtocolStr)protocol;stringid=proto.GetString(1);floatx=proto.GetFloat(2);floaty=proto.GetFloat(3);floatz=proto.GetFloat(4);Vector3vel=newVector3(x,y,z);if(id=GameMgr.instance.id)return;if(!list.ContainsKey(id)Debug.LogError(RecvShoot ba = null “+id);return;BattleArcherba=listid;/*同步*/Ne

28、tCtrlctrl=ba.archer.GetComponent();if(ctrl!=null)ctrl.NetShoot(vel);elseDebug.LogError(RecvShootnetctrl=null); 2攻擊同步7.客戶端實(shí)現(xiàn)攻擊同步修改NetCtrl,添加攻擊相關(guān)的字段,代碼如下。/箭矢預(yù)制體publicGameObjectarrowPrefab;/已經(jīng)上弦的箭矢GameObjectholdArrow;/槍口Transformmuzzle; /上一陣蓄力的位置Vector3lastArrowPosition;/射箭的間隔floatintervalLAtt=1;/上一次箭矢

29、射出的時(shí)間floatlastLAttTime;/是否蓄力boolhold=false;/蓄力時(shí)間floatholdtime=0; 2攻擊同步7.客戶端實(shí)現(xiàn)攻擊同步在Awake方法中初始化muzzle,代碼如下。muzzle=transform.Find(Body).Find(Head).Find(RHand).Find(Gong).Find(Muzzle); 2攻擊同步7.客戶端實(shí)現(xiàn)攻擊同步添加裝填箭矢的方法LoadArrow、網(wǎng)絡(luò)控制蓄力的方法Net Hold和網(wǎng)絡(luò)控制射擊的方法NetShoot,代碼如下。/*裝載箭矢*/publicvoidLoadArrow()/實(shí)例化箭矢holdArro

30、w=(GameObject)Instantiate(arrowPrefab,muzzle.transform.position,muzzle.transform.rotation);/附著父物體holdArrow.transform.SetParent(muzzle);/位置歸零lastArrowPosition=Vector3.zero;/*網(wǎng)絡(luò)控制蓄力*/publicvoidNetHold()hold=true;holdtime=0;2攻擊同步7.客戶端實(shí)現(xiàn)攻擊同步/*網(wǎng)絡(luò)控制發(fā)射*/publicvoidNetShoot(Vector3vel)/添加剛體Rigidbodyharb=hold

31、Arrow.AddComponent();harb.useGravity=false;harb.constraints=RigidbodyConstraints.FreezeRotation;/脫離父物體holdArrow.transform.SetParent(null);/添加速度holdArrow.GetComponent().Launch(this.gameObject,holdtime,vel);/重置箭矢裝填lastLAttTime=Time.time;holdArrow=null;hold=false; 2攻擊同步7.客戶端實(shí)現(xiàn)攻擊同步箭矢在攻擊冷卻后會(huì)自動(dòng)裝填,當(dāng)蓄力開(kāi)始,箭矢

32、需要往回收。當(dāng)沒(méi)有蓄力的時(shí)候,箭矢的位置需要重置。在Update方法的最后加入更新蓄力狀態(tài)的代碼,代碼如下。/*更新攻擊狀態(tài)*/*裝填箭矢*/if(holdArrow=null&Time.time-lastLAttTimeintervalLAtt)LoadArrow();/*更新蓄力狀態(tài)*/*當(dāng)開(kāi)始蓄力*/if(hold)if(holdArrow=null)LoadArrow();/累計(jì)蓄力時(shí)間holdtime+=Time.deltaTime;/*播放蓄力動(dòng)作,箭矢往后收回*/holdArrow.transform.localPosition=Vector3.Lerp(lastArrowPos

33、ition,newVector3(0,0,-0.1f),Time.deltaTime);lastArrowPosition=holdArrow.transform.localPosition;elseif(holdArrow!=null)holdArrow.transform.localPosition=lastArrowPosition; 3命中同步1.設(shè)計(jì)協(xié)議當(dāng)且僅當(dāng)玩家發(fā)出箭矢命中敵人時(shí),向服務(wù)端發(fā)送命中信息,其中包括被命中者的ID和傷害量。協(xié)議格式如下:服務(wù)端收到協(xié)議后,在協(xié)議名后面補(bǔ)充發(fā)送者的ID,然后廣播出去。其他玩家收到協(xié)議后,在客戶端里找到被命中者ID對(duì)應(yīng)的角色,更新其生命狀態(tài)

34、。3命中同步2.客戶端發(fā)送命中同步消息 是否命中敵人是在箭矢的碰撞信息中檢測(cè)到的,所以要在Arrow腳本的OnTriggerStay方法中添加發(fā)送協(xié)議的方法。之前單機(jī)模式下,箭矢命中敵人是直接調(diào)用敵人的受擊方法,現(xiàn)在需要改成命中敵人通知服務(wù)器,由服務(wù)器轉(zhuǎn)發(fā),再讓被命中的客戶端自己調(diào)用受擊方法。 在Arrow腳本中實(shí)現(xiàn)SendHit方法,代碼如下。/*發(fā)送Hit協(xié)議*/publicvoidSendHit(stringdefid,floatdamage)/*構(gòu)建協(xié)議*/ProtocolStrproto=newProtocolStr();proto.AddString(hit);proto.AddS

35、tring(defid);proto.AddFloat(damage);/*發(fā)送協(xié)議*/NetMgr.instance.Send(proto); 3命中同步2.客戶端發(fā)送命中同步消息修改Arrow的OnTriggerStay方法,代碼如下。 /當(dāng)且僅當(dāng)玩家發(fā)出的箭矢在命中其他隊(duì)伍的敵人時(shí),才觸發(fā)命中if(col.gameObject.tag=Archer&=GameMgr.instance.id&BattleManager.instance.listcol.gameO.team!=BattleManager.instance.listsource.na

36、me.team)/發(fā)送命中協(xié)議SendHit(col.gameO,velocity.magnitude); 3命中同步3.服務(wù)端廣播命中同步消息服務(wù)端收到客戶端發(fā)來(lái)的命中信息,然后再?gòu)V播出去。在HandlePlayerMsg中添加Msghit方法,代碼如下。publicvoidMsghit(Playerplayer,ProtocolBaseprotoBase)/*獲取數(shù)值*/ProtocolStrprotocol=(ProtocolStr)protoBase;stringdefid=protocol.GetString(1);floatdamage=protocol.Get

37、Float(2);/*獲取房間*/if(player.tempData.status!=PlayerTempData.Status.Fight)return;Roomroom=player.tempData.room;/*構(gòu)建返回協(xié)議*/ProtocolStrprotocolRet=newProtocolStr();protocolRet.AddString(hit);protocolRet.AddString(player.id);protocolRet.AddString(defid);protocolRet.AddFloat(damage);/*廣播*/room.Broadcast(pr

38、otocolRet); 3命中同步4.客戶端接收命中同步消息在BattleManager腳本的StartBattle方法最底部注冊(cè)監(jiān)聽(tīng),代碼如下。/*受擊協(xié)議*/NetMgr.instance.msgDist.AddListener(hit,RecvHit);3命中同步4.客戶端接收命中同步消息實(shí)現(xiàn)返回協(xié)議方法RecvHit,代碼如下。publicvoidRecvHit(ProtocolBaseprotocol)/*解析協(xié)議*/ProtocolStrproto=(ProtocolStr)protocol;stringattId=proto.GetString(1);stringdefId=pr

39、oto.GetString(2);floatdamage=proto.GetFloat(3);/*查找角色*/if(!list.ContainsKey(attId)Debug.Log(RecvHitattBa=null+attId);return;BattleArcherattBa=listattId;if(!list.ContainsKey(defId)Debug.Log(RecvHitdefBa=null+defId);return;BattleArcherdefBa=listdefId;/*同步*/defBa.archer.BeAttacked(damage);4勝負(fù)判斷1.設(shè)計(jì)協(xié)議玩家

40、在被命中后會(huì)更新生命狀態(tài),減少生命值,當(dāng)生命值低于零時(shí),角色會(huì)死亡,每當(dāng)有角色死亡時(shí)會(huì)向服務(wù)端發(fā)送死亡信息。由于服務(wù)端只需要知道死亡者的ID就可以了,所以死亡協(xié)議沒(méi)有多余的參數(shù)只有協(xié)議名,協(xié)議格式如下:服務(wù)端在接收死亡信息時(shí)會(huì)判斷游戲是否結(jié)束。如果游戲結(jié)束,則判斷勝負(fù)方,然后將戰(zhàn)斗結(jié)果廣播給所有玩家,戰(zhàn)斗結(jié)果協(xié)議需要包含勝利一方的teamID,協(xié)議格式如下:4勝負(fù)判斷2.客戶端發(fā)送死亡消息在Archer腳本中添加SendDie方法,代碼如下。/*發(fā)送死亡協(xié)議*/publicvoidSendDie()/*構(gòu)建協(xié)議*/ProtocolStrproto=newProtocolStr();proto.

41、AddString(die);/*發(fā)送協(xié)議*/NetMgr.instance.Send(proto); 4勝負(fù)判斷2.客戶端發(fā)送死亡消息角色在受擊時(shí)會(huì)判斷是否死亡,如果死亡就發(fā)送死亡協(xié)議,并失去對(duì)角色的控制。修改BeAttacked方法,在生命值小于0時(shí)調(diào)用SendDie方法,代碼如下。/*如果英雄已經(jīng)死亡了*/if(hp=0)alive=false;/*動(dòng)畫(huà)控制*/ anim.SetBool (die,true);anim.speed=1;/如果死亡的是玩家控制的角色if(gameO=GameMgr.instance.id)/*顯示鼠標(biāo)*/Cursor.visible=t

42、rue;/*玩家失去對(duì)角色的控制*/ Component.Destroy (gameObject.GetComponent ();/發(fā)送死亡協(xié)議SendDie(); 4勝負(fù)判斷3.服務(wù)端處理死亡協(xié)議服務(wù)端收到客戶端發(fā)來(lái)的死亡協(xié)議,然后判斷游戲是否結(jié)束。在HandlePlayerMsg中添加Msgdie方法,代碼如下。/*死亡協(xié)議*/publicvoidMsgdie(Playerplayer,ProtocolBaseprotoBase)/修改臨時(shí)數(shù)據(jù)player.tempData.isAlive=false;Console.WriteLine(player.id+死亡);/*判斷游戲是否結(jié)束*/

43、Roomroom=player.tempData.room;room.UpdateWin(); 4勝負(fù)判斷4.服務(wù)端進(jìn)行勝負(fù)判斷在Room中添加勝負(fù)判斷方法IsWin,代碼如下。privateintIsWin()if(status!=Status.Fight)return0;/*統(tǒng)計(jì)雙方存活人數(shù)*/intcount1=0;intcount2=0;foreach(Playerplayerinplayerlist.Values)PlayerTempDatapt=player.tempData;if(pt.team=1&pt.isAlive)count1+;if(pt.team=2&pt.isAli

44、ve)count2+;/*判斷勝利方*/if(count1=0)Console.WriteLine(勝負(fù)已分:隊(duì)伍2獲勝);return2;if(count2=0)Console.WriteLine(勝負(fù)已分:隊(duì)伍1獲勝);return1;/*無(wú)勝方*/return0; 4勝負(fù)判斷5.服務(wù)端發(fā)送勝負(fù)結(jié)果如果勝負(fù)已分,則將勝負(fù)結(jié)果廣播給所有玩家,添加UpdateWin方法,代碼如下。/*游戲結(jié)束判斷*/publicvoidUpdateWin()/*是否勝負(fù)已分*/intisWin=IsWin();if(isWin=0)return;/*構(gòu)建協(xié)議*/ProtocolStrprotocol=newP

45、rotocolStr();protocol.AddString(result);protocol.AddInt(isWin);/*廣播*/Broadcast(protocol);/*解散房間*/lock(playerlist)status=Status.Prepare;4勝負(fù)判斷5.服務(wù)端發(fā)送勝負(fù)結(jié)果/*修改每個(gè)玩家的臨時(shí)數(shù)據(jù)*/foreach(Playerplayerinplayerlist.Values)player.tempData.status=PlayerTempData.Status.None;player.tempData.room=null;player.tempData.he

46、roName=;player.tempData.isAlive=true;/修改戰(zhàn)績(jī)if(player.tempData.team=isWin)player.playerData.win+;elseplayer.playerData.fail+;/*銷毀這個(gè)房間*/RoomMgr.instance.CloseRoom(this); 4勝負(fù)判斷6.客戶端接收勝負(fù)結(jié)果玩家接收到服務(wù)端廣播的result協(xié)議后,彈出勝負(fù)面板,失去對(duì)角色的控制,然后取消之前在戰(zhàn)斗中注冊(cè)的監(jiān)聽(tīng)。在BattleManager腳本的StartBattle方法最底部注冊(cè)監(jiān)聽(tīng),代碼如下。/*接收結(jié)果協(xié)議*/NetMgr.inst

47、ance.msgDist.AddListener(result,RecvResult); 4勝負(fù)判斷6.客戶端接收勝負(fù)結(jié)果實(shí)現(xiàn)返回協(xié)議方法RecvResult,代碼如下。/*接收戰(zhàn)斗結(jié)果回發(fā)*/publicvoidRecvResult(ProtocolBaseprotocol)/*解析協(xié)議*/ProtocolStrproto=(ProtocolStr)protocol;intwinTeam=proto.GetInt(1);/*彈出勝負(fù)面板*/BattleArcherba=listGameMgr.instance.id;if(ba.team=winTeam)PanelMgr.instance.O

48、penPanel(1);elsePanelMgr.instance.OpenPanel(0);/顯示鼠標(biāo)Cursor.visible=true;/玩家失去對(duì)角色的控制Component.Destroy(GameObject.Find(GameMgr.instance.id).GetComponent();4勝負(fù)判斷6.客戶端接收勝負(fù)結(jié)果/*取消戰(zhàn)斗中的監(jiān)聽(tīng)*/NetMgr.instance.msgDist.DelListener(updateunitinfo,RecvUpdateUnitInfo);NetMgr.instance.msgDist.DelListener(hold,RecvHol

49、d);NetMgr.instance.msgDist.DelListener(shoot,RecvShoot);NetMgr.instance.msgDist.DelListener(hit,RecvHit);NetMgr.instance.msgDist.DelListener(result,RecvResult); 5玩家退出1.客戶端注銷賬戶客戶端中途退出有兩種,第一種是在大廳中注銷賬戶,第二種是突然關(guān)閉程序。當(dāng)注銷賬戶時(shí)會(huì)發(fā)送一個(gè)Logout協(xié)議,服務(wù)端需要有Logout協(xié)議的處理方法,在PlayerConnMsg中添加Msglogout方法,代碼如下。/*接收角色主動(dòng)下線*/publ

50、icvoidMsglogout(Connconn,ProtocolBaseprotoBase)if(conn.player!=null)/*處理角色的離線*/conn.player.Logout();else/*關(guān)閉連接*/lock(conn)conn.Close(); 5玩家退出2.服務(wù)端實(shí)現(xiàn)下線無(wú)論是玩家注銷賬戶還是主動(dòng)關(guān)閉程序,最后都會(huì)調(diào)用到Player的Logout方法。Logout方法會(huì)針對(duì)玩家當(dāng)前的狀態(tài)進(jìn)行處理,最后保存數(shù)據(jù),斷開(kāi)連接。當(dāng)玩家在大廳中下線時(shí),不做特殊處理。當(dāng)玩家在匹配中下線時(shí),將玩家從匹配隊(duì)列中移出。當(dāng)玩家在選擇英雄時(shí)下線,則解散房間,計(jì)玩家為逃跑。當(dāng)玩家在戰(zhàn)斗中下

51、線,則計(jì)玩家逃跑,控制的角色立刻死亡,判斷勝負(fù)。代碼如下。/*下線處理*/publicboolLogout()/*如果在戰(zhàn)斗中下線*/if(tempData.status=PlayerTempData.Status.Fight)Roomroom=tempData.room;/戰(zhàn)斗下線處理room.ExitFight(this);/逃跑懲罰room.EscapePunish(this);Console.WriteLine(id+在戰(zhàn)斗中下線);5玩家退出2.服務(wù)端實(shí)現(xiàn)下線/*如果在房間中下線*/elseif(tempData.status=PlayerTempData.Status.Room)Roomroom=tempData.room;room.LeaveRoom(this); /選擇下線處理room.EscapePunish(this); /逃跑懲罰Console.WriteLine(id+在房間中下線);/*如果在匹配中下線*/elseif(tempData.status=PlayerTempData.Status.M

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論