先看一下效果图。
我们的目标是:通过键盘按键,控制人物在屏幕上自由移动。要实现这个目标,只要完成下面三件事就行:1. 监听键盘,获取按键值 2. 根据按键值,修改人物在屏幕上的坐标 3. 在新的坐标位置显示人物
下面是程序的基本框图。
如上图所示:主Activity依次:创建人物、创建键盘监听线程、启动键盘监听线程、显示游戏界面。在游戏界面启动后,游戏界面绘图线程随之启动。绘图线程每隔固定时间对屏幕进行一次刷新。键盘监听线程启动后,会捕获按键值,然后根据按键值来修改人物显示坐标。人物显示坐标改变后,下次绘图线程就可以新的地方把人物画出来。
package com.mapAndSprit; import android.app.Activity; import android.os.Bundle; import android.view.KeyEvent; public class MapAndSpritActivity extends Activity { //游戏界面 GameView gameView; //人物 MySprite mySprite; //键盘监听线程 KeyThread kt; //键盘动作 int action = 0; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); gameView = new GameView( this ); mySprite = new MySprite( this ); kt = new KeyThread( this ); kt.start(); //显示游戏界面 setContentView( gameView ); } //按键按下 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if(keyCode == 19){//上 action = action | 0x08; } if(keyCode == 20){//下 action = action | 0x04; } if(keyCode == 21){//左 action = action | 0x02; } if(keyCode == 22){//右 action = action | 0x01; } return false; } //按键抬起 @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if(keyCode == 19){//上 action = action & 0x37; } if(keyCode == 20){//下 action = action & 0x3B; } if(keyCode == 21){//左 action = action & 0x3D; } if(keyCode == 22){//右 action = action & 0x3E; } return false; } }
package com.mapAndSprit; public class KeyThread extends Thread { MapAndSpritActivity mapAndSpritActivity; boolean flag = true; int sleepSpan = 50; int action; boolean KEY_UP = false; boolean KEY_DOWN = false; boolean KEY_LEFT = false; boolean KEY_RIGHT = false; public KeyThread( MapAndSpritActivity mapAndSpritActivity ) { this.mapAndSpritActivity = mapAndSpritActivity; } public void run() { while( flag ) { action = mapAndSpritActivity.action; if((action & 0x08) != 0){//上 KEY_UP = true; } else{ KEY_UP = false; } if((action & 0x04) != 0){//下 KEY_DOWN = true; } else{ KEY_DOWN = false; } if((action & 0x02) != 0){//左 KEY_LEFT = true; } else{ KEY_LEFT = false; } if((action & 0x01) != 0){//右 KEY_RIGHT = true; } else{ KEY_RIGHT = false; } if( KEY_UP ) { if( !( mapAndSpritActivity.mySprite.curJ < 1 ) ) { mapAndSpritActivity.mySprite.curJ -= 1; } } if( KEY_DOWN ) { if( !( mapAndSpritActivity.mySprite.curJ >15 ) ) { mapAndSpritActivity.mySprite.curJ += 1; } } if( KEY_LEFT ) { if( !( mapAndSpritActivity.mySprite.curI < 1 ) ) { mapAndSpritActivity.mySprite.curI -= 1; } } if( KEY_RIGHT ) { if( !( mapAndSpritActivity.mySprite.curI > 10 ) ) { mapAndSpritActivity.mySprite.curI += 1; } } try{ //睡眠sleepSpan毫秒 Thread.sleep( sleepSpan ); } catch(Exception e){ e.printStackTrace(); } } } }
package com.mapAndSprit; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; public class MySprite { MapAndSpritActivity mapAndSpritActivity; Bitmap man; //人物在地图显示的位置 int curI = 0; int curJ = 0; int curX = 0; int curY = 0; public MySprite( MapAndSpritActivity mapAndSpritActivity ) { this.mapAndSpritActivity = mapAndSpritActivity; man = BitmapFactory.decodeResource( mapAndSpritActivity.getResources(), R.drawable.a1 ); } public void drawSelf( Canvas c, Paint paint ) { //把屏幕分成虚拟的10 * 15的网格,每个格子大小 20 * 20 //每次走动一个格子 curX = this.mapAndSpritActivity.gameView.initX + curI * 20; curY = this.mapAndSpritActivity.gameView.initX + curJ * 20; c.drawBitmap( man, curX, curY, paint ); } }
package com.mapAndSprit; import android.graphics.Canvas; import android.graphics.Color; import android.view.SurfaceHolder; import android.view.SurfaceView; public class GameView extends SurfaceView implements SurfaceHolder.Callback { MapAndSpritActivity mapAndSpritActivity; GameViewDrawThread gameViewDrawThread; SurfaceHolder holder; //人物能在屏幕上显示的最左上角的位置 int initX = 20; int initY = 20; public GameView( MapAndSpritActivity mapAndSpritActivity ) { super( mapAndSpritActivity ); this.mapAndSpritActivity = mapAndSpritActivity; holder = getHolder(); holder.addCallback( this ); gameViewDrawThread = new GameViewDrawThread( this, holder ); } public void onDraw( Canvas c ) { c.drawColor( Color.BLUE ); mapAndSpritActivity.mySprite.drawSelf( c, null ); } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder arg0) { // TODO Auto-generated method stub gameViewDrawThread.setFlag( true ); gameViewDrawThread.start(); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub boolean retry = true; //停止刷帧线程 gameViewDrawThread.setFlag(false); //不断地循环,直到等待的线程结束 while (retry) { try { //等待刷帧线程结束 gameViewDrawThread.join(); retry = false; } catch (InterruptedException e) { } } } }
package com.mapAndSprit; import android.graphics.Canvas; import android.view.SurfaceHolder; public class GameViewDrawThread extends Thread { private GameView gameView; private SurfaceHolder holder; boolean isRun; int sleepSpan = 200; public GameViewDrawThread( GameView gameView, SurfaceHolder holder ) { this.gameView = gameView; this.holder = holder; isRun = true; } public void setFlag( boolean flag ) { isRun = flag; } @Override public void run() { // TODO Auto-generated method stub while( isRun ) { Canvas c = null; try { c = holder.lockCanvas(); synchronized( holder ) { //调用绘图函数 gameView.onDraw( c ); } }finally { if( c != null ) { holder.unlockCanvasAndPost( c ); } } try{ //睡眠200毫秒 Thread.sleep( sleepSpan ); } catch(Exception e){ e.printStackTrace(); } } } }