flex 聯機遊戲開發 - 中國象棋遊戲:(一)核心邏輯

在開發四國軍棋的遊戲中,通過 flex聯機遊戲開發- 四國軍棋遊戲(五)-提煉棋類開發api,我們提煉出了第一個關於棋類遊戲開發的api-FlexChessAPI,這個api設計的方針就是基於狀態機與事件驅動的flex主要機制,使開發工作簡潔易行。現在,我們第一次使用這個api來開發一款中國象棋遊戲,對一個成熟的開發工作者來說,我相信,你大概只需要半天時間就可以讓這個象棋遊戲運作起來。

現在,我們將中國象棋的邏輯出來。

1)中國象棋由9*10個方格,與四國軍棋不同,棋子本身並無行棋路線,

也就是說我們只需要簡單擴展ipostion 形成posiitonVO類即可

2)中國象棋的棋子本身無大小,但每個子有自己的行棋路線,吃子的方式是目標子正好處於該子的行棋路線上,另外,其它的子的行爲會對目標子的行棋路線造成影響。

也就是說,不論是移動,吃子等,我們都無法立即獲得該子的可移動路線,只有等對方行完棋後才能確定行棋路線,所以我們選擇的計算行棋路線的方式應該定位在 選中源棋子的時候。

下面,我設計一個ChinaChessHelp類,類中的所有方法與變量都是靜態類。

2.1 列出所有棋子,(注意,紅方的相與黑方的象不但顯示名稱不同,行棋路線也不同,這樣,我就將他們處理成兩上不同的棋子),至於棋子的值,並不重要,只是一個區別作用。

  //棋子
  public static const PIECE_RED_CHE:int=56;
  public static const QIZHI_RED_MA:int=57;
  public static const QIZHI_RED_XIAN:int=58;
  public static const QIZHI_RED_SHI:int=59;
  public static const QIZHI_RED_JIAN:int=60;
  public static const QIZHI_RED_BING:int=55;
  public static const QIZHI_RED_PAO:int=54;
  
  public static const PIECE_BLACK_CHE:int=156;
  public static const QIZHI_BLACK_MA:int=157;
  public static const QIZHI_BLACK_XIAN:int=158;
  public static const QIZHI_BLACK_SHI:int=159;
  public static const QIZHI_BLACK_SUAN:int=160;
  public static const QIZHI_BLACK_ZHU:int=155;
  public static const QIZHI_BLACK_PAO:int=154;

2.2 設計棋子的移動路線,這是中國象棋最核心的邏輯。請參與這個圖,我設計出每個子的行棋路線,對於一些行棋路線有限而且透明的棋子,我直接索引出值(如士,象,師),對一些行棋路線不確定的棋子,我們計算出他的行棋路線,如車,馬,炮等。所有的索引請參照下面這個圖像(棋盤的繪製我在下一節將講到)。

2.2.1 函數 initMoveRedJian():ArrayCollection

將的行棋路線 用switch case來描述就是如下

/**
   * 紅方將的行棋路線
   * @param posindex
   * @return
   *
   */  
  public static function initMoveRedJian(posindex:int):ArrayCollection{
   var temp:ArrayCollection;
   switch(posindex){
    case 3:
     temp=new ArrayCollection([4,12]);
     break;
    case 4:
     temp=new ArrayCollection([3,5,13]);
     break;
    case 5:
     temp=new ArrayCollection([4,14]);
     break;
    case 12:
     temp=new ArrayCollection([3,13,21]);
     break;
    case 13:
     temp=new ArrayCollection([4,12,14,22]);
     break;
    case 14:
     temp=new ArrayCollection([5,13,23]);
     break;
    case 21:
     temp=new ArrayCollection([12,22]);
     break;
    case 22:
     temp=new ArrayCollection([13,21,23]);
     break;
    case 23:
     temp=new ArrayCollection([14,22]);
     break;
    default:
     break;
   }
   return temp;
  }

 

2.2.2 函數 initMoveRedShi():ArrayCollection

士的行棋路線 用switch case來描述就是如下

/**
   * 紅方士的行棋路線
   * @param posindex
   * @return
   *
   */  
  public static function initMoveRedShi(posindex:int):ArrayCollection{
   var temp:ArrayCollection;
   switch(posindex){
    case 3:
     temp=new ArrayCollection([13]);
     break;
    case 5:
     temp=new ArrayCollection([13]);
     break;
    case 13:
     temp=new ArrayCollection([3,5,21,23]);
     break;
    case 21:
     temp=new ArrayCollection([13]);
     break;
    case 23:
     temp=new ArrayCollection([13]);
     break;
    default:
     break;
   }
   return temp;
  }

邏輯是這樣,但上面的寫法是錯誤的,flex中當數組只有一個元素時,最好不要直接用arraycollection進行初始化。您可以修改一下:)

2.2.3 紅方象的行棋路線 initMoveRedXian

/**
   * 紅方象的行棋路線
   * 注意蹩腳路線。
   * @param posindex
   * @return
   *
   */ 


  public static function initMoveRedXian(posindex:int,pieceMap:HashMap):ArrayCollection{
   var temp:ArrayCollection=new ArrayCollection();
   switch(posindex){
    case 2:
     if ((pieceMap.get(10) as PieceVO).deskpos==-1)
      temp.addItem(18);
     if ((pieceMap.get(12) as PieceVO).deskpos==-1)
      temp.addItem(22);
     break;
    case 6:
     if ((pieceMap.get(14) as PieceVO).deskpos==-1)
      temp.addItem(22);
     if ((pieceMap.get(16) as PieceVO).deskpos==-1)
      temp.addItem(26);
     break;
    case 18:
     if ((pieceMap.get(10) as PieceVO).deskpos==-1)
      temp.addItem(2);
     if ((pieceMap.get(28) as PieceVO).deskpos==-1)
      temp.addItem(38);
     break;
    case 22:
     if ((pieceMap.get(12) as PieceVO).deskpos==-1)
      temp.addItem(2);
     if ((pieceMap.get(14) as PieceVO).deskpos==-1)
      temp.addItem(6);
     if ((pieceMap.get(30) as PieceVO).deskpos==-1)
      temp.addItem(38);
     if ((pieceMap.get(32) as PieceVO).deskpos==-1)
      temp.addItem(42);
     break;
    case 26:
     if ((pieceMap.get(16) as PieceVO).deskpos==-1)
      temp.addItem(6);
     if ((pieceMap.get(34) as PieceVO).deskpos==-1)
      temp.addItem(42);
     
     break;
    case 38:
     if ((pieceMap.get(28) as PieceVO).deskpos==-1)
      temp.addItem(18);
     if ((pieceMap.get(30) as PieceVO).deskpos==-1)
      temp.addItem(22);
     break;
    case 42:
     if ((pieceMap.get(32) as PieceVO).deskpos==-1)
      temp.addItem(22);
     if ((pieceMap.get(34) as PieceVO).deskpos==-1)
      temp.addItem(26);
     break;
    default:
     break;
   }
   return temp;
  }

2.2.4 紅方兵的行棋路線 public static function initMoveRedBing():ArrayCollection

注意的是,並沒有過河時,只能向前走,過河後則可以有三個位置可以走。

利用posindex的值進行判斷

/**
   * 紅方並的行棋路線
   * @param posindex
   * @return
   *
   */ 
  public static function initMoveRedBing(posindex:int,pieceMap:HashMap):ArrayCollection{
   var temp:ArrayCollection=new ArrayCollection();
   if (posindex%9-1>=0&&posindex>=45) temp.addItem(posindex-1);
   if (posindex%9+1<9&&posindex>=45) temp.addItem(posindex+1);
   if (posindex+9<90) temp.addItem(posindex+9);
   return temp;
  }

2.2.5 馬的行棋路線 public static function initMoveRedBing():ArrayCollection

車,馬,炮屬於自由移動棋子,對紅黑雙方是對等存在,所以可以使用公用函數進行處理。

馬的遊戲邏輯主要就是判斷目標點位是否在棋盤中以及是不是有蹩腳點位存在。

 /**
   * 馬的行棋路線
   * 每個馬有八個行棋位置,有四個蹩腳點位,
   * @param posindex
   * @return
   *
   */  
  public static function initMoveMa(posindex:int,pieceMap:HashMap):ArrayCollection{
   var temp:ArrayCollection=new ArrayCollection();
   
   //左方向
   if (posindex%9-2>=0) {
     if ((pieceMap.get(posindex-1) as PieceVO).deskpos==-1)
     {
      if ((posindex-11)>=0)
      {
       temp.addItem(posindex-11);
      }
      if ((posindex+7)<89)
      {
       temp.addItem(posindex+7);
      }
      
     }
   }
   //右方向
   if (posindex%9+2<9) {
    
    if ((pieceMap.get(posindex+1) as PieceVO).deskpos==-1)
    {
     if ((posindex-7)>=0)
     {
      temp.addItem(posindex-7);
     }
     if ((posindex+11)<89)
     {
      temp.addItem(posindex+11);
     }
     
    }
   }
   //上方向
   if (posindex-18>=0) {
    if ((pieceMap.get(posindex-9) as PieceVO).deskpos==-1)
    {
     if ((posindex-19)%9<posindex%9)
     {
      temp.addItem(posindex-19);
     }
     if ((posindex-17)%9>posindex%9)
     {
      temp.addItem(posindex-17);
     }
     
    }
   }
   //下方向
   if (posindex+18<90) {
    if ((posindex+19)%9>posindex%9)
    {
     temp.addItem(posindex+19);
    }
    if ((posindex+17)%9<posindex%9)
    {
     temp.addItem(posindex+17);
    }
   }
   return temp;
  }

 

2.2.6 車的行棋路線

車的行棋邏輯就是查看四個方向是否有空的位置,如果找到一個棋子,則結束尋找,將當前找到的棋子也加入索引。

 /**
   * 車的行棋路線
   * @param posindex
   * @return
   *
   */  
  public static function initMoveChe(posindex:int,pieceMap:HashMap):ArrayCollection{
   var temp:ArrayCollection=new ArrayCollection();
   //模方向
   for (var xr:int=posindex%9+1;xr<9;xr++)
   {
    if ((pieceMap.get(posindex+xr-posindex%9) as PieceVO).deskpos==-1)
    {
     temp.addItem(posindex+xr-posindex%9);
    }
    else
    {
     //將找到最後一子的位置也加入
     temp.addItem(posindex+xr-posindex%9);
     break;
    }
   }
   for (var xl:int=posindex%9-1;xl>=0;xl--)
   {
    if ((pieceMap.get(posindex+xl-posindex%9) as PieceVO).deskpos==-1)
    {
     temp.addItem(posindex+xl-posindex%9);
    }
    else
    {
     temp.addItem(posindex+xl-posindex%9);
     break;
    }
   }
   //豎方向
   for (var yb:int=Math.floor(posindex/9)+1;yb<10;yb++)
   {
    if ((pieceMap.get(posindex+9*(yb-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
    {
     temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
    }
    else
    {
     temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
     break;
    }
   }
   for (var yt:int=Math.floor(posindex/9)-1;yt>=0;yt--)
   {
    if ((pieceMap.get(posindex+9*(yt-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
    {
     temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
    }
    else
    {
     temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
     break;
    }
   }
   return temp;
  }

 

2.2.7 炮的行棋路線

炮的行棋路線相對複雜些,不過也很好處理,基本情況與車相同,只不過當你在某一方向找到第一個棋子後,設置一個判斷,判斷爲找到一個棋子後,對空餘的位置不再添加,則再找第二個棋子,如果找到第二個棋子,將第二個棋子加入索引

/**
   * 炮的行棋路線
   * @param posindex
   * @return
   *
   */  
  public static function initMovePao(posindex:int,pieceMap:HashMap):ArrayCollection{
   var temp:ArrayCollection=new ArrayCollection();
   
   //模方向
   var findOne:Boolean=false;
   for (var xr:int=posindex%9+1;xr<9;xr++)
   {
    if ((pieceMap.get(posindex+xr-posindex%9) as PieceVO).deskpos==-1)
    {
     if (!findOne)
      temp.addItem(posindex+xr-posindex%9);
    }
    else
    {
     if (!findOne)
     {
      findOne=true;
      continue;
     }
     else
     {
      //將找到子的下一子的位置也加入
      temp.addItem(posindex+xr-posindex%9);
      break;
     }
     
    }
   }
   findOne=false;
   for (var xl:int=posindex%9-1;xl>=0;xl--)
   {
    if ((pieceMap.get(posindex+xl-posindex%9) as PieceVO).deskpos==-1)
    {
     if (!findOne)
      temp.addItem(posindex+xl-posindex%9);
    }
    else
    {
     if (!findOne)
     {
      findOne=true;
      continue;
     }
     else
     {
      //將找到子的下一子的位置也加入
      temp.addItem(posindex+xl-posindex%9);
      break;
     }
     
    }
   }
   //豎方向
   findOne=false;
   for (var yb:int=Math.floor(posindex/9)+1;yb<10;yb++)
   {
    if ((pieceMap.get(posindex+9*(yb-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
    {
     if (!findOne)
      temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
    }
    else
    {
     if (!findOne)
     {
      findOne=true;
      continue;
     }
     else
     {
      //將找到子的下一子的位置也加入
      temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
      break;
     }
     
    }
   }
   findOne=false;
   for (var yt:int=Math.floor(posindex/9)-1;yt>=0;yt--)
   {
    if ((pieceMap.get(posindex+9*(yt-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
    {
     if (!findOne)
      temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
    }
    else
    {
     if (!findOne)
     {
      findOne=true;
      continue;
     }
     else
     {
      //將找到子的下一子的位置也加入
      temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
      break;
     }
     
    }
   }
   return temp;
  }

3)中國象棋的遊戲控制引擎與四國軍棋並無太大差異,我們在擴展 BaseGameEngine 後,只需要覆寫 CheckWin()方法,就基本可以完成大量的工作。當然,別忘了棋盤不家個初始佈局,我們只需要設計一個靜態佈局與一個初始化方法即可。

 //默認的棋盤佈局
  private const DEFAULT_LAYOUT:Array=[56,57,58,59,60,59,58,57,56,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,-1,-1,-1,-1,-1,54,-1,55,-1,55,-1,55,-1,55,-1,55,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,155,-1,155,-1,155,-1,155,-1,155,-1,154,-1,-1,-1,-1,-1,154,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,156,157,158,159,160,159,158,157,156];

 

public function initLayout():void{
   for (var i:int=0;i<this.DEFAULT_LAYOUT.length;i++)
   {
    var pieceVO:PieceVO=pieceMap.get(i) as PieceVO;
    pieceVO.value=DEFAULT_LAYOUT[i];
    if (int(DEFAULT_LAYOUT[i])>0&&int(DEFAULT_LAYOUT[i])<100)
    {
     pieceVO.deskpos=getNextPlayer(1).deskpos;
    }
    else if (int(DEFAULT_LAYOUT[i])>=100)
    {
     pieceVO.deskpos=currentDeskpos;
    }
   }
  }

在完成以上這些邏輯工作後,得到的結果就是下面這個,這個是點擊炮後我們可以清楚地看到行棋路線索引。

 

 

核心邏輯基本就是這些,在這個寒冷的冬天裏,我打算利用這些時間開發與優化一些有趣的棋牌類遊戲,我的下一個目標是扎金花遊戲,這是一個牌類遊戲,我打算接着寫一個flexcardapi,當然,本文的下一節我將提供中國象棋的擴展類的設計與顯示設計。如果時間允許的話,會很快,當然,如果您是一名flex開發者,您也可以直接給我發消息,讓您來完成下面的開發,我會把已經完成的設計工作教給你,您也可以學會如何使用這個api,我相信,您會找到樂趣的,您也可以開發一些更簡單或複雜的遊戲,如乖三棋,動物棋,或者跳棋。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章