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

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

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

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

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

    Activity的代码如下:src\org\crazyit\link\Link.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开发学习之路——连连看之游戏逻辑(五)

posted @ 2017-08-19 16:24  Ling先生  阅读(4960)  评论(0编辑  收藏  举报