android碰撞测试与SurfaceView

本文介绍了一个基于Android平台的游戏开发实例,详细展示了如何使用SurfaceView进行游戏画面的绘制与更新,包括角色移动、地图绘制及简单的碰撞检测等核心功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package game.project;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Region.Op;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class SurfaceView01 extends SurfaceView implements Callback, Runnable {

	SurfaceHolder holder;
	Canvas canvas;
	Paint paint;
	boolean isGame;
	TestCollisionActivity activity;
	
	final int UP = 1;
	final int DOWN = 0;
	final int LEFT = 2;
	final int RIGHT = 3;
	int playerX,playerY,playerW,playerH;
	boolean isMove;
	int direction = DOWN;
	int speed;
	int frameIndex;
	Bitmap role;
	
	Bitmap mapImg;
	int tileW ,tileH,tileNum;
	int mapX,mapY;
	int mapW,mapH;
	int map[][] ={
			{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 
				0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
				{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 
				0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
				{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 
				0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
				{ 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 
				0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
				{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
				0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
				{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
				0, 0, 0, 0, 0, 0, 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, 1, 1, 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, 1, 1, 0, 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, 0, 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, 0, 0, 0, 0, 0, 0, 0 },
				{ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 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, 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, 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, 
				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, 1, 1, 1, 1, 1, 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, 1, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
				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, 
				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, 
				1, 0, 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, 
				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, 
				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, 
				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, 
				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, 
				1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
				{ 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 },
				{ 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 },
				{ 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, 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, 0, 
				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
				};
	//在View的构造函数中是拿不到view有关的任何信息的,因为它还没有构建好
	public SurfaceView01(Context context) { 
		super(context);
		activity=(TestCollisionActivity)context;
		holder=getHolder();
		paint=new Paint();
		paint.setAntiAlias(true);
//		获取当前SurfaceHolder 并且把它加到CallBack回调函数中
		holder.addCallback(this);
		role = BitmapFactory.decodeResource(getResources(), R.drawable.role);
		mapImg = BitmapFactory.decodeResource(getResources(), R.drawable.map);
		playerW = 27;
		playerH = 50;
		playerX = 90;
		playerY = 220;
		speed = 5;
		tileW = 16;
		tileH = 16;
		tileNum = mapImg.getWidth()/tileW;
		mapW = tileW*map[0].length;
		mapH = tileH*map.length;
		
	}
		
			
			public void run() {
				// TODO Auto-generated method stub
				while(isGame){
					move(); //人物行走(改变人物的坐标+动作帧坐标)
					render();//画图
					//这段代码是不理智的,每一次绘画完成都要停顿100ms,见下run01
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			}
		
			/**每30帧刷新一次屏幕**/  
		
		    public static final int TIME_IN_FRAME = 30;  
		public void run01() {  
		
		    	while (isGame) {  
		 /**取得更新游戏之前的时间**/  		
		 long startTime = System.currentTimeMillis();  
		 /**在这里加上线程安全锁**/  
		
		 synchronized (holder) {  
			 move(); //人物行走(改变人物的坐标+动作帧坐标)
				render();//画图
		 }  
		 /**取得更新游戏结束的时间**/  		
		 long endTime = System.currentTimeMillis();  
		 /**计算出游戏一次更新的毫秒数**/  	
		 int diffTime  = (int)(endTime - startTime);  
	 /**确保每次更新时间为30帧**/  
		 while(diffTime <=TIME_IN_FRAME) {  
		     diffTime = (int)(System.currentTimeMillis() - startTime);  
		     /**线程等待**/  
		     Thread.yield();  
		 }  
		 }  
		
		}  


//	通过callBack接口监听SurfaceView的状态
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub

	}

	//在surfaceview被创建的时候开启游戏的主线程
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		isGame=true;
		new Thread(this).start();
		
	}
	//在surfaceview结束的时候销毁activity
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		isGame=false;
		activity.finish();
	}
	

	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// TODO Auto-generated method stub
		switch (keyCode) {
		case KeyEvent.KEYCODE_DPAD_LEFT:
			isMove = true;
			direction = LEFT;
			break;
		case KeyEvent.KEYCODE_DPAD_RIGHT:
			isMove = true;
			direction = RIGHT;
			break;
		case KeyEvent.KEYCODE_DPAD_UP:
			isMove = true;
			direction = UP;
			break;
		case KeyEvent.KEYCODE_DPAD_DOWN:
			isMove = true;
			direction = DOWN;
			break;
		}
		return super.onKeyDown(keyCode, event);
	}
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		// TODO Auto-generated method stub
		//frameIndex = 0;只要停止按键后,动作都停在第一帧
			switch (keyCode) {
			case KeyEvent.KEYCODE_DPAD_LEFT:
				isMove = false;
				frameIndex = 0;
				break;
			case KeyEvent.KEYCODE_DPAD_RIGHT:
				isMove = false;
				frameIndex = 0;
				break;
			case KeyEvent.KEYCODE_DPAD_UP:
				isMove = false;
				frameIndex = 0;
				break;
			case KeyEvent.KEYCODE_DPAD_DOWN:
				isMove = false;
				frameIndex = 0;
				break;
			}
			
		return super.onKeyUp(keyCode, event);
	}

	/**人物行走
	 * 
	 */
	void move(){
		if(isMove){
			frameIndex=(frameIndex==3? 0:frameIndex+1);
			switch (direction) {
			case UP:
				if(playerY>getHeight()/2){ //人走无需滚屏,所以用了1/2屏幕做分界(考虑滚屏)
					playerY-=speed; //往上走,屏幕左上角原点(向下向右正轴)
				}else if(mapY<=-speed){ //人物不动滚屏,而且还能滚屏
					mapY+=speed;
				}else if(playerY>=speed){ //不能滚屏了,人物必须动了,但是还能走不出边界
					playerY-=speed;
				}
				break;
			case DOWN:
				if(playerY< getHeight()/2)
					playerY += speed;
				else if(mapY > getHeight()-mapH+speed)
					mapY -= speed;
				else if(playerY <= getHeight()-playerH-speed)
				{
					playerY += speed;
				}
				break;
			case LEFT:
				if(playerX>getWidth()/2)
					playerX -= speed;
				else if(mapX<-speed)
					mapX += speed;
				else if(playerX >= speed)
					playerX -= speed;
				break;
			case RIGHT:
				if(playerX<getWidth()/2)
					playerX += speed;
				else if(mapX >  getWidth()-mapW+speed)
					mapX -= speed;
				else if(playerX <= getWidth()-playerW-speed)
					playerX += speed;
				break;
			}
			
		}
	}

	/**整个游戏的画图都封装在这(地图+人物[包括动态动作])
	 * 
	 * @param canvas
	 */
	void drawGame(Canvas canvas){
		canvas.drawColor(Color.RED);
		//画出地图
		drawMap(canvas, mapImg, tileW, tileH, mapX, mapY, tileNum, map);
		//将人物抠出来
		canvas.clipRect(playerX, playerY, playerX+playerW, playerY+playerH,Op.REPLACE);
		
		//将人物画到map上,跟动画帧结合了
		canvas.drawBitmap(role, playerX-frameIndex*playerW, playerY-direction*playerH, paint);
	}
	
	/**
	 * 绘制地图
	 * @param canvas
	 * @param mapImg 地图原图图片
	 * @param tileW  每个tile的宽
	 * @param tileH  每个tile的高
	 * @param mapX   地图的X位置
	 * @param mapY   地图的Y位置
	 * @param tileNum   地图原图图片上的一行 tile的总个数 
	 * @param map   地图数组 
	 */
	void drawMap(Canvas canvas,Bitmap mapImg, int tileW,int tileH, int mapX,int mapY,int tileNum,int map[][])
	{
		
		for (int i = 0; i <map.length; i++) {
			for (int j = 0; j <map[i].length; j++) {
				if(map[i][j]!=0)
				{
					canvas.save();
					canvas.clipRect(j*tileW+mapX, i*tileH+mapY, (j+1)*tileW+mapX, i*tileH+tileH+mapY,Op.REPLACE);
					canvas.drawBitmap(mapImg, j*tileW+mapX-((map[i][j]-1)%tileNum)*tileW,
							i*tileH+mapY-((map[i][j]-1)/tileNum)*tileH, paint);
					canvas.restore();
				}
			}
		}
		
	}

	/**
	 * 封装surfaceView中著名的三步走
	 * 	锁住canvas
	 * 	画图
	 * 	释放锁然后将图呈现到屏幕上
	 */
	void render()
	{
		canvas = holder.lockCanvas();
		drawGame(canvas);
		holder.unlockCanvasAndPost(canvas);
		
	}
	/**矩阵碰撞检测
	 * 
	 * @param x
	 * @param y
	 * @param w
	 * @param h
	 * @param x1
	 * @param y1
	 * @param w1
	 * @param h1
	 * @return
	 */
	boolean collisionWith(int x,int y,int w,int h,int x1,int y1,int w1,int h1)
	{
		if(((x>=x1 &&  x<=x1+w1)|| (x+w>=x1 && x+w<=x1+w1))&&
				((y>=y1 && y<=y1+h1)||( y+h>=y1 &&y+h<= y1+h1)))
			return true;
		else
			return false;
	}
	
}
<pre name="code" class="java">package game.project;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;


public class TestCollisionActivity extends Activity {
    /** Called when the activity is first created. */
	
	GameSurfaceView surfaceView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
        		WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
        		WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        surfaceView = new GameSurfaceView(this);
        setContentView(surfaceView);
        surfaceView.setFocusable(true);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huangleijay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值