網頁遊戲中PK系統的實現

     在遊戲開發過程當中,寫過一個簡單的PK系統面板,涉及到前端和後端的交互,我將本身製做的流程分享給你們,大概流程是這樣:前端發送PK邀請給後端,後端受到請求後將信息返回給前端處理,先來看下整個流程圖及思路:前端

image

     整個流程如上圖所示,通過服務器和客戶端的幾回交互來肯定PK雙方的狀態及是否能受到攻擊。服務端將要給我五條協議,大概以下:後端

message m_role_pk_invite_tos<29301>[router=role,mod_role_handle]{
   required double                          role_id                 = 1;//邀請PK的對象ID
}
message m_role_pk_invite_toc<29302>{
 required int32     err_code     = 1;//0是已向對方發送邀請,請等待迴應
}
message m_role_pk_info_toc<29304>{
   required string                          invite_name             = 1;//邀請者名稱
   required double                          invite_id                 = 1;//邀請者ID
   required int32                           invite_level           = 1;//邀請者level
   required double                          invite_time          = 1;//計時結束時間戳
}
message m_role_pk_answer_tos<29305>[router=role,mod_role_handle]{
   required int32                          back_type                 = 1;//0爲贊成,1爲拒絕,2爲超時
   required double                          to_id          = 1;//贊成/拒絕/超時的對象
}
message m_role_pk_answer_toc<29306>{
   required int32                          err_code                 = 1;//0爲成功(提示:開始PK)
   required double                          to_id          = 1;     //成功時讀取PK對象ID
}

     其中toc表明服務端發給客戶端的數據,tos表示客戶端發給服務端的消息,他們都是封裝好的數據結構信息,這些都是咱們和後端約定好的協議,通常後端發給前端咱們都會制定一個err_code,它表示該協議是否成功發送到客戶端。服務器

     前端的代碼處理比較簡單,在編碼過程當中,將數據和視圖分別放在不一樣的模塊中,便於管理,在接受邀請後,咱們會給被邀請方一個彈窗顯示並給60秒的時間來處理。重點看下服務端發給客戶端處理的代碼:數據結構

package modules.invitePK {
  /* 五條協議 */
 import proto.m_role_pk_answer_toc;
 import proto.m_role_pk_answer_tos;
 import proto.m_role_pk_info_toc;      
 import proto.m_role_pk_invite_toc;
 import proto.m_role_pk_invite_tos;

 public class InvitePKCase extends BaseModule {

  public function InvitePKCase() {
   super();
  }
  private var invitePKPanel:InvitePKPanel;
  private static var instance:InvitePKCase;

  public static function getInstance():InvitePKCase {
   return instance ||= new InvitePKCase(); //單例模式
  }

  override protected function initListeners():void {
   addMessageListener(ModuleCommand.INVITE_PK, toInvite); //調用偵聽事件邀請PK
   addMessageListener(ModuleCommand.INVITE_ANSWER, toAnswer)  
   addMessageListener(ModuleCommand.INVITE_OPENPANEL, toOpenPanel) //出面板
   /* 監聽服務端發來的數據,包括三條協議 */
   addSocketListener(SocketCommand.ROLE_PK_INFO, onPKInfo);
   addSocketListener(SocketCommand.ROLE_PK_INVITE, onInvite);
   addSocketListener(SocketCommand.ROLE_PK_ANSWER, onAnswer);
  }

  private function toOpenPanel(vo:m_role_pk_info_toc):void {
   invitePKPanel = new InvitePKPanel(vo.invite_name, vo.invite_id, vo.invite_level, vo.invite_time); //new一個模板
   invitePKPanel.durTime = vo.invite_time;
   invitePKPanel.open(); //打開面板
   invitePKPanel.readTime(); //開始計時
  }

  private function onAnswer(vo:m_role_pk_answer_toc):void {
   if (vo.err_code == 0) {
    if (vo.pk_type != 0) {
     FightModule.getInstance().toOpenPanel(vo);//顯示PK雙方的信息
     InvitePKManager.pkRoleID = vo.to_id;
     MangerTime.last_time = 30;   //MangerTime是管理時間類
     MangerTime.endTime(); //讀取時間
    } else {
     InvitePKManager.pkRoleID = 0;
     Dispatcher.dispatch(ModuleCommand.FIGHT_CLOSEPANEL); //發送關閉消息
    }
   } else {
    TopTip.addMouseTipsMsg(ErrorCode.getError(vo.err_code));
   }
  }

  private function toAnswer(back_type:int, id:Number):void {
   var vo:m_role_pk_answer_tos = new m_role_pk_answer_tos();  //發給服務端
   vo.back_type = back_type;
   vo.to_id = id;
   sendSocketMessage(vo);
  }

  private function onPKInfo(vo:m_role_pk_info_toc):void {
   dispatch(ModuleCommand.INVITE_OPENPANEL, vo); //開面板,顯示邀請者的信息
  }

  private function onInvite(vo:m_role_pk_invite_toc):void {
   // 發給客戶端的消息,提示我已經邀請你pk
   if (vo.err_code == 0) {
    TopTip.addMouseTipsMsg("已邀請PK,請等待迴應");  //表示發送成功
   } else {
    TopTip.addMouseTipsMsg(ErrorCode.getError(vo.err_code)); //返回失敗的緣由
   }

  }

  private function toInvite(tarid:Number):void {
   //這裏面有調用者的ID,由客戶端發給服務端
   var vo:m_role_pk_invite_tos = new m_role_pk_invite_tos();
   vo.role_id = tarid;
   sendSocketMessage(vo); //發送消息
  }
 }
}

     上面的MangerTime類主要是用於PK雙方時間的限定,若是在雙方都接受邀請以後30秒內沒有動做,或者30秒有攻擊可是接着停下來沒有繼續攻擊,時間又要從新開始計時,我這裏用一個靜態類來處理:框架

package modules.fight {
import com.managers.Dispatcher;
import com.scene.sceneManager.LoopManager;
import modules.ModuleCommand;
import modules.fight.FightView;
    public class MangerTime {
        public static var last_time:int = 30;  //靜態30秒,每次攻擊玩能夠重置這個時間
        public static function updateEndTime():void {
        last_time--;
        if (last_time < 0) {
        last_time = 0;
        LoopManager.removeFromSceond("updateTime");
        FightView.getInstance().toCloseWindow(); //pk結束,關閉面板
   } 
}
    public static function readTime():void {
    LoopManager.addToSecond("updateTime", updateEndTime);  //啓動一個定時器開始計時
    }
  }
}

     在監聽服務器發過來的fight事件的時候,能夠改變last_time對時間進行重置,加入計時器,30秒到後就能夠關閉雙方的面板,可是必定要注意的是,咱們這裏用到AS3中的字典來存儲函數的名稱,因此在命名的時候必定不要重複命名,否則可能會致使程序運行出錯或者PK雙方只關閉一個面板。ide

     總結:在遇到和服務器交互的時候只須要針對對應協議作出相應的邏輯判斷,代碼分別用模塊化的形式來清晰表達出本身的思想,後面開發的同志看代碼也就不會很困難,遊戲行業的開發速度很是快,有好的框架開發起來速度會很是快,因此平時應該多專研這些面板底層機制是如何實現的,並記錄一些本身的想法。模塊化

相關文章
相關標籤/搜索