android开发学习之路——连连看之游戏界面(一)

  学习了李刚老师的《疯狂Android讲义》,其中18章是介绍连连看的设计。从而学会了如何设计一个android小程序。

  这个游戏,难度适中,适合初学者学习。

  开发连连看游戏,除了需要理解游戏界面的数据模型外,程序开发者还需要判断两个方块是否可以相连,为了判断两个方块是否可以相连,开发者需要对两个方块所处的位置进行分类,然后针对不同的情况采用不同的判断算法进行判断,这需要开发者采用条理化的思维方式进行分析、处理,这也是这小程序需要重点掌握的能力。

  开发游戏界面

  连连看的游戏界面分为两个区域:

  ·游戏主界面区。

  ·控制按钮与数据显示区。

(一)开发界面布局

  本程序将会使用一个RelativeLayout作为整体的界面布局元素,界面布局的上面是一个自定义组件,下面是一个水平排列的LinearLayout。

  布局文件代码如下:reslayoutmain.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <Relativelayout
 3     xmlns:android="http://schemas.android.com/apk/res/android“
 4     android:layout_width="fill_parent"
 5     android:layout_height="fill_parent"
 6     android:background="@drawable/room">
 7 <!--游戏主界面的自定义组件-->
 8 <org.crazyit.link.view.GameView
 9     android:id="@+id/gameView"
10     android:layout_width="fill_parent"
11     android:layout_height="fill_parent"/>
12 <!--水平排列的LinearLayout-->
13     android:layout_width="fill_parent"
14     android:layout_height="fill_parent"
15     android:orientation="horizontal"
16     android:layout_marginTop="380px"
17     android:background="#le72bb"
18     android:gravity="center">
19 <!--控制游戏开始的按钮-->
20 <Button
21     android:id="@+id/startButton"
22     android:layout_width="wrap_content"
23     android:layout_height="wrap_content"
24     android:background="@drawable/button_selector"/>
25 <!--显示游戏剩余时间的文本框-->
26 <TextView
27     android:id="@+id/timeText"
28     android:layout_width="wrap_content"
29     android:layout_height="wrap_content"
30     android:gravity="center"
31     android:textSize="20dip"
32     android:width="150px"
33     android:textColor="#ff9"/>
34 </LinearLayout>
35 </RelativeLayout>

  这个界面布局很简单,指定按钮的背景色时使用了@drawable/button_selector,这是一个在resdrawable目录下配置的StateListDrawable对象。

  配置文件代码如下:resdrawable-mdpiutton_selector.xml

1 <?xml version="1.0" encoding="UTF-8"?>
2 <selector xmlns:android="http://schemas.android.com/spk/res/android">
3     <!--指定按钮按下时的图片-->
4     <item android:state_pressed="true"
5               android:drawable="@drawable/start_down"/>
6     <!--指定按钮按下时的图片-->
7     <item android:state_pressed="false"
8               android:drawable="@drawable/start"/>
9 </selector>

(二) 开发游戏界面组件

    本游戏的界面组件采用了一个自定义View:GameView,它从View基类派出而出,这个自定义View的功能就是根据游戏状态来绘制游戏界面的全部方块。为了开发这个GameView,本程序还提供了一个Piece类,一个Piece对象代表游戏界面上的一个方块,它除了封装方块上的图片之外,还需要封装该方块代表二维数组中的哪个元素;也需要封装它的左上角在游戏界面中X、Y坐标。方块左上角的X、Y坐标可决定它的绘制位置,GameView根据这两个坐标绘制全部方块即可。

Piece类代码如下:srcorgcrazyitlinkviewPiece.java

 1 public class Piece
 2 {
 3     // 保存方块对象的所对应的图片
 4     private PieceImage image;
 5     // 该方块的左上角的x坐标
 6     private int beginX;
 7     // 该方块的左上角的y座标
 8     private int beginY;
 9     // 该对象在Piece[][]数组中第一维的索引值
10     private int indexX;
11     // 该对象在Piece[][]数组中第二维的索引值
12     private int indexY;
13 
14     // 只设置该Piece对象在数组中的索引值
15     public Piece(int indexX , int indexY)
16     {
17         this.indexX = indexX;
18         this.indexY = indexY;
19     }
20 
21     public int getBeginX()
22     {
23         return beginX;
24     }
25 
26     public void setBeginX(int beginX)
27     {
28         this.beginX = beginX;
29     }
30 
31     public int getBeginY()
32     {
33         return beginY;
34     }
35 
36     public void setBeginY(int beginY)
37     {
38         this.beginY = beginY;
39     }
40 
41     public int getIndexX()
42     {
43         return indexX;
44     }
45 
46     public void setIndexX(int indexX)
47     {
48         this.indexX = indexX;
49     }
50 
51     public int getIndexY()
52     {
53         return indexY;
54     }
55 
56     public void setIndexY(int indexY)
57     {
58         this.indexY = indexY;
59     }
60     
61 
62     public PieceImage getImage()
63     {
64         return image;
65     }
66 
67     public void setImage(PieceImage image)
68     {
69         this.image = image;
70     }
71 
72     // 获取该Piece的中心
73     public Point getCenter()
74     {
75         return new Point(getImage().getImage().getWidth() / 2
76             + getBeginX(), getBeginY()
77             + getImage().getImage().getHeight() / 2);
78     }    
79     // 判断两个Piece上的图片是否相同
80     public boolean isSameImage(Piece other)
81     {
82         if (image == null)
83         {
84             if (other.image != null)
85                 return false;
86         }
87         // 只要Piece封装图片ID相同,即可认为两个Piece相等。
88         return image.getImageId() == other.image.getImageId();
89     }
90 }

    上面的Piece类中封装的PieceImage代表了该方块上的图片,但此处并未直接使用Bitmap对象来代表方块上的图片——因为我们需要使用PieceImage来封装两个信息:

    ·Bitmap对象。

    ·图片资源的ID。

    其中Bitmap对象用于在游戏界面上绘制方块,而图片资源的ID则代表该Piece对象的标识,用于判断两个Piece上的图片是否相同。如前面代码所示。

    PieceImage类的代码如下:srcorgcrazyitlinkviewPieceImage.java

 1 public class PieceImage
 2 {
 3     private Bitmap image;
 4     private int imageId;
 5     // 有参数的构造器
 6     public PieceImage(Bitmap image, int imageId)
 7     {
 8         super();
 9         this.image = image;
10         this.imageId = imageId;
11     }
12     public Bitmap getImage()
13     {
14         return image;
15     }
16     public void setImage(Bitmap image)
17     {
18         this.image = image;
19     }
20     public int getImageId()
21     {
22         return imageId;
23     }
24     public void setImageId(int imageId)
25     {
26         this.imageId = imageId;
27     }
28 }

    GameView主要就是根据游戏的状态数据来绘制界面上的方块,GameView继承了View组件,重写了View组件上onDraw(Canvas canvas)方法,重写该方法主要就是绘制游戏里剩余的方块;除此之外,它还会负责绘制连接方块的连接线。

    GameView的代码如下:srcorgcrazyitlinkviewGameView.java

  1 public class GameView extends View
  2 {
  3     // 游戏逻辑的实现类
  4     private GameService gameService;
  5     // 保存当前已经被选中的方块
  6     private Piece selectedPiece;
  7     // 连接信息对象
  8     private LinkInfo linkInfo;
  9     private Paint paint;
 10     // 选中标识的图片对象
 11     private Bitmap selectImage;
 12 
 13     public GameView(Context context, AttributeSet attrs)
 14     {
 15         super(context, attrs);
 16         this.paint = new Paint();
 17         // 设置连接线的颜色
 18         this.paint.setColor(Color.RED);
 19         // 设置连接线的粗细
 20         this.paint.setStrokeWidth(3);
 21         this.selectImage = ImageUtil.getSelectImage(context);
 22     }
 23 
 24     public void setLinkInfo(LinkInfo linkInfo)
 25     {
 26         this.linkInfo = linkInfo;
 27     }
 28 
 29     public void setGameService(GameService gameService)
 30     {
 31         this.gameService = gameService;
 32     }
 33 
 34     @Override
 35     protected void onDraw(Canvas canvas)
 36     {
 37         super.onDraw(canvas);
 38         if (this.gameService == null)
 39             return;
 40         Piece[][] pieces = gameService.getPieces();
 41         if (pieces != null)
 42         {
 43             // 遍历pieces二维数组
 44             for (int i = 0; i < pieces.length; i++)
 45             {
 46                 for (int j = 0; j < pieces[i].length; j++)
 47                 {
 48                     // 如果二维数组中该元素不为空(即有方块),将这个方块的图片画出来
 49                     if (pieces[i][j] != null)
 50                     {
 51                         // 得到这个Piece对象
 52                         Piece piece = pieces[i][j];
 53                         // 根据方块左上角X、Y座标绘制方块
 54                         canvas.drawBitmap(piece.getImage().getImage(),
 55                             piece.getBeginX(), piece.getBeginY(), null);
 56                     }
 57                 }
 58             }
 59         }
 60         // 如果当前对象中有linkInfo对象, 即连接信息
 61         if (this.linkInfo != null)
 62         {
 63             // 绘制连接线
 64             drawLine(this.linkInfo, canvas);
 65             // 处理完后清空linkInfo对象
 66             this.linkInfo = null;
 67         }
 68         // 画选中标识的图片
 69         if (this.selectedPiece != null)
 70         {
 71             canvas.drawBitmap(this.selectImage, this.selectedPiece.getBeginX(),
 72                 this.selectedPiece.getBeginY(), null);
 73         }
 74     }
 75 
 76     // 根据LinkInfo绘制连接线的方法。
 77     private void drawLine(LinkInfo linkInfo, Canvas canvas)
 78     {
 79         // 获取LinkInfo中封装的所有连接点
 80         List<Point> points = linkInfo.getLinkPoints();
 81         // 依次遍历linkInfo中的每个连接点
 82         for (int i = 0; i < points.size() - 1; i++)
 83         {
 84             // 获取当前连接点与下一个连接点
 85             Point currentPoint = points.get(i);
 86             Point nextPoint = points.get(i + 1);
 87             // 绘制连线
 88             canvas.drawLine(currentPoint.x , currentPoint.y,
 89                 nextPoint.x, nextPoint.y, this.paint);
 90         }
 91     }
 92 
 93     // 设置当前选中方块的方法
 94     public void setSelectedPiece(Piece piece)
 95     {
 96         this.selectedPiece = piece;
 97     }
 98 
 99     // 开始游戏方法
100     public void startGame()
101     {
102         this.gameService.start();
103         this.postInvalidate();
104     }
105 }

    GameView根据游戏的状态数据来绘制界面中的所有方块,根据LinkInfo来绘制两个方块间的连接线。上面的代码中定义了GameService对象,调用了GameService的getPiece()方法来获取游戏中剩余的方块,GameService是游戏的业务逻辑实现类。后面的篇幅会介绍(android开发学习之路——连连看之游戏逻辑(五)

(三)处理方块之间的连接线

    LinkInfo是一个非常简单的工具类,它用于封装两个方块之间的连接信息——其实就是封装一个List,List里保存了连接线需要经过的点。在实现LinkInfo对象之前,先分析两个方块可以相连的情形。两个方块之间最多只能用3条线段相连,也就是说最多只能有2个“拐点”,加上两个方块的中心,方块的连接信息最多只需要4个连接点。考虑到LinkInfo最多需要封装4个连接点,最少需要封装2个连接点,因此定义LinkInfo类的代码如下:srcorgcrazyitlinkobjectLinkinfo.java

 1 public class LinkInfo
 2 {
 3     // 创建一个集合用于保存连接点
 4     private List<Point> points = new ArrayList<Point>();
 5 
 6     // 提供第一个构造器, 表示两个Point可以直接相连, 没有转折点
 7     public LinkInfo(Point p1, Point p2)
 8     {
 9         // 加到集合中去
10         points.add(p1);
11         points.add(p2);
12     }
13 
14     // 提供第二个构造器, 表示三个Point可以相连, p2是p1与p3之间的转折点
15     public LinkInfo(Point p1, Point p2, Point p3)
16     {
17         points.add(p1);
18         points.add(p2);
19         points.add(p3);
20     }
21 
22     // 提供第三个构造器, 表示四个Point可以相连, p2, p3是p1与p4的转折点
23     public LinkInfo(Point p1, Point p2, Point p3, Point p4)
24     {
25         points.add(p1);
26         points.add(p2);
27         points.add(p3);
28         points.add(p4);
29     }
30 
31     // 返回连接集合
32     public List<Point> getLinkPoints()
33     {
34         return points;
35     }
36 }

    LinkInfo中所用的Point代表一个点,程序直接使用了android.graphics.Point类,每个Point封装了该点的X,Y坐标。

具体实现步骤连接:

android开发学习之路——连连看之游戏界面(一)

android开发学习之路——连连看之数据模型(二)

android开发学习之路——连连看之加载图片(三)

android开发学习之路——连连看之游戏Activity(四)

android开发学习之路——连连看之游戏逻辑(五)

 

 

原文地址:https://www.cnblogs.com/weilongfu/p/7366520.html