flex 联机游戏开发 - 四国军棋游戏:(三) 核心类

通过前面的练习 flex 联机游戏开发 - 四国军棋游戏:(二)棋盘棋子 我们已经成功地用不到200行的代码绘制出了一个漂亮的棋盘,现在,我们开始进入游戏的核心类设计阶段。四国军棋的游戏逻辑还是比较复杂的,棋子在布局,游戏阶段有不同的可移动位置,棋子的位置也有自己的可移动位置,工并可以到处飞,还有铁道等,当然,设计者通过不同的渠道都可以达到相同的设计目标,主要看你设计的目标及对性能的要求。在开始设计之前,我先来说说flex的坏话

一)利用flex设计的利与弊

1.1)坏处

1)flex暂时还很难在没有fms支持的情况下实现双工通讯,这与silverlight成熟的双工通讯机制比还是有点不足,当然,也并不全是坏事,在下棋的时候加上聊天,双工通讯的开销也是挺吓人的。 在没有双工通讯的基础上,我们只能通过定时期不断的获得服务器端的数据进行更新

2) flex暂时还没有比较完善的集合类,它仅提供了一个arraycollection及xmlcollection类供开发者使用,我们不得不使用一些第三方或自己开发的集合类来完善功能,比如hashmap,这总是应该有的一个集合类吧。当然,作为一个plug in ,adobe也是挺痛苦的,类库太大方便了开发者,就苦了消费者。当年的java swing  直接将 java applet 送入了死亡通道,前车之鉴嘛,我估计最终仍旧是消费者战胜开发者。

3)图形绘制中没有drawsting的功能,而且就算将来有,对中文字体的支持估计也够呛,所以,你只能自己写一个类似于label的uid类或者直接用label类来显示中文文本。这无疑增大系统的开销。

1.2)好处

1)良好的ui设计,通过flex绘制出来的图形本身已经比较漂亮,当你加入一些简单的组件的效果,滤镜时就更漂亮了,而所有这些,开销并不算太大。在讲究用户体验的今天,这些还是相当诱人的。

这是设计的一个全局位置图。仅在棋盘中绑定一些label,label加上一些效果就行了,几行代码。sg3_1

2)flex简单易学,我从java,c#转头来做这个游戏似乎只看了一本书,书名叫“flex 4-一学就会”,所以,如果你是一位java,c#程序员,不要有太多的顾虑。另外,flex类似于silverlight的绑定机制,事件冒泡模式使设计开发变得更有想象力(当然,想象力太好也可能把事情越弄越复杂)s

3)所有好处好象最终只围绕这个好处,那就是 flash player拥有全世界无人能敌的98%的装机量,而且,直接延伸到android,iphone。还有什么比这更让一个游戏开发者羡慕。。。

好了,聊完了上面的这些内容,让我们来干些实事

二)全局设计考虑

1) 你可以从任何一个方向来开始这个程序,对老练的程序员来算,只要你有头脑,似乎并不需要太多的经验,但是你首先得确定方向,本程序里,我开发的首先是一个联机,然后才是游戏,对于联机游戏,有必引入adobe的一种设计模式 cairngoarm,似乎可以将事情变得简单一点。

2)作为联机游戏,你得时时考虑服务器的开销,在本程序里,服务器需要什么,他只需要一个数组标识三个内容(位置,玩家,棋子),算起来一共只要6个字节,加上129个位置,最多也不超过1k的传输内容,真是令人惊讶。没开发的时候,我以为要传输的内容很多呐。所以,我决定从自顶向下的开发这个游戏。就是先设计与服务器交互的内容 GameEngine,然后再回头来设计每个类。

3)需要设计什么类,首先是位置需要有个类 PositionVO,然后棋子应该是最主要的类QizhiVO,位置应该是棋子的成员,为什么棋子不是位置的成员?(原因:(有没有没有位置的棋子?当然没有;有没有没有棋子的位置?当然有),还要设计一个玩家的类,玩家在一张桌子上有一个位置,我们就按顺时针方向设计为(0,1,2,3)吧。这也是棋子的成员。似乎就没什么要考虑了的吧。

好了,现在我们来做四国军棋游戏的逻辑部分,一些轻松的工作,设计自己的第一个类,常量助辅类 Enum,类里的元素相信你一看就明白;

 

package com.boyiju.game.siguo.util
{
	/**
	 * 四国军模可能用到的常量值 
	 * @author Administrator
	 * 
	 */	
	public class Enum
	{
		//棋局状态
		public static const GAME_LAYOUT:int=0;//布局
		public static const GAME_WAIT:int=1;//完成布局,等待棋它玩家
		public static const GAME_PLAYING:int=2;//游戏中
		public static const GAME_END:int=3;//游戏结束
		
		//玩家颜色
		public static const COLOR_PLAYER_BOTTOM:int=0X34699d;//下
		public static const COLOR_PLAYER_RIGHT:int=0Xd86c00;//右
		public static const COLOR_PLAYER_TOP:int=0X8f449f;//上
		public static const COLOR_PLAYER_LEFT:int=0X709c00;//左
		
		//棋子
		public static const QIZHI_SINING:int=40;//司令
		public static const QIZHI_JUNZHANG:int=39;
		public static const QIZHI_SHIZHANG:int=38;
		public static const QIZHI_LVZHANG:int=37;
		public static const QIZHI_TUANZHANG:int=36;
		public static const QIZHI_YINGZHANG:int=35;
		public static const QIZHI_LIANGZHANG:int=34;
		public static const QIZHI_PAIZHANG:int=33;
		public static const QIZHI_GONGBING:int=32;
		public static const QIZHI_DILEI:int=31;
		public static const QIZHI_JUQI:int=30; //最小为军棋,谁都可以吃
		public static const QIZHI_ZHADAN:int=100;
		
		
		//可视
		public static const QIZHI_STATE_NONE:int=-1;//不可见
		public static const QIZHI_STATE_SELF:int=0; //自己可见
		public static const QIZHI_STATE_TEAM:int=1;//队友可见
		public static const QIZHI_STATE_ALL:int=2;//全部可见
		
		//位置类型		
		public static const POSITION_NORAML:int=0;
		public static const POSITION_YING:int=1; //行营
		public static const POSITION_DABENYING:int=2; //大本营
		
		//布局移动
		public static const LAYOUT_MOVE_ALL:int=0;
		public static const LAYOUT_MOVE_LAST_TWO:int=1;//地雷只能在后两排
		public static const LAYOUT_MOVE_NOT_FRONT:int=2;//炸弹不能在前排铁道上
		public static const LAYOUT_MOVE_JUNQI:int=3;//军棋只能在大本营内
		
		
		
	}
}

 

三,核心类设计

3.1 Position类

棋盘由4个layout与一个centerarea组成,每个layout有30个位置,包括25个棋子位置与5个行营位置,centerarea包括9个行棋位置,棋盘共129个位置。位置的标识如上图所示,当用户进入棋局时,他的布局的索引就是 (30*玩家位置+具体位置)。这个逻辑就相当清楚了。

下面看类的具体内容,我将解释直接写到了类内部。

 

package com.boyiju.game.siguo.vo
{

	import com.boyiju.game.siguo.util.Enum;
	
	import mx.collections.ArrayCollection;
	/**
	 * 位置类,每个棋盘共129个位置,每个位置有不同的可移动目标,类型,编号等 
	 * 每个位置将对应一个棋子类
	 */	
	[Bindable]
	public class PositionVO
	{
		/**
		 *常量:可以直接移动的位置的集合,共30个 
		 */		
		public static const MOVE_ONE_STEP:Array=[new Array(1,6,7),new Array(0,2,7),new Array(1,3,7,8,9),new Array(2,4,9),new Array(3,5,9,10),new Array(4,11),new Array(0,12,7),new Array(0,1,2,6,8,12,13,14),new Array(2,7,9,14),new Array(2,3,4,8,10,14,15,16),new Array(4,9,11,16),null,new Array(6,7,13,18,19),new Array(7,12,14,19),new Array(7,8,9,13,15,19,20,21),new Array(9,14,16,21),new Array(9,10,15,17,21,22),new Array(11,16,23),new Array(12,19,24),new Array(12,13,14,18,20,24,25,26),new Array(14,19,21,26),new Array(14,15,16,20,22,26,27,28),new Array(16,21,23,28),null,new Array(18,19,25),new Array(19,24,26),new Array(19,20,21,25,27),new Array(21,26,28),new Array(21,22,27,29),new Array(23,28)];
		
		/**
		 *常量:铁道线上的位置集合,横7条,竖七条,外加拐弯的4条,共18条 
		 */		
		public static const MOVE_RAIL:Array=[new Array(118,112,106,100,94),new Array(114,108,102,96,90),new Array(4,3,2,1,0,122,121,120,84,85,86,87,88),new Array(12,125,124,123,72),new Array(28,27,26,25,24,128,127,126,60,61,62,63,64),new Array(30,36,42,48,54),new Array(34,40,46,52,58),new Array(28,22,16,10,4),new Array(24,18,12,6,0),new Array(34,33,32,31,30,128,125,122,114,115,116,117,118),new Array(42,127,124,121,102),new Array(2,7,9,14),new Array(58,57,56,55,54,126,123,120,90,91,92,93,94),new Array(4,9,11,16),new Array(60,66,72,78,84),new Array(64,70,76,82,88)];

		
		private var _index:int=-1;
		/**
		 *棋子位置的类型 如营或大本营 
		 */		
		public var type:int;
		
		/**
		 *棋子绘制的开始位置 
		 */		
		public var startX:int;
		public var startY:int;
		
		
		/**
		 *可移动位置的索引 
		 */		
		public var moveAC:ArrayCollection=new ArrayCollection();
		public var moveRailAC:ArrayCollection=new ArrayCollection();
		
		public function get index():int
		{
			return _index;
		}
		/**
		 *位置的索引,作为一个联机游戏,用户在桌子上的位置就是索引的,在进入游戏时,索引已经固定(0-129)。 
		 * 通过索引可以得到可以移动的全部目标子位,棋子的类型,布局的位置索引(0-30)
		 * @param value
		 * 
		 */
		public function set index(value:int):void
		{
			_index = value;
			var layoutindex:int = value%30;
			if (_index<120)
			{
				startX=Math.floor(layoutindex/6)*37.5+5;
				startY=Math.floor(layoutindex%6)*30+10;	
			}
			else
			{
				startX=Math.floor(layoutindex/3)*75+7.5;
				startY=Math.floor(layoutindex%3)*75+7.5;	
			}
			type=getType(layoutindex);
			initMoveAC(layoutindex);
			initMoveRoad(index);
		}
		/**
		 *可以直接移动的子位,不需要判断中间是否有间隔 
		 * @param layoutindex
		 * 
		 */		
		private function initMoveAC(layoutindex:int):void
		{
			moveAC.removeAll();
			var tempAC:ArrayCollection=new ArrayCollection(MOVE_ONE_STEP[layoutindex]);
			moveAC.addAll(tempAC);
			var basecount:int=_index-layoutindex;
			if (moveAC.length>0)
			{
				for (var i2:int=0;i2<moveAC.length;i2++)
				{
					moveAC[i2]=moveAC[i2]+basecount;
				}
			}
			
		}
		/**
		 *铁道线上的位置索引,如果该子包括在线路中,则将铁路放到索引中。 
		 * @param index
		 * 
		 */		
		private function initMoveRoad(index:int):void{
			moveRailAC.removeAll();
			for (var i:int=0;i<MOVE_RAIL.length;i++)
			{
				if (MOVE_RAIL[i].indexOf(index)>=0)
				{
					var tempAC:ArrayCollection=new ArrayCollection(MOVE_RAIL[i]);
					if (tempAC.contains(_index))
					{
						moveRailAC.addItem(tempAC);
					}
				}
			}
		}
		/**
		 *获得当前位置的类型,如棋,大本营,行营等。
		 * @param layoutindex
		 * @return 
		 * 
		 */
		private function getType(layoutindex:int):int{
			var type:int;
			if (layoutindex==7||layoutindex==9||layoutindex==14||layoutindex==19||layoutindex==21)
			{
				type=Enum.POSITION_YING;
			}
			else if (layoutindex==11||layoutindex==23)
			{
				type=Enum.POSITION_DABENYING;
			}
			else
			{
				type=Enum.POSITION_NORAML;
			}
			return type;
		}

	}
}

 

3.2 QizhiVO类

棋子是棋局的基本组成部分,在布局阶段,我们会为用户在除行营外的位置上放置一些默认的棋子作为初始值,一共25个,也就是说,一个棋局只可能有100个棋子,并且会慢慢减小。现在,我们就来描述具体的棋子类。棋子的核实属性,也就是与服务器进行交互的只有3个,位置,值,与玩家,扩展显示的有一些,如名称,背景,位置的起始值等。棋子的方法包括 与其它棋子比较大小,移动到目标位置,与目标位置的棋子碰撞等。现在,我们围绕这个设计棋子类。

package com.boyiju.game.siguo.vo
{
	import asds.map.HashMap;
	
	import com.boyiju.game.siguo.components.Qizhi;
	import com.boyiju.game.siguo.util.Enum;
	
	import mx.collections.ArrayCollection;
	
	/**
	 *棋子类,每个棋子核心数值仅包括棋子的值,棋子的位置,棋子是否显示与棋子的玩家,
	 * 其它的辅助值主要用于交互与显示,将通过核心值获得并可进行绑定显示 
	 */	
	[Bindable]
	public class QizhiVO
	{
		private var _value:int=-1;
		private var _deskpos:int=-1;			
		private var _display:int=-1;
	
		public var positionVO:PositionVO;
		public var name:String;
		public var bgColor:int;
		public var layoutMoveType:int;
		
		
		public function get display():int
		{
			return _display;
		}
		
		public function set display(value:int):void
		{
			_display = value;
		}
		
		public function get deskpos():int
		{
			return _deskpos;
		}
		
		
		public function set deskpos(value:int):void
		{
			_deskpos = value;
			this.bgColor=getColor(value);
		}
		
		public function get value():int
		{
			return _value;
		}
		
		public function set value(value:int):void
		{
			_value = value;
			this.name=getQizhiName(value);
			this.layoutMoveType=getLayoutMoveType(value);
		}

		private function isTeam(deskpos:int):Boolean
		{
			var teamdeskpos:int=(this.deskpos+2)%4;
			return deskpos==teamdeskpos;
		}
		/**
		 *获得棋子的显示名称,与棋子的显示类进行绑定 
		 * @param value
		 * @return 
		 * 
		 */		
		private function getQizhiName(value:int):String{
			if (value==40) return "司令";
			if (value==39) return "军长";
			if (value==38) return "师长";
			if (value==37) return "旅长";
			if (value==36) return "团长";
			if (value==35) return "营长";
			if (value==34) return "连长";
			if (value==33) return "排长";
			if (value==32) return "工兵";
			if (value==31) return "地雷";
			if (value==30) return "军棋";
			if (value==100) return "炸弹";
			return "";
		}
		/**
		 *棋子的颜色,通过棋子的玩家获得 
		 * @param player
		 * 玩家
		 * @return 
		 * 颜色值
		 * 
		 */		
		private function getColor(player:int):int{
			if (player==0) return Enum.COLOR_PLAYER_BOTTOM;
			else if(player==1) return Enum.COLOR_PLAYER_RIGHT;
			else if (player==2) return Enum.COLOR_PLAYER_TOP;
			else if (player==3) return Enum.COLOR_PLAYER_LEFT;
			return 0x000000;
		}
		/**
		 * 棋子本身在布局阶段的移动限制 
		 * @param value 棋子的值
		 * @return 
		 * 
		 */		
		private function getLayoutMoveType(value:int):int{
			
			if (value==Enum.QIZHI_GONGBING) return Enum.LAYOUT_MOVE_LAST_TWO;
			if (value==Enum.QIZHI_ZHADAN) return Enum.LAYOUT_MOVE_NOT_FRONT;
			if (value==Enum.QIZHI_DILEI) return Enum.LAYOUT_MOVE_JUNQI;
			return Enum.LAYOUT_MOVE_ALL;
		}
		
		/**
		 * 与目标棋子比较大小 
		 * @param target
		 * @return 
		 * 
		 */		
		public function Compare(target:QizhiVO):int
		{
			if (this.value==Enum.QIZHI_ZHADAN||target.value==Enum.QIZHI_ZHADAN||this.value==target.value) 
			{
				trace("很壮烈,您的 "+this.name+" 与敌人的 "+target.name+" 同归于尽");
				return 0;
			}
			if (target.value==Enum.QIZHI_DILEI&&this.value!=Enum.QIZHI_GONGBING||this.value<target.value)
			{
				trace("很悲剧,您的 "+this.name+" 被敌人的 "+target.name+" 吃掉了");
				
				return -1;
			}
			if (this.value>target.value) 
			{
				trace("很爽,您的 "+this.name+" 吃掉了敌人的 "+target.name);
				return 1;
			}
			return 1;
		}
		
		/**
		 *布局阶段与目标棋子交换 
		 * @param target
		 * 
		 */		
		public function exchange(target:QizhiVO):void
		{
			if (target==null) return;
			if (target.value==-1) return;
			if (target.deskpos!=this.deskpos) return;
			
			//军棋只能放大本营
			if (this.layoutMoveType==Enum.LAYOUT_MOVE_JUNQI)
			{
				if (target.positionVO.index==11)
				{
					
				}else if (target.positionVO.index==23)
				{
					
				}
				else
					return;
			}
			if (target.layoutMoveType==Enum.LAYOUT_MOVE_JUNQI)
			{
				if (this.positionVO.index==11)
				{
					
				}else if (this.positionVO.index==23)
				{
					
				}
				else
					return;
			}
			//地雷只能放在后两排
			if (this.layoutMoveType==Enum.LAYOUT_MOVE_LAST_TWO)
			{
				if (target.positionVO.index%6<4) return;
			}
			if (target.layoutMoveType==Enum.LAYOUT_MOVE_LAST_TWO)
			{
				if (this.positionVO.index%6<4) return;
			}
			//炸弹不能放在第一排三个位置
			if (this.layoutMoveType==Enum.LAYOUT_MOVE_NOT_FRONT)
			{
				if (target.positionVO.index==0||target.positionVO.index==12||target.positionVO.index==24) return;
			}
			if (target.layoutMoveType==Enum.LAYOUT_MOVE_NOT_FRONT)
			{
				if (this.positionVO.index==0||this.positionVO.index==12||this.positionVO.index==24) return;
			}
			var temp:int=target.value;
			target.value=this.value;
			this.value=temp;
		}
		
		/**
		 * 可否移动到目标位置,主要包括棋子的可移动性,棋子的移动目标值,目标位置的内容等。
		 * @param targetPos
		 * @param qizhiMap
		 * @return 
		 * 
		 */		
		public function canMoveTo(targetPos:PositionVO,qizhiMap:HashMap):Boolean{
			
			//位置无法移动
			if (this.positionVO.moveAC.length==0||this.value==Enum.QIZHI_DILEI||this.value==Enum.QIZHI_JUQI) 
			{
				trace("该位置无法移动:"+this.positionVO.index);
				return false;
			}
			//目标位置不在可移动区内
			if (!this.positionVO.moveAC.contains(targetPos.index)) 
			{
				if (this.positionVO.moveRailAC.length==0){
					trace(targetPos.index+" 不在该位置的可移动路径内:"+this.positionVO.index);
					return false;
					
				}
				for each (var railAC:ArrayCollection in this.positionVO.moveRailAC)
				{
						
						var targetindex:int=railAC.getItemIndex(targetPos.index);
						//目标棋子不在铁路中
						if (targetindex==-1) continue;
						//目标棋子在铁路中.再找原始棋子的位置
						var sourceindex:int=railAC.getItemIndex(this.positionVO.index);
						//从原始棋子到目标棋子的通路中没有其它子
						
						if (sourceindex>targetindex)
						{
							for(var i:int=targetindex+1;i<sourceindex;i++)
							{
								//到达目标区的通路有其它的棋子
								var qizhiVO:QizhiVO=qizhiMap.get(railAC.getItemAt(i)) as QizhiVO;
								if (qizhiVO.value!=-1)
								{
									trace("路径不通:"+qizhiVO.positionVO.index+" 有子 "+qizhiVO.name);					return false;
								}
								trace("经过:"+qizhiVO.positionVO.index);
								
								
							}
							
						}
						else
						{
							for(var j:int=sourceindex+1;j<targetindex;j++)
							{
								//到达目标区的通路有其它的棋子
								var qizhiVO2:QizhiVO=qizhiMap.get(railAC.getItemAt(j)) as QizhiVO;
								if (qizhiVO2.value!=-1)
								{
									trace("路径不通:"+qizhiVO2.positionVO.index+" 有子 "+qizhiVO2.name);
									return false;
								}
								trace("经过:"+qizhiVO2.positionVO.index);
								
							}
							
						}
						trace(this.name+" 从 "+this.positionVO.index+ " 移动至:"+targetPos.index);
						return true;
						
				}
					
			}
			
			trace(this.name+" 从 "+this.positionVO.index+ " 移动至:"+targetPos.index);
			return true;
			
		}
		
		/**
		 * 与目标棋子碰撞 
		 * @param target
		 * @return 
		 * 
		 */		
		public function eat(target:QizhiVO,qizhiMap:HashMap):int{
			//不能吃自己的子
			if (target==null)
			{
				return -6;
			}
			if (target.value==-1)
			{
				trace( "目标位置无棋子");
				return -5;
			}
			if (target.deskpos==this.deskpos)
			{
				trace( "不能吃自己的子");
				
				return -4;
			}
			//不能吃队友的子
			if (isTeam(target.deskpos))
			{
				trace( "位于"+target.positionVO.index+" 的棋子是您的队友的 "+target.name);
				
				return -3;
			}
			if (!canMoveTo(target.positionVO,qizhiMap))
			{
				return -2;
			}
			//比较大小
			return this.Compare(target);
			
		}
		
	}
}

 

 

 

3.3 GameEngine 游戏控制类

游戏控制类用于对游戏进行调试,设计为一个全局类,包括了游戏进行必需的一些内容,如桌主,等待时间,游戏状态,游戏棋子集合,当前玩家,当前布局,当前选中棋子等内容。充分利用flex的绑定机制,将显示部分与控制部分结合。

 
 
package com.boyiju.game.siguo.model
{

	import asds.map.HashMap;
	
	import com.adobe.cairngorm.model.IModelLocator;
	import com.boyiju.game.siguo.components.LayoutSelect;
	import com.boyiju.game.siguo.components.Qizhi;
	import com.boyiju.game.siguo.util.Enum;
	import com.boyiju.game.siguo.vo.LayoutVO;
	import com.boyiju.game.siguo.vo.PositionVO;
	import com.boyiju.game.siguo.vo.QizhiVO;
	import com.boyiju.game.siguo.vo.UserVO;
	
	import mx.collections.ArrayCollection;
	import mx.core.FlexGlobals;
	
	/**
	 *四国军棋游戏的全局控制类,使用了cairngoarm类设计
	 */	
	
	[Bindable]
	public class GameEngine implements IModelLocator
	{
		private static var _model:GameEngine;
			
		
		
		public var gameOwner:int;//游戏桌主
				
		public var gameWaitTime:int=30;//等待时间 秒		
		
		public var gameStatus:int;//游戏状态
		
		
		public var currentPlayer:UserVO;//当前玩家
		public var currentTurn:int;//当前回合玩家
		public var currentSelectedQZ:Qizhi; //选中的棋子
		
		
		public var sourceQZ:Qizhi;	 //源棋子,用于棋子之间产鲜红用
		
		
		public var layoutAC:ArrayCollection;//布局文件组合
		public var currentLayout:LayoutVO;//当前布局文件
		
		public var playerAC:HashMap; //玩家组合
		
		
		public var qizhiMap:HashMap; //所有棋子有组合,与服务器交互的主要类
		
		
		
		/**
		 *初始化四国军棋棋局 
		 * @param enforcer
		 * 
		 */		
		public function GameEngine(enforcer:SingletonEnforcer) {	
			
			gameStatus=Enum.GAME_LAYOUT;
			
			layoutAC=new ArrayCollection();
			layoutAC.addItem(new LayoutVO("守型",LayoutSelect.LAYOUT_COOL,"偏防守"));
			layoutAC.addItem(new LayoutVO("攻型",LayoutSelect.LAYOUT_HOT,"偏进攻"));
			layoutAC.addItem(new LayoutVO("基本",LayoutSelect.LAYOUT_NORMAL,"攻守平衡"));
			currentLayout=layoutAC.getItemAt(0) as LayoutVO;
			
			qizhiMap=new HashMap();
			playerAC =new HashMap();
			
			createAndInitUser();
			currentPlayer=playerAC.get(0) as UserVO;
		}
		/**
		 *将布局文件添加到全局布局列表中 
		 * @param layout
		 * 
		 */		
		public function addLayout(layout:LayoutVO,deskpos:int):void{
			
			for (var i:int=0;i<layout.lyAC.length;i++)
			{
				if (layout.lyAC[i]!=-1)
				{
					var positionVO:PositionVO=new PositionVO();
					positionVO.index=30*deskpos+i;
					var qizhiVO:QizhiVO=new QizhiVO();
					qizhiVO.value=(layout.lyAC[i]);
					qizhiVO.deskpos=deskpos;
					qizhiVO.positionVO=positionVO;
					qizhiMap.put(qizhiVO.positionVO.index,qizhiVO);
				}
			}
		}
		
		public static function get intance():GameEngine
		{
			if (_model ==null) {
				_model=new GameEngine(new SingletonEnforcer());
			}
			return _model;
		}
		/**
		 *测试用,加入一些用户 
		 * 
		 */		
		private function createAndInitUser():void {
			var user:UserVO=new UserVO();
			user.name="张柏枝";
			user.picture="assets/images/zbz.jpg";
			user.score=0;
			user.win=0;
			user.lost=0;
			user.points=2100;
			user.deskpos=0;
			playerAC.put(user.deskpos,user);
			user=new UserVO();
			user.name="王菲";
			user.picture="assets/images/wf.jpg";
			user.score=0;
			user.win=0;
			user.lost=0;
			user.points=500;
			user.deskpos=1;
			playerAC.put(user.deskpos,user);
			user=new UserVO();
			user.name="林志玲";
			user.picture="assets/images/lzl.jpg";
			user.score=0;
			user.win=0;
			user.lost=0;
			user.points=2250;
			user.deskpos=2;
			playerAC.put(user.deskpos,user);
			user=new UserVO();
			user.name="阿娇";
			user.picture="assets/images/aj.jpg";
			user.score=0;
			user.win=0;
			user.lost=0;
			user.points=350;
			user.deskpos=3;
			playerAC.put(user.deskpos,user);
		}
		/**
		 *获得下一位玩家, 
		 * @param num
		 * @return 
		 * 
		 */		
		public function getNextUser(num:int):UserVO{
			var nextid:int=(currentPlayer.deskpos+num)%4;
			return playerAC.get(nextid) as UserVO;
		} 
		
	}
	
}
class SingletonEnforcer
{
	
}
3.4 LayoutVO 类 布局文件类
布局文件类是个更简单的类,他包括一个名称,目录,及30个棋子位置的子的集合,
    [Bindable]    
public class LayoutVO    
{        

public var name:String;        
public var lyAC:ArrayCollection;        
public var catalog:String;     
           
public function LayoutVO(name:String,lyAC:Array,catalog:String)        
{           
 this.name=name;            
this.lyAC=new ArrayCollection(lyAC);           
 this.catalog=catalog;        
 }  
}

一个典型的博命型的划攻布局可以描述如下。够简单了吧,看看我们下QQ游戏的布局文件,几个K,我汗。。

public static const LAYOUT_HOT:Array=[40,39,38,38,37,37,36,-1,100,-1,36,30,35,35,-1,34,34,34,33,-1,33,-1,33,32,32,32,31,31,31,100];

四)下一节可能做的工作

核心部分基本就包括在这四个类内,应该来讲够简单吧,最终完成的效果如图

sg3_2s

下一节我来设计显示的部分及游戏进行中的逻辑部分,显示的部分就是把控件拉来拉去,加上绑定机制。你会觉得更简单的:),同时,下节打算做出第一个测试版本swf文件供大家测试一下。

posted @ 2010-12-31 14:22  博弈居  阅读(1858)  评论(0编辑  收藏  举报

我的微博