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开发学习之路——连连看之游戏逻辑(五)

     

     

  • 相关阅读:
    动态规划(1)
    dockerfile构架镜像(8)
    redis(1)
    递归算法(1)
    docker commit理解构建镜像(7)
    Node fs 创建多层文件夹
    SUSE系列---修改IP和hosts文件
    本地oracle可以通过localhost连接,无法通过ip地址连接解决方法,oracle远程连接配置
    PLSQL报错: ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务
    StringUtils字符串工具类左侧补齐(leftPad)、右侧补齐(rightPad)、左右两侧补齐(center)工具方法
  • 原文地址:https://www.cnblogs.com/weilongfu/p/7366520.html
Copyright © 2011-2022 走看看