package com.android.gameview5;
import java.io.InputStream;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.Display;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
public class SurfaceViewActivity extends Activity{
AnimView mAnimView = null;
public
void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//全屏显示
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
//获得屏幕的宽高
Display
display =
getWindowManager().getDefaultDisplay();
mAnimView = new
AnimView(this,display.getWidth(),display.getHeight());
setContentView(mAnimView);
}
public
class AnimView extends SurfaceView implements
Callback,Runnable{
public final static int
ANIM_DOWN =0;
public final static int
ANIM_LEFT=1;
public final static int
ANIM_RIGHT =2;
public final static int
ANIM_UP =3;
public final static int
ANIM_COUNT =4;
Animation
heroAnimation[] = new Animation[ANIM_COUNT];
Paint mPaint
= null;
private boolean
mAllkeyDown = false;
private boolean
mIskeyDown = false;
private boolean
mIskeyLeft = false;
private boolean
mIskeyRight = false;
private boolean mIskeyUp
= false;
//当前绘制动画的Id
int
mAnimationState =0;
//tile块的宽跟高
public
final static int TILE_WIDTH =32;
public
final static int TILE_HEIGHT =32;
//缓冲块的宽和高的数量
public
final static int BUFFER_WIDTH_COUNT =10;
public
final static int BUFFER_HEIGHT_COUNT = 15;
//场景的宽和高
public
final static int SCENCE_WIDTH = 480;
public
final static int SCENCE_HEIGHT = 800;
//场景偏移量,未到场景边界地图向回滚动
public
final static int SCENCE_OFFSET = 3;
public
final static int SCENCE_OFFSET_WIDTH =100;
//场景块的宽和高的数量
public
final static int TILE_WIDTH_COUNT= 15;
public
final static int TILE_HEIGHT_COUNT =25;
//数组元素为0 则什么都不画
public
final static int TILE_NULL = 0;
// 第一层游戏View地图数组
public int[][] mMapView
= {
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 } };
// 第二层游戏实体actor数组
public int[][]
mMapAcotor = {
{ 5, 6, 7, 0, 3, 4, 3,
4, 3, 4, 0, 0, 2, 2, 0 },
{ 13, 14, 15, 0, 11, 12,
11, 12, 11, 12, 0, 0, 10, 10, 0 },
{ 21, 22, 23, 0, 19, 20,
19, 20, 19, 20, 0, 0, 18, 18, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2 },
{ 10, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 10 },
{ 18, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 18 },
{ 8, 8, 8, 8, 9, 0, 0,
0, 0, 0, 9, 8, 8, 8, 8 },
{ 8, 8, 8, 8, 17, 0, 0,
0, 0, 0, 17, 8, 8, 8, 8 },
{ 3, 4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2, 5, 6, 7 },
{ 11, 12, 0, 0, 0, 0, 0,
0, 0, 0, 0, 10, 13, 14, 15 },
{ 19, 20, 0, 0, 0, 0, 0,
0, 0, 0, 0, 18, 21, 22, 23 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 8, 8, 8, 8, 9, 0, 0,
0, 0, 0, 9, 8, 8, 8, 8 },
{ 8, 8, 8, 8, 17, 0, 0,
0, 0, 0, 17, 8, 8, 8, 8 },
{ 5, 6, 7, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 3, 4 },
{ 13, 14, 15, 10, 0, 0,
0, 0, 0, 0, 0, 0, 0, 11, 12 },
{ 21, 22, 23, 18, 0, 0,
0, 0, 0, 0, 0, 0, 0, 19, 20 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } };
// 第三层游戏碰撞物理层数组
public int[][]
mCollision = {
{ -1, -1, -1, 0, -1, -1,
-1, -1, -1, -1, 0, 0, -1, -1, 0 },
{ -1, -1, -1, 0, -1, -1,
-1, -1, -1, -1, 0, 0, -1, -1, 0 },
{ -1, -1, -1, 0, -1, -1,
-1, -1, -1, -1, 0, 0, -1, -1, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ -1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, -1 },
{ -1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, -1 },
{ -1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, -1 },
{ -1, -1, -1, -1, -1, 0,
0, 0, 0, 0, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, 0,
0, 0, 0, 0, -1, -1, -1, -1, -1 },
{ -1, -1, 0, 0, 0, 0, 0,
0, 0, 0, 0, -1, -1, -1, -1 },
{ -1, -1, 0, 0, 0, 0, 0,
0, 0, 0, 0, -1, -1, -1, -1 },
{ -1, -1, 0, 0, 0, 0, 0,
0, 0, 0, 0, -1, -1, -1, -1 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
{ -1, -1, -1, -1, -1, 0,
0, 0, 0, 0, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, 0,
0, 0, 0, 0, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, 0, 0,
0, 0, 0, 0, 0, 0, 0, -1, -1 },
{ -1, -1, -1, -1, 0, 0,
0, 0, 0, 0, 0, 0, 0, -1, -1 },
{ -1, -1, -1, -1, 0, 0,
0, 0, 0, 0, 0, 0, 0, -1, -1 },
{ 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } };
//游戏地图资源
Bitmap
mBitmap = null;
//资源文件
Resources mResources = null;
//地图资源横向纵向tile块的数量
int
mWidthTileCount =0;
int
mHeightTileCount =0;
//地图横向纵向的大小
int
mBitMapWidth = 0;
int
mBitMapHeight =0;
//英雄在地图中的坐标以英雄脚底中心为原点
int
mHeroPosX =0;
int
mHeroPosY =0;
// 备份英雄发生碰撞以前的坐标点
int mBackHeroPosX =
0;
int mBackHeroPosY =
0;
//备份英雄发生碰撞以前的坐标点
int
mBackHeroScreenX =0;
int
mBackHeroScreenY =0;
//英雄在地图中绘制的坐标
int
mHeroImageX = 0;
int
mHeroImageY =0;
//英雄在行走范围中绘制的坐标
int
mHeroScreenX =0;
int
mHeroScreenY =0;
//英雄在地图二维数组中的索引
int
mHeroIndexX =0;
int
mHeroIndexY =0;
//屏幕的尺寸
int
mScreenWidth =0;
int
mScreenHeight =0;
//缓冲去数据的index
int
mBufferIndexX = 0;
int
mBufferIndexY =0;
//地图坐标
int
mMapPosX =0;
int
mMapPosY =0;
//人物图片资源与实际英雄脚底坐标的便宜
public
final static int OFF_HERO_X = 16;
public
final static int OFF_HERO_Y = 35;
//主角行走的步长
public
final static int HERO_STEP =8;
//与实体层发生碰撞
private boolean isAcotorCollision = false;
//与边界发生碰撞
private boolean isBorderCollision = false;
//游戏主线程
private Thread mThread = null;
//循环标志
private boolean mIsRuning = false;
private SurfaceHolder mSurfaceHolder =
null;
private Canvas mCanvas =
null;
public
AnimView(Context context,int screenWidth,int screenHeight){
super(context);
mPaint
= new Paint();
mScreenWidth = screenWidth;
mScreenHeight = screenHeight;
initAnimation(context);
initMap(context);
initHero();
//获取mSurfaceHolder
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
setFocusable(true);
}
private void initHero(){
mHeroImageX =100;
mHeroImageY =100;
mHeroPosX = mHeroImageX +OFF_HERO_X;
mHeroPosY = mHeroImageY +OFF_HERO_Y;
mHeroIndexX = mHeroPosX/TILE_WIDTH;
mHeroIndexY = mHeroPosY /TILE_HEIGHT;
mHeroScreenX = mHeroPosX;
mHeroScreenY = mHeroPosY;
}
private void
initMap(Context context){
mBitmap =
ReaderBitmap(context,R.drawable.map);
mBitMapWidth =
mBitmap.getWidth();
mBitMapHeight =
mBitmap.getHeight();
mWidthTileCount =
mBitMapWidth /TILE_WIDTH;
mHeightTileCount =
mBitMapHeight/TILE_HEIGHT;
}
private void
initAnimation(Context context){
Bitmap bitmap =
ReaderBitmap(context,R.drawable.hero);
Bitmap[][] testBitmap =
new Bitmap[ANIM_COUNT][ANIM_COUNT];
int widthTile =
bitmap.getWidth()/ANIM_COUNT;
int heightTile =
bitmap.getHeight()/ANIM_COUNT;
int i =0,x=0,y =0;
for(i
=0;i
y =0;
testBitmap[ANIM_DOWN][i]
= BitmapClipBitmap(bitmap,x,y,widthTile,heightTile);
y+=heightTile;
testBitmap[ANIM_LEFT][i]
= BitmapClipBitmap(bitmap,x,y,widthTile,heightTile);
y+=heightTile;
testBitmap[ANIM_RIGHT][i] =
BitmapClipBitmap(bitmap,x,y,widthTile,heightTile);
y+=heightTile;
testBitmap[ANIM_UP][i] =
BitmapClipBitmap(bitmap,x,y,widthTile,heightTile);
x+=widthTile;
}
heroAnimation[ANIM_DOWN]= new
Animation(context,testBitmap[ANIM_DOWN],true);
heroAnimation[ANIM_LEFT]
= new Animation(context,testBitmap[ANIM_LEFT],true);
heroAnimation[ANIM_RIGHT] = new
Animation(context,testBitmap[ANIM_RIGHT],true);
heroAnimation[ANIM_UP] =
new Animation(context,testBitmap[ANIM_UP],true);
}
protected void
Draw(){
//绘制地图
DrawMap(mCanvas,mPaint,mBitmap);
//绘制动画
ReaderAnimation(mCanvas);
//更新动画
UpdateHero();
}
private void
UpdateHero(){
if(mAllkeyDown){
if(mIskeyDown){
mAnimationState =
ANIM_DOWN;
mHeroPosY+=HERO_STEP;
if(mHeroScreenY>=320){
if(mHeroIndexY>=10&&mHeroIndexY<=20){
mMapPosY
-=HERO_STEP;
}else{
mHeroScreenY
+=HERO_STEP;
}
}else{
mHeroScreenY+=HERO_STEP;
}
}else
if(mIskeyLeft){
mAnimationState =
ANIM_LEFT;
mHeroPosX
-=HERO_STEP;
if(mHeroScreenX<=96){
if(mHeroIndexX>=3&&mHeroIndexY<=7){
mMapPosX+=HERO_STEP;
}else {
mHeroScreenX
-=HERO_STEP;
}
}else{
mHeroScreenX-=HERO_STEP;
}
}else
if(mIskeyRight){
mAnimationState =
ANIM_RIGHT;
mHeroPosX+=HERO_STEP;
if(mHeroScreenX
>=192){
if(mHeroIndexX>=6&&mHeroIndexX<=10){
mMapPosX
-=HERO_STEP;
}else {
mHeroScreenX
+=HERO_STEP;
}
}else{
mHeroScreenX
+=HERO_STEP;
}
}else
if(mIskeyUp){
mAnimationState =
ANIM_UP;
mHeroPosY-=HERO_STEP;
if(mHeroScreenY
<=160){
if(mHeroIndexY
>=5&&mHeroIndexY<=15){
mMapPosY+=HERO_STEP;
}else {
mHeroScreenY-=HERO_STEP;
}
}else {
mHeroScreenY
-=HERO_STEP;
}
}
//算出英雄移动后在地图二位数组中的索引
mHeroIndexX =
mHeroPosX/TILE_WIDTH;
mHeroIndexY =
mHeroPosY/TILE_HEIGHT;
//检测人物是否出屏
isBorderCollision =
false;
if(mHeroPosX<=0){
mHeroPosX =0;
mHeroScreenX = 0;
isBorderCollision =
true;
}else
if(mHeroPosX>=TILE_WIDTH*TILE_WIDTH_COUNT){
mHeroPosX =
TILE_WIDTH*TILE_WIDTH_COUNT;
mHeroScreenX =
mScreenWidth;
isBorderCollision =
true;
}
if(mHeroPosY<=0){
mHeroPosY =0;
mHeroScreenY =0;
isBorderCollision =
true;
}else if(mHeroPosY
>=TILE_HEIGHT*TILE_HEIGHT_COUNT){
mHeroPosY =
TILE_HEIGHT*TILE_HEIGHT_COUNT;
mHeroScreenY =
mScreenHeight;
isBorderCollision =
true;
}
//防止地图越界
if(mMapPosX
>=0) {
mMapPosX=0;
}else
if(mMapPosX<=-(480-320)) {
mMapPosX = -(480-320);
}
if(mMapPosY
>=0) {
mMapPosY=0;
}else
if(mMapPosY<= -(800 - 480)) {
mMapPosY = -(800 - 480);
}
//越界检测
int width =
mCollision[0].length-1;
int height =
mCollision.length-1;
if(mHeroIndexX
<=0){
mHeroIndexX =0;
}else if(mHeroIndexX
>=width){
mHeroIndexX
=width;
}
if(mHeroIndexY
<=0){
mHeroIndexY =0;
}else if(mHeroIndexY
>=height){
mHeroIndexY
=height;
}
//碰撞检测
if(mCollision[mHeroIndexY][mHeroIndexX]==-1){
mHeroPosX =
mBackHeroPosX;
mHeroPosY =
mBackHeroPosY;
mHeroScreenY =
mBackHeroScreenY;
mHeroScreenX =
mBackHeroScreenX;
isAcotorCollision=
true;
}else{
mBackHeroPosX =
mHeroPosX;
mBackHeroPosY =
mHeroPosY;
mBackHeroScreenX =
mHeroScreenX;
mBackHeroScreenY =
mHeroScreenY;
isAcotorCollision =
true;
}
mHeroImageX =
mHeroScreenX - OFF_HERO_X;
mHeroImageY =
mHeroScreenY - OFF_HERO_Y;
}
}
private void
ReaderAnimation(Canvas canvas){
if(mAllkeyDown){
heroAnimation[mAnimationState].DrawAnimtion(canvas, mPaint,
mHeroImageX, mHeroImageY);
}else {
heroAnimation[mAnimationState].DrawFrame(canvas, mPaint,
mHeroImageX, mHeroImageY, 0);
}
}
public void
setKeyState(int keyCode,boolean state){
switch(keyCode){
case
KeyEvent.KEYCODE_DPAD_DOWN:
mIskeyDown =
state;
break;
case
KeyEvent.KEYCODE_DPAD_LEFT:
mIskeyLeft =
state;
break;
case
KeyEvent.KEYCODE_DPAD_RIGHT:
mIskeyRight =
state;
break;
case
KeyEvent.KEYCODE_DPAD_UP:
mIskeyUp = state;
break;
}
mAllkeyDown =
state;
}
private void DrawMap(Canvas canvas,Paint
paint,Bitmap bitmap){
int
i,j;
for(i
=0;i
for(j
=0;j
int
ViewID = mMapView[i][j];
int
ActorID = mMapAcotor[i][j];
if(ViewID>TILE_NULL){
DrawMapTile(ViewID,canvas,paint,bitmap,mMapPosX+(j*TILE_WIDTH),mMapPosY+(i*TILE_HEIGHT));
}
//绘制地图第二层
if(ActorID>TILE_NULL){
DrawMapTile(ActorID,canvas,paint,bitmap,
mMapPosX+(j*TILE_WIDTH),mMapPosY+(i*TILE_HEIGHT));
}
}
}
}
private void DrawMapTile(int id,Canvas
canvas,Paint paint,Bitmap bitmap,int x,int y){
id--;
int
count = id/mWidthTileCount;
int
bitmapX =
(id-(count*mWidthTileCount))*TILE_WIDTH;
int
bitmapY = count*TILE_HEIGHT;
DrawClipImage(canvas,paint,bitmap,x,y,bitmapX,bitmapY,TILE_WIDTH,TILE_HEIGHT);
}
private void DrawClipImage(Canvas canvas,Paint
paint,Bitmap bitmap,int x,int y,int src_x,int src_y,int width,int
height){
canvas.save();
canvas.clipRect(x,y,x+width,y+height);
canvas.drawBitmap(bitmap, x-src_x, y-src_y,
paint);
canvas.restore();
}
public
Bitmap BitmapClipBitmap(Bitmap bitmap,int x,int y,int w,int
h){
return
Bitmap.createBitmap(bitmap, x, y, w, h);
}
public
Bitmap ReaderBitmap(Context context, int resId){
BitmapFactory.Options opt = new
BitmapFactory.Options();
opt.inPreferredConfig =
Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
InputStream is =
context.getResources().openRawResource(resId);
return
BitmapFactory.decodeStream(is, null, opt);
}
public void run() {
while(mIsRuning){
synchronized(mSurfaceHolder){
mCanvas = mSurfaceHolder.lockCanvas();
Draw();
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsRuning = true;
mThread = new Thread(this);
mThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsRuning = false;
}
}
public
boolean onKeyDown(int keyCode, KeyEvent event){
mAnimView.setKeyState(keyCode, true);
return
super.onKeyDown(keyCode, event);
}
public
boolean onKeyUp(int keyCode, KeyEvent event){
mAnimView.setKeyState(keyCode, false);
return
super.onKeyUp(keyCode, event);
}
}