GameService组件则是整个游戏逻辑实现的核心,而且GameService是一个可以复用的业务逻辑类。
(一)定义GameService组件接口
根据前面程序对GameService组件的依赖,程序需要GameService组件包含如下方法。
·start():初始化游戏状态,开始游戏的方法。
·Piece[][]getPieces():返回表示游戏状态的Piece[][]数组。
·booleanhasPieces():判断Pieces[][]数组中是否还剩Piece对象;如果所有Piece都被消除了,游戏也就胜利了。
·PiecefindPiece(floattouchX,floattouchY):根据触碰点的X、Y坐标来获取。
·LinkInfolink(Piecep1,Piecep2):判断p1、p2两个方块是否可以相连。
为了考虑以后的可拓展性,需先为GameService组件定义如下接口。
接口代码如下:src\org\crazyit\link\board\GameService
1publicinterfaceGameService2{3/**4*控制游戏开始的方法5*/6voidstart();78/**9*定义一个接口方法,用于返回一个二维数组10*11*@return存放方块对象的二维数组12*/13Piece[][]getPieces();1415/**16*判断参数Piece[][]数组中是否还存在非空的Piece对象17*18*@return如果还剩Piece对象返回true,没有返回false19*/20booleanhasPieces();2122/**23*根据鼠标的x座标和y座标,查找出一个Piece对象24*25*@paramtouchX鼠标点击的x座标26*@paramtouchY鼠标点击的y座标27*@return返回对应的Piece对象,没有返回null28*/29PiecefindPiece(floattouchX,floattouchY);3031/**32*判断两个Piece是否可以相连,可以连接,返回LinkInfo对象33*34*@paramp1第一个Piece对象35*@paramp2第二个Piece对象36*@return如果可以相连,返回LinkInfo对象,如果两个Piece不可以连接,返回null37*/38LinkInfolink(Piecep1,Piecep2);39}
(二)实现GameService组件
GameService组件的前面三个方法实现起来都比较简单。
前3个方法的代码如下:src\org\crazyit\link\board\impl\GameServiceImpl
(三)获取触碰点的方块
当用户触碰游戏界面时,事件监听器获取的时该触碰点在游戏界面上的X、Y坐标,但程序需要获取用户触碰的是哪块方块,就要把获取的X、Y坐标换算成Piece[][]二维数组中的两个索引值。
考虑到游戏界面上每个方块的宽度、高度都是相同的,因此将获取得X、Y坐标除以图片得宽、高即可换算成Piece[][]二维数组中的索引。
根据触碰点X、Y坐标获取对应方块得代码如下:src\org\crazyit\link\board\impl\GameServiceImpl.java
getIndex(intrelative,intsize)方法的实现就是拿relative除以size,只是程序需要判断可以整除和不能整除两种情况:如果可以整除,说明还在前一块方块内;如果不能整除,则对应于下一块方块。
getIndex(intrelative,intsize)方法的代码如下:src\org\crazyit\link\board\impl\GameServiceImpl.java
1//工具方法,根据relative座标计算相对于Piece[][]数组的第一维2//或第二维的索引值,size为每张图片边的长或者宽3privateintgetIndex(intrelative,intsize)4{5//表示座标relative不在该数组中6intindex=-1;7//让座标除以边长,没有余数,索引减18//例如点了x座标为20,边宽为10,20%10没有余数,9//index为1,即在数组中的索引为1(第二个元素)10if(relative%size==0)11{12index=relative/size-1;13}14else15{16//有余数,例如点了x座标为21,边宽为10,21%10有余数,index为217//即在数组中的索引为2(第三个元素)18index=relative/size;19}20returnindex;21}
(四)判断两个方块是否可以相连
判断两个方块是否可以相连是本程序需要处理的最繁琐的地方:两个方块可以相连的情形比较多,大致可分为:
·两个方块位于同一条水平线,可以直接相连。
·两个方块位于同一条竖直线,可以直接相连。
·两个方块以两条线段相连,有1个拐点。
·两个方块以三条线段相连,有2个拐点。
下面link(Piecep1,Piecep2)方法把这四种情况分开进行处理。
代码如下:src\org\crazyit\link\board\impl\GameServiceImpl.java
为了实现上面4个方法,可以对两个Piece的位置关系进行归纳。
·p1于p2在同一行(indexY值相同)。
·p1与p2在同一列(indexX值相同)。
·p2在p1的右上角(p2的indexX>p1的indexX,p2的indexY ·p2的p1的右下角(p2的indexX>p1的indexX,p2的indexY>p1的indexY)。 至于p2在p1的左上角,或者p2在p1的左下角这两种情况,程序可以重新执行link方法,将p1和p2两个参数的位置互换即可。 (五)定义获取通道的工具方法 这里所谓的通到,指的是一个方块上、下、左、右四个方向的空白方块。 下面是获取某个坐标点四周通道的4个方法的代码如下:src\org\crazyit\link\board\impl\GameServiceImpl.java (六)没有转折点的横向连接 如果两个Piece在Piece[][]数组中的第二维索引值相等,那么这两个Piece就位于同一行,如前面的link(Piecep1,Piecep2)方法中,调用isXBlock(Pointp1,Pointp2,intpieceWidth)判断p1、p2之间是否有障碍。 下面是isXBlock方法的代码:src\org\crazyit\link\board\impl\GameServiceImpl.java 1/**2*判断两个y座标相同的点对象之间是否有障碍,以p1为中心向右遍历3*4*@paramp15*@paramp26*@parampieceWidth7*@return两个Piece之间有障碍返回true,否则返回false8*/9privatebooleanisXBlock(Pointp1,Pointp2,intpieceWidth)10{11if(p2.x (七)没有转折点的纵向连接 如果两个Piece在Piece[][]数组中的第一维索引值相等,那么这两个Piece就位于同一列,如前面的link(Piecep1,Piecep2)方法中,调用isYBlock(Pointp1,Pointp2,intpieceWidth)判断p1、p2之间是否有障碍。 下面是isYBlock方法的代码:src\org\crazyit\link\board\impl\GameServiceImpl.java /***判断两个x座标相同的点对象之间是否有障碍,以p1为中心向下遍历**@paramp1*@paramp2*@parampieceHeight*@return两个Piece之间有障碍返回true,否则返回false*/privatebooleanisYBlock(Pointp1,Pointp2,intpieceHeight){if(p2.y (八)一个转折点的连接 对于两个方块连接线上只有一个转折点的情况,程序需要先找到这个转折点。为了找到这个转折点,程序定义一个遍历两个通道并获取它们交点的方法。 /***遍历两个通道,获取它们的交点**@paramp1Chanel第一个点的通道*@paramp2Chanel第二个点的通道*@return两个通道有交点,返回交点,否则返回null*/privatePointgetWrapPoint(List 当p2位于p1的右上角时,应该计算p1的向左通道与p2的向下通道是否有交点,p1的向上通道与p2的向左通道是否有交点。 当p2位于p1的右上角时,应该计算p1的向右通道与p2的向上通道是否有交点,p1的向下通道与p2的向左通道是否有交点。 根据p1与p2具有上面两种分布情形,程序提供如下方法进行处理。 在上面程序中用到isLeftUp、isLeftDown、isRightUp、isRightDown四个方法来判断p2位于p1的左上、左下、右上、右下4种情形。这4个方法的实现,只要对它们的X、Y坐标进行简单判断即可。 4个方法的代码如下:src\org\crazyit\link\board\impl\GameServiceImpl.java 1/**2*判断point2是否在point1的左上角3*4*@parampoint15*@parampoint26*@returnp2位于p1的左上角时返回true,否则返回false7*/8privatebooleanisLeftUp(Pointpoint1,Pointpoint2)9{10return(point2.x (九)两个转折点的连接 两个转折点的1连接又是最复杂的一种连接情况,因为两个转折点又可分为如下几种情况。 ·p1、p2位于同一行,不能直接相连,就必须有两个转折点,分向上与向下两种连接情况。 ·p1、p2位于同一列,不能直接相连,也必须有两个转折点,分向左与向右两种连接情况。 ·p2在p1的右下角,有6种转折情况。 ·p2在p1的右上角,有6种转折情况。 对于上面4种情况,同样需要分别进行处理。 1.同一行不能直接相连 p1、p2位于同一行,但它们不能直接相连,因此必须有两个转折点。当p1与p2位于同一行不能直接相连时,这两个点既可在上面相连,也可在下面相连。这两种情况都代表它们可以相连,我们先把这两种情况都加入结果中,最后再去计算最近的距离。 实现时可以先构建一个Map,Map的key为第一个转折点,Map的value为第二转折点,如果Map的size()大于1,说明这两个Point有多种连接途径,那么程序还需要计算路径最小的连接方式。 2.同一列不能直接相连 p1、p2位于同一列,但它们不能直接相连,因此必须有两个转折点。当p1与p2位于同一列不能直接相连时,这两个点既可在左边相连,也可在右边相连。这两种情况都代表它们可以相连,我们先把这两种情况都加入结果中,最后再去计算最近的距离。 同样的,我们实现时也是构建一个Map。当size()大于1,还要计算最小的连接方式。 3.p2位于p1右下角的六种转折情况 有一条垂直通道与p1的向右通道和p2的向左通道相交的方式。有一条水平通道与p1的向下通道和p2的向上通道相交的方式。即可在上面相连,也可在下面相连。即可在左边相连,也可在右边相连。共6种相连情况。 4.p2位于p1右上角的六种转折情况 与3类似,不再叙述。 对具有两个连接点的情况进行处理的代码如下:src\org\crazyit\link\board\impl\GameServiceImpl.java getYLinkPoints、getXLinkPoints两种方法的代码如下:src\org\crazyit\link\board\impl\GameServiceImpl.java 但point1、point2之间有多种连接情况时,程序还需要找出所有连接情况中的最短路径,,上面代码中调用了getShortcut(Pointp1,Pointp2,turns,getDistance(Pointp1,Pointp2))方法进行处理。 (十)找出最短距离 为了找出最短路径,程序可分为两步。 1.遍历转折点Map中所有key-value对,与原来选择的两个点构成了一个LinkInfo。每个LinkInfo代表一条完整的连接路径,并将这些LinkInfo收集成一个List集合。 2.遍历第一步得到的List 通过连连看游戏的分析与学习,加强了开发者界面分析与数据建模的能力。通过自定义View来实现游戏的主界面。连连看中需要判断两个方块是否可以相连,需要开发这对两个方块的位置分门别类地进行处理,也加强开发者冷静、条理化的思维。