汉字先生-----初学android时做的小游戏
12年初,开始接触android,看的书是:[Android.游戏开发入门](美)Mario.Zechner.插图版
一边看一边做了这个小游戏,是以选择两个字形组成一个完整的汉字来进行游戏的。
目前只有两种模式:
标准模式:在规定时间内成功组合指定个数的汉字
渡水模式:游戏中,会有一匹白马一直向前行进,如果白马进水游戏便会失败。玩家需要组合汉字使得白马脚下的木桥延长,木桥覆盖过小河游戏便胜利!共5关。
画面比较粗糙,毕竟没有那个美工细胞=.=
整个程序还是有不少问题的, 也有很多用户体验不好的地方,大家也理解 一下哈。
先看一下截图:
下面是工程结构:
游戏中应用 [Android.游戏开发入门](美)Mario.Zechner 一书中介绍的游戏框架,我也对框架进入了适当的修改,以更好地适应自己的游戏。游戏只有一个Activity,继承框架中的 DTGame.java 类,游戏中的界面都是Screen的子类, DTGame 通过调用 getScreen() 获取当前的游戏界面进行绘图。 在游戏中可以调用 DTGame 的setScreen(new Screen())方法来切换界面。整个游戏都只在SurfaceView中更新视图,在框架中 GameSurfaceView.java 继承 SurfaceView 并开启一个线程,调用DTGame 中的 getScreen() 得到当前Screen对象,调用Screen中的 draw() 和update() 方法。
下面是 自己定义的 Activity,继承DTGame:
package cn.dt.mr_cc; import android.app.ProgressDialog; import android.app.Service; import android.os.Handler; import android.os.Vibrator; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.widget.Toast; import cn.dt.mr_cc.screen.LoadScreen; import dt.humen.game.GM; import dt.humen.game.Screen; import dt.humen.game.core.impl.DTGame; public class MrCCActivity extends DTGame { protected WebView webView=null;//加载html的容器 protected View aboutView;//关于的视图 protected boolean gameing=true;//是否在游戏界面中 protected ProgressDialog progressDialog; private Handler handler=new Handler(){ public void handleMessage(android.os.Message msg) { switch(msg.what){ case Constant.GAME_EXIT: beforeExit(); break; case Constant.SHOW_INFO: Toast.makeText(MrCCActivity.this,msg.getData().getString(Constant.MESSAGE), 4000).show(); break; case Constant.ToAbout: toAbout(); break; case Constant.ToMenu: toGame(); break; case Constant.LOADING_SHOW: progressDialog.show(); break; case Constant.LOADING_HIDE: progressDialog.hide(); break; case Constant.VIBRATOR_DEF: vibrate(300); break; case Constant.VIBRATOR_LONG: vibrate(1000); break; } } }; @Override protected void onCreate(android.os.Bundle savedInstanceState) { super.onCreate(savedInstanceState); startMyGame(); } public void startMyGame(){ //设置进度条 progressDialog=new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setMessage("加载中..."); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(!gameing){ handler.sendEmptyMessage(Constant.ToMenu); return false; } return super.onKeyDown(keyCode, event); } @Override public void onResume() { super.onResume(); if(Asset.bgMusic!=null) Asset.bgMusic.play(); } @Override protected void onPause() { super.onPause(); if(Asset.bgMusic!=null) Asset.bgMusic.pause(); } @Override public void finish() { if(Asset.bgMusic!=null) Asset.bgMusic.stop(); Asset.bgMusic=null; super.finish(); } @Override public Screen getStartScreen() { return new LoadScreen(this); } @Override public void afterCreate() { //首先加载背景图片 Asset.background=GM.loadBitmap("imgs/bg.jpg"); //设置进度条的颜色 this.getGameBar().barColor=Constant.CELL_COLOR; } @Override public Handler getHandler() { return handler; } private void toAbout(){ if(aboutView==null){ handler.sendEmptyMessage(Constant.LOADING_SHOW); LayoutInflater lif=LayoutInflater.from(MrCCActivity.this); aboutView=lif.inflate(R.layout.about, null); webView=(WebView)aboutView.findViewById(R.id.webview); webView.setWebChromeClient(new WebChromeClient(){ @Override public void onProgressChanged(WebView view, int newProgress) { if(newProgress==100) handler.sendEmptyMessage(Constant.LOADING_HIDE); super.onProgressChanged(view, newProgress); } }); webView.loadUrl("file:///android_asset/html/about.html"); } gameView.pause(); gameing=false; setContentView(aboutView); } private void toGame(){ gameView.resume(); gameing=true; setContentView(gameView); } public void vibrate(long ms){ if(Setting.vibrateAble){ Vibrator v=(Vibrator)getSystemService(Service.VIBRATOR_SERVICE); v.vibrate(ms); } } }
框架中的 GameSurfaceView类:
package dt.humen.game; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; import android.view.SurfaceHolder; import android.view.SurfaceView; import dt.humen.game.core.impl.DTGame; /** *这个surfaceView 只负责显示 * * @创建者 :集成显卡 1053214511@qq.com * @创建日期 :2012-1-26 * @修改记录 : */ public class GameSurfaceView extends SurfaceView implements Runnable{ public DTGame game; public Bitmap gameBuffer; public SurfaceHolder holder; public Thread thread; public int sleep=0;//线程间隔 public boolean running=false;//游戏是否在进行 public GameSurfaceView(DTGame game,Bitmap map) { super(game); this.game=game; this.gameBuffer=map; this.holder=getHolder(); } /** * 游戏恢复时 * * @date :2012-1-23 */ public void resume() { running = true; thread = new Thread(this); thread.start(); System.out.println("线程开启!---->"); } /** * 游戏暂停时 * * @date :2012-1-23 */ public void pause() { running = false; System.out.println("线程暂停!---->"); while(true) { try { thread.join(); break; } catch (InterruptedException e) { } } } @Override public void run() { Rect rect=new Rect(); while(running){ //如果没有可用的外观,就直接跳过 if(!holder.getSurface().isValid()) continue; //让game的画面更新 game.getScreen().update(); game.getScreen().draw(); //将更新后的画布画到屏幕上 Canvas canvas=holder.lockCanvas(); canvas.getClipBounds(rect); //将gameBuffer 这个 bitmap 画到屏幕上 canvas.drawBitmap(gameBuffer, null, rect, null); holder.unlockCanvasAndPost(canvas); try{ Thread.sleep(sleep); }catch(Exception r){} } } public void setSleep(int time){ this.sleep=time; if(sleep<0) sleep=0; } }
每个Screen都要重写Screen的 draw 和update 方法,前者是绘图,后者是事件处理,这里贴出游戏主菜单 MenuScreen.java 的代码:
package cn.dt.mr_cc.screen; import java.util.List; import cn.dt.mr_cc.Asset; import cn.dt.mr_cc.Constant; import cn.dt.mr_cc.Setting; import dt.humen.game.Screen; import dt.humen.game.core.Game; import dt.humen.game.unit.Cell; import dt.humen.game.unit.Point; import dt.humen.io.Input; import dt.humen.io.Input.TouchEvent; public class MenuScreen extends Screen{ public int count=0; private Cell startCell; private Cell exitCell; private Cell optionCell; private Cell aboutCell; public MenuScreen(Game game) { super(game); init(); } private void init(){ startCell=new Cell(120, 360,Asset.startBtn,Asset.selectSound); exitCell=new Cell(120, 360, Asset.exitBtn,Asset.selectSound); optionCell=new Cell(120,360,Asset.optionBtn,Asset.downSound); aboutCell=new Cell(120,360,Asset.aboutBtn,Asset.selectSound); //开始动画! exitCell.getAnimate().setEndPoint(new Point(230,360)).start(350); optionCell.getAnimate().setEndPoint(new Point(160,400)).start(350); aboutCell.getAnimate().setEndPoint(new Point(10,360)).start(350); startCell.getAnimate().setEndPoint(new Point(80,400)).start(350); } @Override public void dispose() { } @Override public void pause() { } @Override public void draw() { game.getCanvas().drawBitmap(Asset.background, 0, 0, null); game.getCanvas().drawBitmap(Asset.logoPNG, 15, 30, null); startCell.draw(game.getCanvas()); exitCell.draw(game.getCanvas()); optionCell.draw(game.getCanvas()); aboutCell.draw(game.getCanvas()); } @Override public void resume() { } @Override public void update() { List<TouchEvent> list=game.getInput().getTouchEvents(); if(list.size()==0) return ; TouchEvent e=list.get(0); if(e.type==Input.TOUCH_DOWN){ //判断是否按下了菜单按钮 //说明 if(aboutCell.isClick(e.x, e.y,Setting.soundAble)){ toAbout(); } //开始 else if(startCell.isClick(e.x, e.y,Setting.soundAble)){ game.setScreen(new SelectScreen(game)); } else if(optionCell.isClick(e.x, e.y,Setting.soundAble)){ game.setScreen(new SettingScreen(game)); } //退出 else if(exitCell.isClick(e.x, e.y,Setting.soundAble)){ /* * 因为是线程里面更新UI,需要使用Looper帮助 * 还可以使用handler机制,给Activity传递一个Message然后更新UI * * ps: * 使用Looper会产生一个bug:当点击退出按钮时,可以成功退出,但是两次打开程序时会失去响应! * 用Handler就没有问题 */ //Looper.prepare(); game.getHandler().sendEmptyMessage(Constant.GAME_EXIT); //Looper.loop(); } } } private void toAbout(){ game.getHandler().sendEmptyMessage(Constant.ToAbout); } }
这里就只介绍这么多了。有兴趣的可以下载看看:下载源代码