android 模拟物品移动

上次写了一个android模拟下雪的demo。

基本是模拟出来雪花飘落的效果了,但是并没有达到真正的“下雪”。因为一次只产生了几朵雪花而已。于是想改进一下。

我原打算改进的方法是:

  定义一个雪花类,继承runnable,只要在控制类里面启动,就让雪花自动飘落,当落到屏幕下方的时候,重新回到屏幕顶部,然后再次下落……

  这样设计,是因为我原先做过一下SWT的游戏,让物品自己绘制自己,自己控制自己的生命周期,这应该是面向对象设计的第一反应……

但是遇到了问题,因为在android中,界面显示是靠View来控制的,如果让需要View把自己的canvas传递给雪花,这样还不如让所有的界面显示都交给VIEW来处理。

在不停的实验之后,发现我自己的设计,我没有走通……归结原因,还是自己对android 2D方面的东西不了解。于是网上下载一些资料学习

-----------------------------------分割线,一下内容来源互联网---------------------------------------------------------

android中涉及到显示的基本都要交给View处理,这里就不不得不提到两个类:android.view.View和android.view.SurfaceView。

SurfaceView 是从View基类中派生出来的显示类,直接子类有GLSurfaceView和VideoView,可以看出GL和视频播放以及Camera摄像头一般均使用SurfaceView。

surfaceView 到底有哪些优势呢?

 SurfaceView 可以控制表面的格式,比如大小,显示在屏幕中的位置,最关键是的提供了SurfaceHolder类,使用getHolder方法获取,相关的有

Canvas lockCanvas() ,Canvas lockCanvas(Rect dirty) 、void removeCallback(SurfaceHolder.Callback callback)、void unlockCanvasAndPost(Canvas canvas) 控制图形以及绘制,而在SurfaceHolder.Callback 接口回调中可以通过重写下面方法实现:

              使用的SurfaceView的时候,一般情况下要对其进行创建,销毁,改变时的情况进行监视,这就要用到 SurfaceHolder.Callback. 

class XxxView extends SurfaceView implements SurfaceHolder.Callback {

public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){} 
//看其名知其义,在surface的大小发生改变时激发 
public void surfaceCreated(SurfaceHolder holder){} 
//同上,在创建时激发,一般在这里调用画图的线程。 
public void surfaceDestroyed(SurfaceHolder holder) {} 
//同上,销毁时激发,一般在这里将画图的线程停止、释放。

}

对于Surface相关的,Android底层还提供了GPU加速功能,所以一般实时性很强的应用中主要使用SurfaceView而不是直接从View构建,同时后来做android 3d OpenGL中的GLSurfaceView也是从该类实现。

SurfaceView 和View 最本质的区别在于,surfaceView 是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。 

那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。 
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。

所以基于以上,根据游戏特点,一般分成两类。

1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

3.Android中的SurfaceView类就是双缓冲机制。因此,开发游戏时尽量使用SurfaceView而不要使用View,这样的话效率较高,而且SurfaceView的功能也更加完善。

---------------------------------------------分割线---------------------------------------------


于是就写了一个简单的demo,让一个物体(我用的是一朵花),在屏幕中不停的移动。选择使用surfaceView

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		SH = this.getHeight();
		SW = this.getWidth();
		th.start();

	}

这里我们重载,surfaceCrate方法,获得屏幕的高度和宽度,启动绘制线程……因为只有当执行surfaceCreate的时候,界面才真正绘制出来,如果在构造函数中获得屏幕的高度和宽度,就只能为0;


public void draw() {
		canvas = sfh.lockCanvas();
		if (canvas == null) {// 防止在按返回键的时候,报空指针异常
			return;
		}
		canvas.drawRect(0, 0, SW, SH, p); // 刷屏
		canvas.save();
		canvas.drawBitmap(bmp, bmp_x, bmp_y, p);
		Log.v("DEBUG", bmp_x + " |" + bmp_y + " | " + speed_x + " |" + speed_y);
		canvas.restore();
		sfh.unlockCanvasAndPost(canvas);

	}
这个方法会被线程不停的调用,让物体有移动的效果。其中
canvas.drawRect(0, 0, SW, SH, p); // 刷屏
负责清理上一次绘制留下的图片,让物体“动起来”。

为了防止当用户点击放回按钮的时候,线程仍在绘制,会报空指针异常,所以每次绘制前,要检查canvas是否为空。

	private void path() {
		if (bmp_x >= SW - 20) {
			speed_x += 1;
			if(speed_x>15){
				speed_x = 3;
			}
			speed_x = -speed_x;
		} else if (bmp_x <= 20) {
			speed_x -=1;
			if(speed_x<-15){
				speed_x = -3;
			}
			speed_x = -speed_x;
		}
		if (bmp_y >= SH - 20) {
			speed_y+=5;
			if(speed_y>15){
				speed_y = 3;
			}
			speed_y = -speed_y;
		} else if (bmp_y <= 10){
			speed_y -=5;
			if(speed_y<-15){
				speed_y = -3;
			}
			speed_y = -speed_y;
		}
		bmp_x += speed_x;
		bmp_y += speed_y;
	}

path这个方法控制着物体移动的速度,方向……

代码下载地址:点击打开链接


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值