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


        前面连连看之游戏界面(一)中已设计出游戏界面的布局文件,该布局文件需要使用一个Activity来负责显示,除此以外,Activity还需要为游戏界面的按钮、GameView组件的事件提供事件监听器。

        尤其是对于GameView组件,程序需要监听用户的触碰动作,当用户触碰屏幕时,程序需要获取用户触碰的是哪个方块,并判断是否需要“消除”该方块。为了判断能否消除该方块,程序需要进行如下判断:

        ·如果程序之前已经选中了某个方块,就判断当前触碰多的方块是否能与之前的方块“相连”,如果可以相连,则消除两个方块;如果两个方块不可以相连,则把当前方块设置为选中方块。

        ·如果程序之前没有选中方块,直接将当前方块设置为选中方块。

        Activity的代码如下:srcorgcrazyitlinkLink.java

      1 public class Link extends Activity
      2 {
      3     // 游戏配置对象
      4     private GameConf config;
      5     // 游戏业务逻辑接口
      6     private GameService gameService;
      7     // 游戏界面
      8     private GameView gameView;
      9     // 开始按钮
     10     private Button startButton;
     11     // 记录剩余时间的TextView
     12     private TextView timeTextView;
     13     // 失败后弹出的对话框
     14     private AlertDialog.Builder lostDialog;
     15     // 游戏胜利后的对话框
     16     private AlertDialog.Builder successDialog;
     17     // 定时器
     18     private Timer timer = new Timer();
     19     // 记录游戏的剩余时间
     20     private int gameTime;
     21     // 记录是否处于游戏状态
     22     private boolean isPlaying;
     23     // 振动处理类
     24     private Vibrator vibrator;
     25     // 记录已经选中的方块
     26     private Piece selected = null;
     27     private Handler handler = new Handler()
     28     {
     29         public void handleMessage(Message msg)
     30         {
     31             switch (msg.what)
     32             {
     33                 case 0x123:
     34                     timeTextView.setText("剩余时间: " + gameTime);
     35                     gameTime--;
     36                     // 时间小于0, 游戏失败
     37                     if (gameTime < 0)
     38                     {
     39                         stopTimer();
     40                         // 更改游戏的状态
     41                         isPlaying = false;
     42                         lostDialog.show();
     43                         return;
     44                     }
     45                     break;
     46             }
     47         }
     48     };
     49 
     50     @Override
     51     public void onCreate(Bundle savedInstanceState)
     52     {
     53         super.onCreate(savedInstanceState);
     54         setContentView(R.layout.main);
     55         // 初始化界面
     56         init();
     57     }
     58 
     59     // 初始化游戏的方法
     60     private void init()
     61     {
     62         config = new GameConf(8, 9, 2, 10 , 100000, this);
     63         // 得到游戏区域对象
     64         gameView = (GameView) findViewById(R.id.gameView);
     65         // 获取显示剩余时间的文本框
     66         timeTextView = (TextView) findViewById(R.id.timeText);
     67         // 获取开始按钮
     68         startButton = (Button) this.findViewById(R.id.startButton);
     69         // 获取振动器
     70         vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
     71         gameService = new GameServiceImpl(this.config);
     72         gameView.setGameService(gameService);
     73         // 为开始按钮的单击事件绑定事件监听器
     74         startButton.setOnClickListener(new View.OnClickListener()
     75         {
     76             @Override
     77             public void onClick(View source)
     78             {
     79                 startGame(GameConf.DEFAULT_TIME);
     80             }
     81         });
     82         // 为游戏区域的触碰事件绑定监听器
     83         this.gameView.setOnTouchListener(new View.OnTouchListener()
     84         {
     85             public boolean onTouch(View view, MotionEvent e)
     86             {
     87                 if (e.getAction() == MotionEvent.ACTION_DOWN)
     88                 {
     89                     gameViewTouchDown(e);
     90                 }
     91                 if (e.getAction() == MotionEvent.ACTION_UP)
     92                 {
     93                     gameViewTouchUp(e);
     94                 }
     95                 return true;
     96             }
     97         });
     98         // 初始化游戏失败的对话框
     99         lostDialog = createDialog("Lost", "游戏失败! 重新开始", R.drawable.lost)
    100             .setPositiveButton("确定", new DialogInterface.OnClickListener()
    101             {
    102                 public void onClick(DialogInterface dialog, int which)
    103                 {
    104                     startGame(GameConf.DEFAULT_TIME);
    105                 }
    106             });
    107         // 初始化游戏胜利的对话框
    108         successDialog = createDialog("Success", "游戏胜利! 重新开始",
    109             R.drawable.success).setPositiveButton("确定",
    110             new DialogInterface.OnClickListener()
    111             {
    112                 public void onClick(DialogInterface dialog, int which)
    113                 {
    114                     startGame(GameConf.DEFAULT_TIME);
    115                 }
    116             });
    117     }
    118     @Override
    119     protected void onPause()
    120     {
    121         // 暂停游戏
    122         stopTimer();
    123         super.onPause();
    124     }
    125     @Override
    126     protected void onResume()
    127     {
    128         // 如果处于游戏状态中
    129         if (isPlaying)
    130         {
    131             // 以剩余时间重写开始游戏
    132             startGame(gameTime);
    133         }
    134         super.onResume();
    135     }
    136 
    137     // 触碰游戏区域的处理方法
    138     private void gameViewTouchDown(MotionEvent event)
    139     {
    140         // 获取GameServiceImpl中的Piece[][]数组
    141         Piece[][] pieces = gameService.getPieces();
    142         // 获取用户点击的x座标
    143         float touchX = event.getX();
    144         // 获取用户点击的y座标
    145         float touchY = event.getY();
    146         // 根据用户触碰的座标得到对应的Piece对象
    147         Piece currentPiece = gameService.findPiece(touchX, touchY);
    148         // 如果没有选中任何Piece对象(即鼠标点击的地方没有图片), 不再往下执行
    149         if (currentPiece == null)
    150             return;
    151         // 将gameView中的选中方块设为当前方块
    152         this.gameView.setSelectedPiece(currentPiece);
    153         // 表示之前没有选中任何一个Piece
    154         if (this.selected == null)
    155         {
    156             // 将当前方块设为已选中的方块, 重新将GamePanel绘制, 并不再往下执行
    157             this.selected = currentPiece;
    158             this.gameView.postInvalidate();
    159             return;
    160         }
    161         // 表示之前已经选择了一个
    162         if (this.selected != null)
    163         {
    164             // 在这里就要对currentPiece和prePiece进行判断并进行连接
    165             LinkInfo linkInfo = this.gameService.link(this.selected,
    166                 currentPiece);
    167             // 两个Piece不可连, linkInfo为null
    168             if (linkInfo == null)
    169             {
    170                 // 如果连接不成功, 将当前方块设为选中方块
    171                 this.selected = currentPiece;
    172                 this.gameView.postInvalidate();
    173             }
    174             else
    175             {
    176                 // 处理成功连接
    177                 handleSuccessLink(linkInfo, this.selected
    178                     , currentPiece, pieces);
    179             }
    180         }
    181     }
    182     // 触碰游戏区域的处理方法
    183     private void gameViewTouchUp(MotionEvent e)
    184     {
    185         this.gameView.postInvalidate();
    186     }
    187     
    188     // 以gameTime作为剩余时间开始或恢复游戏
    189     private void startGame(int gameTime)
    190     {
    191         // 如果之前的timer还未取消,取消timer
    192         if (this.timer != null)
    193         {
    194             stopTimer();
    195         }
    196         // 重新设置游戏时间
    197         this.gameTime = gameTime;        
    198         // 如果游戏剩余时间与总游戏时间相等,即为重新开始新游戏
    199         if(gameTime == GameConf.DEFAULT_TIME)
    200         {
    201             // 开始新的游戏游戏
    202             gameView.startGame();
    203         }
    204         isPlaying = true;    
    205         this.timer = new Timer();
    206         // 启动计时器 , 每隔1秒发送一次消息
    207         this.timer.schedule(new TimerTask()
    208         {
    209             public void run()
    210             {
    211                 handler.sendEmptyMessage(0x123);
    212             }
    213         }, 0, 1000);
    214         // 将选中方块设为null。
    215         this.selected = null;
    216     }    
    217 
    218     /**
    219      * 成功连接后处理
    220      * 
    221      * @param linkInfo 连接信息
    222      * @param prePiece 前一个选中方块
    223      * @param currentPiece 当前选择方块
    224      * @param pieces 系统中还剩的全部方块
    225      */
    226     private void handleSuccessLink(LinkInfo linkInfo, Piece prePiece,
    227         Piece currentPiece, Piece[][] pieces)
    228     {
    229         // 它们可以相连, 让GamePanel处理LinkInfo
    230         this.gameView.setLinkInfo(linkInfo);
    231         // 将gameView中的选中方块设为null
    232         this.gameView.setSelectedPiece(null);
    233         this.gameView.postInvalidate();
    234         // 将两个Piece对象从数组中删除
    235         pieces[prePiece.getIndexX()][prePiece.getIndexY()] = null;
    236         pieces[currentPiece.getIndexX()][currentPiece.getIndexY()] = null;
    237         // 将选中的方块设置null。
    238         this.selected = null;
    239         // 手机振动(100毫秒)
    240         this.vibrator.vibrate(100);
    241         // 判断是否还有剩下的方块, 如果没有, 游戏胜利
    242         if (!this.gameService.hasPieces())
    243         {
    244             // 游戏胜利
    245             this.successDialog.show();
    246             // 停止定时器
    247             stopTimer();
    248             // 更改游戏状态
    249             isPlaying = false;
    250         }
    251     }
    252 
    253     // 创建对话框的工具方法
    254     private AlertDialog.Builder createDialog(String title, String message,
    255         int imageResource)
    256     {
    257         return new AlertDialog.Builder(this).setTitle(title)
    258             .setMessage(message).setIcon(imageResource);
    259     }
    260     private void stopTimer()
    261     {
    262         // 停止定时器
    263         this.timer.cancel();
    264         this.timer = null;
    265     }
    266 }

        上面代码中的gameViewTouchDown()方法负责处理触碰事件。它会先根据触碰点计算出触碰的方法。接下来该方法会判断是否之前已有选中的方块,如果没有,直接将当前方块设为选中方块,如果有,判断两个方块是否可以相连。

        如果两个方块可以相连,程序将会从Piece[][]数组中删除这两个方块,该逻辑由handleSuccessLink()方法完成。

        除此之外,该程序为了控制时间流失,定义了一个计时器,该计时器每隔1秒发送一条消息,程序将会根据该消息减少游戏剩余的时间。

        该Link Activity用的两个类如下:

        ·GameConf:负责管理游戏的初始化设置信息。

        ·GameService:负责游戏的逻辑实现。

        上面两个工具类中GameConf只是一个简单的设置类,代码如下:

     1 public class GameConf
     2 {
     3     // 设置连连看的每个方块的图片的宽、高
     4     public static final int PIECE_WIDTH = 40;
     5     public static final int PIECE_HEIGHT = 40;
     6     // 记录游戏的总事件(100秒).
     7     public static int DEFAULT_TIME = 100;    
     8     // Piece[][]数组第一维的长度
     9     private int xSize;
    10     // Piece[][]数组第二维的长度
    11     private int ySize;
    12     // Board中第一张图片出现的x座标
    13     private int beginImageX;
    14     // Board中第一张图片出现的y座标
    15     private int beginImageY;
    16     // 记录游戏的总时间, 单位是秒
    17     private long gameTime;
    18     private Context context;
    19 
    20     /**
    21      * 提供一个参数构造器
    22      * 
    23      * @param xSize Piece[][]数组第一维长度
    24      * @param ySize Piece[][]数组第二维长度
    25      * @param beginImageX Board中第一张图片出现的x座标
    26      * @param beginImageY Board中第一张图片出现的y座标
    27      * @param gameTime 设置每局的时间, 单位是秒
    28      * @param context 应用上下文
    29      */
    30     public GameConf(int xSize, int ySize, int beginImageX,
    31         int beginImageY, long gameTime, Context context)
    32     {
    33         this.xSize = xSize;
    34         this.ySize = ySize;
    35         this.beginImageX = beginImageX;
    36         this.beginImageY = beginImageY;
    37         this.gameTime = gameTime;
    38         this.context = context;
    39     }
    40 
    41     public long getGameTime()
    42     {
    43         return gameTime;
    44     }
    45 
    46     public int getXSize()
    47     {
    48         return xSize;
    49     }
    50 
    51     public int getYSize()
    52     {
    53         return ySize;
    54     }
    55 
    56     public int getBeginImageX()
    57     {
    58         return beginImageX;
    59     }
    60 
    61     public int getBeginImageY()
    62     {
    63         return beginImageY;
    64     }
    65 
    66     public Context getContext()
    67     {
    68         return context;
    69     }
    70 }

    具体实现步骤连接:

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

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

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

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

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

  • 相关阅读:
    TQJson序列和还原clientdataset.data
    BPL插件框架的二种实现
    数据序列的本质论
    MSGPACK(一)
    内存数据库和关系数据库之间的数据同步原理
    redis神器
    从Cell的视图推出一个新的界面
    iOS -- DES算法
    Base64---加密
    iOS -- MD5加密
  • 原文地址:https://www.cnblogs.com/weilongfu/p/7385119.html
Copyright © 2020-2023  润新知