Android 应用开发学习 (1):物理小球 与 粒子特效
来源:互联网 发布:微软编程一小时官网 编辑:程序博客网 时间:2024/06/05 04:13
Android 应用开发学习 (1):物理小球 与 粒子特效
该学习内容是出自 Android 游戏开发大全 里的。物理小球与粒子特效在测试效果的时候,最终是通过自定义的View来测试的。所以在下面写下自己的学习笔记。
实现效果
整体结构
以粒子特效为例:
其中每一块分别的用途为:
Particle: 粒子特效 的 “粒子” 。是Demo里最基本的数据结构。
ParticleSet: “粒子”的集合,数据上是”粒子”的 ArrayList. 同时拥有添加粒子时,对每一个粒子进行属性初始化的工作。
ParticleThread: [extends Thread] “粒子” 每时每刻都在发生着运动状态的变化,这种变化的逻辑将通过该线程来实现。
DrawThread:[extends Thread] “粒子”的数据发生了改变后,如果没有一个能对视图进行重绘的线程是看不到变化的效果的。所以重绘工作的调用将通过该线程来实现。
ParticleView:[extends SurfaceView,implements SurfaceHolder.Callback] “粒子视图” 在初始化的时候,会自动开启两个线程,然后测试能够看到“粒子瀑布”效果。
工作细节
继承与实现
ParticleView 需要 继承 SurfaceView 并且 实现 SurfaceHolder.Callback 接口。
【该段代码 From ParticleView】
public class ParticleView extends SurfaceView implements SurfaceHolder.Callback{ ....//省略}
【该段代码 From ParticleView】
public ParticleView(Context context) { super(context); this.getHolder().addCallback(this); // 该行必须有 /*实例化的过程*/ ps = new ParticleSet(); pt = new ParticleThread(this); dt = new DrawThread(this, getHolder()); }
视图重绘
ParticleView 中需要写出 doDraw()方法。
当然该 方法也可以不叫 “doDraw” ,你可以任取名字,毕竟不是覆写方法。
【该段代码 From ParticleView】
public void doDraw(Canvas canvas) { ArrayList<Particle> particles = ps.particles; for (int i = 0; i < particles.size(); i++) { paint = new Paint(); Particle p = particles.get(i); //得到 每一个粒子,并且将他们在视图上进行绘制 paint.setColor(p.color); canvas.drawCircle(p.x, p.y, p.r, paint); //属性分别是:横坐标,纵坐标,半径,画笔(主要是每个"粒子"的颜色可能是不同的) } }
因为doDraw()方法是 自己写的,而不是我们直接去覆写 onDraw()方法,如果我们不在其他地方调用它,它是肯定不会生效的。所以我们需要写出DrawThread 的调用逻辑,并让它去调用这个方法。
【该段代码 From DrawThread】
while (flag){ try { canvas = surfaceHolder.lockCanvas(null); // surfaceholder 得到画布 synchronized (surfaceHolder){ particleView.doDraw(canvas); //将得到的画布作为参数让ParticleView 用doDraw()方法去进行绘制。此处是死循环,会不断的绘制。从而实现动画效果。 } }catch (Exception e){ e.printStackTrace(); }finally { if (canvas != null){ surfaceHolder.unlockCanvasAndPost(canvas); //【重要】每绘制完一次,不要忘了 使用这个方法。 } } try { Thread.sleep(120); } catch (InterruptedException e) { e.printStackTrace(); } }
调用线程
如果 doDraw() 是通过DrawThread 调用的,那么DrawThread 也一定会有一个被调用的过程。
【该段代码 From ParticleView】
@Override public void surfaceCreated(SurfaceHolder surfaceHolder) { if (!dt.isAlive()) { dt.start(); //开启DrawThread线程 } if (!pt.isAlive()) { pt.start(); //开启ParticleThread线程 } //两个线程都将在SurfaceView 被创建后 就执行。该方法的执行 紧随 构造函数之后。 } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { dt.flag = false; dt = null; pt.flag = false; pt = null; //关闭线程的时候,都应先将它的开关关掉,再执行置空的操作。不然可能会报错。 //所以写线程的时候,线程也会有两个属性。 }
线程的格式
自定义线程时,不要遗忘的两个属性:
第一个是flag,也就是线程的开关。
第二个是sleepSpan ,更新的线程是死循环执行,为了限制执行的频率,每次执行完了以后,通常会让线程休眠一段时间。
【该段代码 From DrawThread】
@Override public void run() { Canvas canvas = null; while (flag){ //这是flag try { canvas = surfaceHolder.lockCanvas(null); synchronized (surfaceHolder){ particleView.doDraw(canvas); } }catch (Exception e){ e.printStackTrace(); }finally { if (canvas != null){ surfaceHolder.unlockCanvasAndPost(canvas); } } try { Thread.sleep(120); //这是sleepSpan } catch (InterruptedException e) { e.printStackTrace(); } } }
【该段代码 From ParticleThread】
@Override public void run() { while (flag) { //这是flag ArrayList<Particle> particles = pv.ps.particles; pv.addParticles(5); Log.i(TAG, "run: "+particles.size()); int count = particles.size(); for (int i = 0; i < count; i++) { Particle particle = particles.get(i); long timeNow = System.nanoTime(); long timeSpan =(timeNow - particle.startTime)/1000/1000/1000; int x = (int) (particle.startX + particle.horizontal_v * timeSpan); int y = (int) (particle.startY + particle.vertical_v * timeSpan + 4.9 * timeSpan * timeSpan); if (y > OUTLINE) { particles.remove(particle); count = particles.size(); i--; } particle.x = x; particle.y = y; } try { Thread.sleep(sleepSpan); //这是sleepSpan 数值在ParticleThread的成员变量中 } catch (InterruptedException e) { e.printStackTrace(); } } }
粒子运动原理
计算小球运动的距离,主要运用了高中物理的公式:
X=Vot+1/2gt^2;
或者X=Vot;
其中这个t的获取 在测试的demo 里主要是通过 给每一个粒子一个初始的时间点 to,这个时间点的获得是通过方法 System.nanotime() 来获得的。
同样,每次要刷新粒子的位置的时候,会重新去得到系统的时间t1,然后两个时间 作差,即t = t1-to 得到的差值t即为运动公式里的t。
也就是说,to 在最开始测了一次后,在运动状态未改变的情况下,是不会发生改变的,而为了得到运动方程里的t,t1 将时常发生改动。
[只有发生了碰撞,或者是其他的改变方程的情况时, to 才会发生改变,然而 “粒子瀑布”Demo 中不会有碰撞,并不需要to 发生改变。 ]
【该段代码 From ParticleThread】
@Override public void run() { while (flag) { ArrayList<Particle> particles = pv.ps.particles; //ParticleThread 先得到ParticleSet 里的 Particle 的列表 pv.addParticles(5); //每次执行都会添加五个粒子,从而实现粒子瀑布 for (int i = 0; i < particles.size(); i++) { //对每一个粒子进行 运动模拟。 Particle particle = particles.get(i); long timeNow = System.nanoTime(); //得到当前的时间 long timeSpan =(timeNow - particle.startTime)/1000/1000/1000; /*【注意】因为System.nanoTime() 得到的是纳秒,如果你不 除以 10^9 ,那么timeSpan将会变的非常大。*/ int x = (int) (particle.startX + particle.horizontal_v * timeSpan); int y = (int) (particle.startY + particle.vertical_v * timeSpan + 4.9 * timeSpan * timeSpan); if (y > OUTLINE) { particles.remove(particle); i--; } particle.x = x; particle.y = y; // 更新 每一个点的 X,Y 坐标。 } try { Thread.sleep(sleepSpan); } catch (InterruptedException e) { e.printStackTrace(); } } }
源码
http://download.csdn.net/detail/qq_34107083/9742162
- Android 应用开发学习 (1):物理小球 与 粒子特效
- android 游戏开发之物理小球的应用
- Qt移动应用开发:应用粒子特效
- 粒子特效编程与手机应用研究
- Qt移动应用开发(四):应用粒子特效
- android 粒子爆炸特效
- android 游戏开发之粒子系统应用
- 【iOS-Cocos2d游戏开发之十】添加粒子系统特效并解决粒子特效与Layer之间的坐标问题;
- 【iOS-Cocos2d游戏开发之十】添加粒子系统特效并解决粒子特效与Layer之间的坐标问题;
- 【iOS-Cocos2d游戏开发之十】添加粒子系统特效并解决粒子特效与Layer之间的坐标问题;
- 【iOS-Cocos2d游戏开发之十】添加粒子系统特效并解决粒子特效与Layer之间的坐标问题;
- 【iOS-Cocos2d游戏开发之十】添加粒子特效并解决粒子系统特效与Layer之间的坐标问题;
- 【iOS-Cocos2d游戏开发之十】添加粒子系统特效并解决粒子特效与Layer之间的坐标问题;
- Android制作粒子爆炸特效
- Android制作粒子爆炸特效
- Android制作粒子爆炸特效
- Android制作粒子爆炸特效
- Android制作粒子爆炸特效
- win7下的Django学习
- MySQL 存储引擎
- Codeforces Round #392(Div. 2) B Blown Garland【暴力枚举】
- linux 下查看tomcat版本
- 图像拼接一般流程
- Android 应用开发学习 (1):物理小球 与 粒子特效
- git学习
- 一张二维码集成微信、支付宝支付
- 欢迎使用CSDN-markdown编辑器
- 关于.net 开发web遇到的一个奇葩问题 drowdown未放置在runat="server"标记里
- 2016的学习总结
- Junit加载Spring容器作单元测试_添加事务回滚
- Android常见bug
- maven国内镜像