程序运行画面
可以通过上下左右键控制人物行走
思路
启动一个线程来不断的刷帧
在每一帧里重新绘制游戏画面
在每一帧里对鼠标点击事件作出响应,维护好游戏逻辑
需求分析
怎么实现键盘点击事件的响应。
通过Override onKeyDown函数实现。
值得注意的是
如果游戏的主画面是自定义的View,那么记得要在其初始化函数中加上setFocusable(true)
否则将不会对键盘点击事件作出响应,因为自定义的视图并没有获得焦点,因而无法对键盘点击事件作出响应。
怎么实现绘制一幅图片的特定区域。
canvas.drawBitmap函数有多个版本。
为了绘制一幅图片的指定区域,我们使用的是下面的版本
canvas.drawBitmap(Bitmap bitmap,Rect rect1,Rect rect2,Paint paint)
rect1用于指定截图区域
rect2用于指定展示区域
代码实现
MainActivity.java
package com.example.move;import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.Window;import android.view.WindowManager;public class MainActivity extends Activity { GameView gameView; //GameViewDrawThread gameViewDrawThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); //setContentView(R.layout.main); gameView=new GameView(this); setContentView(gameView); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; }}
GameViewDrawThread.java
package com.example.move;import android.graphics.Canvas;import android.view.SurfaceHolder;class GameViewDrawThread extends Thread{ private int sleepSpan=100; private boolean flag=true; GameView gameView; SurfaceHolder surfaceHolder=null; public GameViewDrawThread(GameView gameView,SurfaceHolder surfaceHolder) { this.gameView=gameView; this.surfaceHolder=surfaceHolder; } public void run() { while(flag) { Canvas c=null; try { //锁定整个画布,在内存要求比较高的情况下,建议参数不要为null c=surfaceHolder.lockCanvas(null); synchronized(this.surfaceHolder) { try { gameView.onDraw(c); } catch(Exception e){}; } } finally { if(c!=null) { if(c!=null) { surfaceHolder.unlockCanvasAndPost(c); } } } try { Thread.sleep(sleepSpan); } catch(Exception e) { e.printStackTrace(); } } } public void setFlag(boolean flag) { this.flag=flag; }}
GameView.java
package com.example.move;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.view.KeyEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.widget.Toast;class GameView extends SurfaceView implements SurfaceHolder.Callback{ MainActivity activity; Paint paint; Bitmap image_sprite; GameViewDrawThread gameViewDrawThread; Sprite sprite; SurfaceHolder holder; //Measures int sprite_width=32; int sprite_height=48; int unit=48; int box_x=0; int box_y=0; int box_width=0; int box_height=0; int bound_left,bound_right,bound_up,bound_down; public GameView(MainActivity activity) { super(activity); this.activity=activity; this.sprite=new Sprite(3*unit,2*unit,sprite_width,sprite_height,0,0,0,true); gameViewDrawThread=new GameViewDrawThread(this,getHolder()); gameViewDrawThread.start(); holder=this.getHolder(); holder.addCallback(this); initBitmap(); setFocusable(true); } public void initBitmap() { paint=new Paint(); image_sprite=BitmapFactory.decodeResource(getResources(),R.drawable.sprite); } protected void onDraw(Canvas canvas) { //canvas.drawRect(0,0,box_width,box_height,paint); paint.setAntiAlias(true); canvas.drawColor(Color.WHITE); canvas.save(); int cur_x=sprite.status*sprite.w; int cur_y=sprite.direction*sprite.h; Rect src = new Rect();// 图片 Rect dst = new Rect();// 屏幕位置及尺寸 //src 这个是表示绘画图片的大小 src.left =cur_x; src.top = cur_y; src.right =cur_x+sprite_width; src.bottom =cur_y+sprite_height; // 下面的 dst 是表示 绘画这个图片的位置 dst.left =sprite.x; dst.top =sprite.y; dst.right =sprite.x+sprite_width; dst.bottom =sprite.y+sprite_height; canvas.drawBitmap(image_sprite, src, dst, null);//这个方法 第一个参数是图片原来的大小,第二个参数是 绘画该图片需显示多少。也就是说你想绘画该图片的某一些地方,而不是全部图片,第三个参数表示该图片绘画的位置 src = null; dst = null; System.out.println(sprite.direction+" "+sprite.x+" "+sprite.y); /*canvas.clipRect(sprite.x,sprite.y,sprite.x+sprite_width,sprite.y+sprite_height); canvas.drawBitmap(image_sprite,sprite.x,sprite.y,paint);*/ canvas.restore(); } public void surfaceDestroyed(SurfaceHolder holder) { boolean retry=true; gameViewDrawThread.setFlag(false);//note while(retry) { try { gameViewDrawThread.join();//不断尝试执行此行代码,直到成功 retry=false; } catch(InterruptedException e) { } } } @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 box_width=this.getWidth(); box_height=this.getHeight(); bound_left=box_x; bound_right=box_x+box_width-unit; bound_up=box_y; bound_down=box_y+box_height-unit; } @Override public boolean onKeyDown(int key,KeyEvent event) { //Toast.makeText(activity, "HELLO", 1000); //System.out.println("change"); int cur_direction=0; switch(key) { case KeyEvent.KEYCODE_DPAD_UP: sprite.y-=unit; if(sprite.y<bound_up) sprite.y=bound_up; cur_direction=3; break; case KeyEvent.KEYCODE_DPAD_DOWN: sprite.y+=unit; if(sprite.y>bound_down) sprite.y=bound_down; cur_direction=0; break; case KeyEvent.KEYCODE_DPAD_LEFT: sprite.x-=unit; if(sprite.x<bound_left) sprite.x=bound_left; cur_direction=1; break; case KeyEvent.KEYCODE_DPAD_RIGHT: sprite.x+=unit; if(sprite.x>bound_right) sprite.x=bound_right; cur_direction=2; break; } if(cur_direction!=sprite.direction) { sprite.direction=cur_direction; sprite.status=0; } else { sprite.status=(sprite.status+1)%4; } return super.onKeyDown(key, event); //return true; } }
sprite.java
package com.example.move;public class Sprite{ int x,y,w,h,direction,status,speed; boolean flag; public Sprite(int x,int y,int sw,int sh,int direction,int status,int speed,boolean flag) { this.x=x; this.y=y; this.w=sw; this.h=sh; this.direction=direction; this.status=status; this.speed=speed; this.flag=flag; }}
使用android实现人物行走的思路和使用Html5实现人物行走的思路是相近的,代码的写法也差不多。
具体可以参考另一篇文章
HTML5 实现人物行走