欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

android 模拟物品移动

发布时间:2023/12/20 编程问答 55 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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

@Overridepublic 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这个方法控制着物体移动的速度,方向……

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


总结

以上是生活随笔为你收集整理的android 模拟物品移动的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。