程序运行画面
可以通过上下左右键控制人物行走
思路
启动一个线程来不断的刷帧
在每一帧里重新绘制游戏画面
在每一帧里对鼠标点击事件作出响应,维护好游戏逻辑
需求分析
怎么实现键盘点击事件的响应。
通过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实现人物行走的思路是相近的,代码的写法也差不多。
具体可以参考另一篇文章