zoukankan      html  css  js  c++  java
  • 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开发学习之路——连连看之游戏逻辑(五)

     

     

  • 相关阅读:
    Python3之random模块常用方法
    Go语言学习笔记(九)之数组
    Go语言学习笔记之简单的几个排序
    Go语言学习笔记(八)
    Python3之logging模块
    Go语言学习笔记(六)
    123. Best Time to Buy and Sell Stock III(js)
    122. Best Time to Buy and Sell Stock II(js)
    121. Best Time to Buy and Sell Stock(js)
    120. Triangle(js)
  • 原文地址:https://www.cnblogs.com/weilongfu/p/7366520.html
Copyright © 2011-2022 走看看