helloPe的android项目实战之连连看—实现篇(三)

  前面两篇“实现篇”已经将程序后台框架基本实现了,今天将涉及程序的 activity类,在这个类中,为了有一个比较好的视觉效果,将介绍一些android中动画效果,依靠animation来实现,以及简单介绍 android中自定义dialog的实现;首先看一下游戏界面运行时的效果图(程序中图片使用了网上的网友的,仅当学习之用):

                                                    

                                  游戏运行时界面                                              用于显示游戏结果的自定义dialog显示

先看看用于显示程序的activity类中的代码(这里主要是一些调用等,实现的逻辑在前面两篇文章中已经包含了)

001 package nate.llk;
002  
003 //包得导入略去
004  
005 public class GameActivity extends Activity implements OnToolsChangeListener,OnTimerListener,
006                         OnStateListener{
007     private ImageButton img_startPlay;
008     private ImageView img_title;
009     private ProgressBar progress;
010      
011     private MyDialog dialog;
012     //visibility at first is "gone"
013     private ImageView clock;
014     private GameView gameView = null;
015     private ImageButton img_tip;
016     private ImageButton img_refresh;
017     private TextView text_refreshNum;
018     private TextView text_tipNum;
019     //两个帮助按键的特效
020     private Animation anim = null;
021  
022      
023     private Handler handler = new Handler(){
024         @Override
025         public void handleMessage(Message msg) {
026             switch(msg.what){
027             case 0:
028                 dialog = new MyDialog(GameActivity.this,gameView,"完成!",gameView.getTotalTime() - progress.getProgress() + 1);
029                 dialog.show();
030                 break;
031             case 1:
032                 dialog = new MyDialog(GameActivity.this,gameView,"失败!",gameView.getTotalTime() - progress.getProgress() + 1);
033                 dialog.show();
034             }
035         }
036     };
037      
038     /** Called when the activity is first created. */
039     @Override
040     public void onCreate(Bundle savedInstanceState) {
041         super.onCreate(savedInstanceState);
042         setContentView(R.layout.game_view);
043         anim =  AnimationUtils.loadAnimation(this, R.anim.shake);
044         findView();
045         startView();
046          
047         img_startPlay.setOnClickListener(new BtnClickListener());
048         
049         gameView.setOnTimerListener(this);
050         gameView.setOnStateChangeListener(this);
051         gameView.setOnToolsChangedListener(this);
052         img_refresh.setOnClickListener(new BtnClickListener());
053         img_tip.setOnClickListener(new BtnClickListener());
054     }//end of the OnCreate method!
055     /**
056      * 寻找对应资源控件
057      */
058     public void findView(){
059         clock = (ImageView)this.findViewById(R.id.clock);
060         progress = (ProgressBar)this.findViewById(R.id.timer);
061         img_title = (ImageView)this.findViewById(R.id.title_img);
062         img_startPlay = (ImageButton)this.findViewById(R.id.play_btn);
063         img_tip = (ImageButton)this.findViewById(R.id.tip_btn);
064         img_refresh = (ImageButton)this.findViewById(R.id.refresh_btn);
065         gameView = (GameView)this.findViewById(R.id.game_view);
066         text_refreshNum = (TextView)this.findViewById(R.id.text_refresh_num);
067         text_tipNum = (TextView)this.findViewById(R.id.text_tip_num);
068     }
069     /**
070      * 程序开启界面显示
071      */
072     public void startView(){
073         Animation scale = AnimationUtils.loadAnimation(this,R.anim.scale_anim);
074         img_title.startAnimation(scale);
075         img_startPlay.startAnimation(scale);
076     }
077     /**
078      * 游戏运行时界面显示,即连连看的布局
079      */
080     public void playingView(){
081         Animation scaleOut = AnimationUtils.loadAnimation(this, R.anim.scale_anim_out);
082         img_title.startAnimation(scaleOut);
083         img_startPlay.startAnimation(scaleOut);
084         img_title.setVisibility(View.GONE);
085         img_startPlay.setVisibility(View.GONE);
086          
087         clock.setVisibility(View.VISIBLE);
088         progress.setMax(gameView.getTotalTime());
089         progress.setProgress(gameView.getTotalTime());
090         progress.setVisibility(View.VISIBLE);
091         gameView.setVisibility(View.VISIBLE);
092         img_tip.setVisibility(View.VISIBLE);
093         img_refresh.setVisibility(View.VISIBLE);
094         text_tipNum.setVisibility(View.VISIBLE);
095         text_refreshNum.setVisibility(View.VISIBLE);
096         Animation animIn = AnimationUtils.loadAnimation(this, R.anim.trans_in);
097         gameView.startAnimation(animIn);
098         img_tip.startAnimation(animIn);
099         img_refresh.startAnimation(animIn);
100         text_tipNum.startAnimation(animIn);
101         text_refreshNum.startAnimation(animIn);
102         //player.pause();
103         gameView.startPlay();
104         toast();
105     }
106     /**
107      * 一个处理开始游戏,刷新,帮助三个按钮的listener的类
108      * @author HelloPe || NatePan
109      *
110      */
111     class BtnClickListener implements OnClickListener{
112         @Override
113         public void onClick(View v) {
114             switch(v.getId()){
115             case R.id.play_btn:
116                 playingView();
117                 break;
118             case R.id.refresh_btn:
119                 img_refresh.startAnimation(anim);
120                 gameView.refreshChange();
121                 gameView.invalidate();
122                 break;
123             case R.id.tip_btn:
124                 img_tip.startAnimation(anim);
125                 gameView.autoHelp();
126                 break;
127             }
128         }
129     }
130     @Override
131     public void onRefreshChanged(int count) {
132         text_refreshNum.setText(""+gameView.getRefreshNum());
133     }
134     @Override
135     public void onTipChanged(int count) {
136         text_tipNum.setText("" + gameView.getTipNum());
137     }
138     @Override
139     public void onTimer(int leftTime) {
140         progress.setProgress(leftTime);
141          
142     }
143      
144     /**
145      *用来控制音乐的播放
146      */
147     @Override
148     public void OnStateChanged(int StateMode) {
149         switch(StateMode){
150         case GameView.WIN:
151             handler.sendEmptyMessage(0);
152             break;
153         case GameView.LOSE:
154             handler.sendEmptyMessage(1);
155             break;
156         case GameView.PAUSE:
157             //player.stop();
158             //gameView.player.stop();
159             gameView.stopTimer();
160             break;
161         case GameView.QUIT:
162             //player.release();
163             //gameView.player.release();
164             gameView.stopTimer();
165             break;
166         }
167     }
168     public void quit(){
169         this.finish();
170     }
171     /**
172      * 用于提醒游戏开始,提醒总时间
173      */
174     public void toast(){
175         Toast.makeText(this, "游戏已经开始!总时间: " + gameView.getTotalTime() + "s", Toast.LENGTH_LONG).show();
176     }
177         @Override
178         protected void onPause() {
179             super.onPause();
180             gameView.setMode(GameView.PAUSE);
181         }  
182         @Override
183         protected void onDestroy() {
184             super.onDestroy();
185             gameView.setMode(GameView.QUIT);
186         }
187         @Override
188         public boolean onCreateOptionsMenu(Menu menu) {
189             menu.add(Menu.NONE, 1, Menu.NONE,"Replay").setIcon(R.drawable.buttons_replay);
190             menu.add(Menu.NONE, 2, Menu.NONE, "Pause").setIcon(R.drawable.pause);
191             menu.add(Menu.NONE, 3, Menu.NONE,"SoundOn").setIcon(R.drawable.volume);
192             return super.onCreateOptionsMenu(menu);
193         }
194         @Override
195         public boolean onOptionsItemSelected(MenuItem item) {
196             switch(item.getItemId()){
197             case 1:
198                 gameView.setTotalTime(100);
199                 progress.setMax(100);
200                 gameView.startPlay();
201                 break;
202             case 2:
203                 gameView.stopTimer();
204                 if(item.getTitle().equals("Pause")){
205                     item.setTitle("Continue");
206                     item.setIcon(R.drawable.play);
207                 }else if(item.getTitle().equals("Continue")){
208                     item.setTitle("Pause");
209                     item.setIcon(R.drawable.pause);
210                 }
211                 AlertDialog.Builder dialog = new AlertDialog.Builder(this);
212                 dialog.setIcon(R.drawable.icon);
213                 dialog.setTitle("继续");
214                 dialog.setMessage("继续游戏?");
215                 dialog.setPositiveButton("继续", new DialogInterface.OnClickListener() {
216                      
217                     @Override
218                     public void onClick(DialogInterface dialog, int which) {
219                         gameView.setContinue();
220                     }
221                 }).setNeutralButton("重玩", new DialogInterface.OnClickListener() {
222                      
223                     @Override
224                     public void onClick(DialogInterface dialog, int which) {
225                         gameView.startPlay();
226                     }
227                 }).setNegativeButton("退出", new DialogInterface.OnClickListener() {
228                      
229                     @Override
230                     public void onClick(DialogInterface dialog, int which) {
231                         Intent startMain = new Intent(Intent.ACTION_MAIN); 
232                         startMain.addCategory(Intent.CATEGORY_HOME);  
233                         startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
234                         startActivity(startMain); 
235                         System.exit(0);
236                     }
237                 });
238                 dialog.show();
239                 break;
240             case 3:
241                 ///////////////////////////
242                 if(item.getTitle().equals("Mute")){
243                     item.setTitle("SoundOn");
244                     item.setIcon(R.drawable.volume);
245                 }else if(item.getTitle().equals("SoundOn")){
246                     item.setTitle("Mute");
247                     item.setIcon(R.drawable.mute);
248                 }
249                 break;
250             }
251             return super.onOptionsItemSelected(item);
252         }
253         /**
254          * 监听后退按钮,以防止误按,按下back按钮后,程序应当处于暂停状态
255          */
256         @Override
257         public boolean onKeyDown(int keyCode, KeyEvent event) {
258             if(keyCode == KeyEvent.KEYCODE_BACK){
259                 AlertDialog.Builder dialog= new AlertDialog.Builder(GameActivity.this).setTitle("退出游戏")
260                 .setMessage("确定退出游戏?")
261                 .setPositiveButton("是",new DialogInterface.OnClickListener(){
262  
263                     @Override
264                     public void onClick(DialogInterface dialog, int which) {
265                         Intent startMain = new Intent(Intent.ACTION_MAIN); 
266                         startMain.addCategory(Intent.CATEGORY_HOME);  
267                         startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
268                         startActivity(startMain); 
269                         System.exit(0);
270                     }
271                 }).setNegativeButton("否", new DialogInterface.OnClickListener(){
272  
273                     @Override
274                     public void onClick(DialogInterface dialog, int which) {
275                         Toast.makeText(GameActivity.this, "重新开始了游戏", Toast.LENGTH_LONG).show();
276                         gameView.startPlay();
277                     }
278                      
279                 });
280                 dialog.setIcon(R.drawable.icon);
281                 dialog.show();
282             }
283             return super.onKeyDown(keyCode, event);
284         }
285          
286 }

在此类中,如上次我们所说的,我们实现了之前定义的三个接口,引用了GameView类(在activity的布局文件中使用到),在activity布局文件中如下使用:

1 <nate.llk.view.GameView
2       android:layout_width="wrap_content"
3       android:layout_height="wrap_content"
4       android:id="@+id/game_view"
5       android:visibility="gone"
6       android:layout_below="@id/timer"
7   />

同样对于我们自定义的dialog,跟自定义的GameView(继承自View)是一样的。MyDialog类继承自Dialog类,实现了 OnClickListener的OnClick方法,使用一个布局文件,将自定义的dialog布局。布局文件很简单,MyDialog类如下:

1 package nate.llk;
2 //导入包略去
01 public class MyDialog extends Dialog implements OnClickListener{
02  
03     private GameView gameview;
04     private Context context;
05      
06     public MyDialog(Context context, GameView gameview, String msg, int time) {
07         super(context,R.style.dialog);
08         this.gameview = gameview;
09         this.context = context;
10         this.setContentView(R.layout.dialog_view);
11         TextView text_msg = (TextView) findViewById(R.id.text_message);
12         TextView text_time = (TextView) findViewById(R.id.text_time);
13         ImageButton btn_menu = (ImageButton) findViewById(R.id.menu_imgbtn);
14         ImageButton btn_next = (ImageButton) findViewById(R.id.next_imgbtn);
15         ImageButton btn_replay = (ImageButton) findViewById(R.id.replay_imgbtn);
16          
17         text_msg.setText(msg);
18         text_time.setText(text_time.getText().toString().replace("$", String.valueOf(time)));
19         btn_menu.setOnClickListener(this);
20         btn_next.setOnClickListener(this);
21         btn_replay.setOnClickListener(this);
22         this.setCancelable(false);
23     }
24  
25     @Override
26     public void onClick(View v) {
27         this.dismiss();
28         switch(v.getId()){
29         case R.id.menu_imgbtn:
30             Dialog dialog = new AlertDialog.Builder(context)
31             .setIcon(R.drawable.buttons_bg20)
32             .setTitle(R.string.quit)
33             .setMessage(R.string.sure_quit)
34             .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
35                 public void onClick(DialogInterface dialog, int whichButton) {
36                     ((GameActivity)context).quit();
37                 }
38             })
39             .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
40                 public void onClick(DialogInterface dialog, int whichButton) {
41                     gameview.startPlay();
42                 }
43             })
44             .create();
45             dialog.show();
46             break;
47         case R.id.replay_imgbtn:
48             gameview.startPlay();
49             break;
50         case R.id.next_imgbtn:
51             gameview.startNextPlay();
52             break;
53         }
54     }
55  
56     @Override
57     public boolean onKeyDown(int keyCode, KeyEvent event) {
58         if(keyCode == KeyEvent.KEYCODE_BACK){
59             this.dismiss();
60         }
61         return super.onKeyDown(keyCode, event);
62     }
63      
64 }

上面代码简单,不过还是实现了较好的效果。

在android中使用animation的动画包含四种,Tween animation的使用也能够使程序看起来效果好点:

在anim文件下:

实现当点击程序中两个工具按钮时,工具按钮出现抖动的效果:

1 <?xml version="1.0" encoding="utf-8"?>
2 <translate xmlns:android="http://schemas.android.com/apk/res/android"
3             android:fromXDelta="0"
4             android:toXDelta="10"
5             android:duration="1000"
6             android:interpolator="@anim/cycle" />
1 <?xml version="1.0" encoding="utf-8"?>
2 <cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
3                    android:cycles="7"
4                    /><!--用于控制上面颤动的次数-->

用于控制欢迎界面的图标逐渐变大的出场效果:

01 <?xml version="1.0" encoding="utf-8"?>
03     <scale
04           android:interpolator="@android:anim/accelerate_decelerate_interpolator"
05           android:fromXScale="0.0"
06           android:toXScale="1.0"
07           android:fromYScale="0.0"
08           android:toYScale="1.0"
09           android:pivotX="50%"
10           android:pivotY="50%"
11           android:fillAfter="true"
12           android:duration="1600" />
13 </set>

当然放大效果只是改一下android:fromXScale="1.0"     与    android:toXScale="0.0"即可;

至于透明效果,用于将GameView中的内容从透明慢慢展示出来:

1 <?xml version="1.0" encoding="utf-8"?>
3     <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="1000" />
4 </set>

而在activity中对于以上资源的使用上面activity类中已经给出,先载入,然后调用imageView或者其他View的startAnimation方法即可;

对于游戏中音效的播放方法比较简单,主要是在不同的状态播放不同的声音比较繁琐,android中有两种播放音效的方法:一种是 SoundPool,一种是MediaPlayer。SoundPool适合短促音乐,但是反应速度要求比较高的情况;MediaPlayer则是是相 反。使用步骤如:

// 初始化soundPool 对象,第一个参数是允许有多少个声音流同时播放,第2个参数是声音类型,第三个参数是声音的品质
        soundPool = new SoundPool(25, AudioManager.STREAM_MUSIC, 100);//SoudPool的引用
soundPool.load(context, raw, 1);//调用load函数载入音乐资源

//之后调用play函数即可播放参数中相应的音乐资源

posted @ 2011-11-25 16:18  jeffkuang  阅读(188)  评论(0)    收藏  举报