android 遊戲開發之粒子系統應用

來源:互聯網
上載者:User

       上一節說的是小球運動,而這節介紹的是粒子系統,從名字上就可以得出數量之極多.簡單說:粒子系統就是有好多好多小球在一起欲動,那麼這就叫做粒子系統,考慮的是整體感覺,而不是單個小球的軌跡.這讓我聯想到了墨跡和新浪推出的天氣動態背景,是不是也是這樣實現的呢.總而言之,如下雨,下雨,瀑布等都可以做到,但是做起來很複雜,估計我想遠跑偏了,肯定有更好的辦法實現動態背景.

我們還是先看一個案例,實現起來和前面講解小球一樣.

首先粒子物件Particle.java

package com.jj.partical;/*** * 粒子物件 *  * @author zhangjia *  */public class Particle {int color; // 顏色int r;// 半徑double vertical_v;// 垂直速度double horizontal_v;// 水平速度int startX;int startY;int x;int y;double startTime;// 起始時間public Particle(int color, int r, double vertical_v, double horizontal_v,int x, int y, double startTime) {super();this.color = color;this.r = r;this.vertical_v = vertical_v;this.horizontal_v = horizontal_v;this.startX = x;this.startY = y;this.x = x;this.y = y;this.startTime = startTime;}}

就是一些屬性,下面我們建立一個存放粒子的幾個ParticleSet.java其實二者可以整個一個裡面,總而言之,達到效果就OK.

package com.jj.partical;import java.util.ArrayList;import android.graphics.Color;/*** * 存放粒子物件集合 *  * @author zhangjia *  */public class ParticleSet {ArrayList<Particle> particals;public ParticleSet() {super();particals = new ArrayList<Particle>();}/*** * 擷取相關顏色 *  * @return */public int getColor(int i) {int color = Color.RED;switch (i % 4) {case 0:color = Color.RED;break;case 1:color = Color.GREEN;break;case 2:color = Color.YELLOW;break;case 3:color = Color.WHITE;break;default:break;}return color;}/*** * 添加粒子 *  * @param count *            個數 * @param startTime *            起始時間 */public void addPartical(int count, double startTime, int window_Width) {for (int i = 0; i < count; i++) {int color = getColor(i);int r = 1;double vertical_v = -30 + 10 * (Math.random());// 垂直速度double horizontal_v = 10 - 20 * (Math.random());// 水平速度int startX = window_Width / 2;int startY = 100;Particle partical = new Particle(color, r, vertical_v,horizontal_v, startX, startY, startTime);particals.add(partical);}}}

接下來介紹:粒子物理引擎ParticleThread.java

package com.jj.partical;import java.util.ArrayList;/*** * 粒子物理引擎 *  * @author zhangjia *  */public class ParticleThread extends Thread {boolean flag;// 線程標識ParticleView particalView;int sleepSpan = 80;double time = 0;double span = 0.15;private int window_Width;public ParticleThread(ParticleView particleView, int window_Width) {this.particalView = particleView;this.flag = true; // 設定線程執行標誌位為truethis.window_Width = window_Width;}@Overridepublic void run() {while (flag) {particalView.particleSet.addPartical(5, time, window_Width);// 每次添加5粒ArrayList<Particle> particals = particalView.particleSet.particals;// 擷取粒子集合int count = particals.size();for (int i = 0; i < count; i++) {Particle partical = particals.get(i);double timeSpan = time - partical.startTime;// 計算程式開始到現在的時間差int tempX = (int) (partical.startX + partical.horizontal_v* timeSpan);// 計算此時粒子的X值// 4.9 * timeSpan * timeSpan=1/2*g*t*t;//物理公式,g=9.8m/s;int tempY = (int) (partical.startY + 4.9 * timeSpan * timeSpan);// 計算此時粒子的Y值if (tempY > ParticleView.DIE_OUT_LINE) {particals.remove(partical);// 刪除該粒子count = particals.size();// 重新擷取個數}partical.x = tempX;partical.y = tempY;}time += span;try {Thread.sleep(sleepSpan);} catch (InterruptedException e) {e.printStackTrace();}}}}

ParticleView.java

package com.jj.partical;import java.util.ArrayList;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.view.SurfaceHolder;import android.view.SurfaceView;//繼承自SurfaceView並實現SurfaceHolder.Callback介面的類public class ParticleView extends SurfaceView implements SurfaceHolder.Callback {public static int DIE_OUT_LINE = 420;// 粒子的Y座標超過該值會從粒子集合移除DrawThread drawThread; // 後台重新整理螢幕線程ParticleSet particleSet; // ParticleSet對象引用ParticleThread particleThread; // ParticleThread對象引用String fps = "FPS:N/A"; // 聲明畫面播放速率字串// 構造器,初始化主要成員變數public ParticleView(Context context, int window_Width, int window_Height) {super(context); // 調用父類構造器DIE_OUT_LINE = window_Height;this.getHolder().addCallback(this); // 添加Callback介面drawThread = new DrawThread(this, getHolder()); // 建立DrawThread對象particleSet = new ParticleSet(); // 建立ParticleSet對象particleThread = new ParticleThread(this, window_Width); // 建立ParticleThread對象}// 方法:繪製螢幕public void doDraw(Canvas canvas) {canvas.drawColor(Color.BLACK); // 清屏ArrayList<Particle> particleSet = this.particleSet.particals; // 獲得ParticleSet對象中的粒子集合對象Paint paint = new Paint(); // 建立畫筆對象for (int i = 0; i < particleSet.size(); i++) { // 遍曆粒子集合,繪製每個粒子Particle p = particleSet.get(i);paint.setColor(p.color); // 設定畫筆顏色為粒子顏色int tempX = p.x; // 獲得粒子X座標int tempY = p.y; // 獲得粒子Y座標int tempRadius = p.r; // 獲得粒子半徑RectF oval = new RectF(tempX, tempY, tempX + 2 * tempRadius, tempY+ 2 * tempRadius);// canvas.drawOval(oval, paint); // 繪製橢圓粒子canvas.drawCircle(tempX, tempY, tempRadius, paint);}paint.setColor(Color.WHITE); // 設定畫筆顏色paint.setTextSize(18); // 設定文字大小paint.setAntiAlias(true); // 設定消除鋸齒canvas.drawText(fps, 15, 15, paint);// 畫出畫面播放速率字串}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {// 重寫surfaceChanged方法}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// 從寫surfaceCreated方法if (!drawThread.isAlive()) { // 如果DrawThread沒有啟動,就啟動這個線程drawThread.start();}if (!particleThread.isAlive()) { // 如果ParticleThread沒有啟動,就啟動這個線程particleThread.start();}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// 重寫surfaceDestroyed方法drawThread.flag = false; // 停止線程的執行drawThread = null; // 將dt指向的對象聲明為垃圾}}

用於重繪螢幕和計算幀率DrawThread.java

package com.jj.partical;import android.graphics.Canvas;import android.view.SurfaceHolder;/*** * 用於重繪螢幕和計算幀率 *  * @author zhangjia *  */public class DrawThread extends Thread {ParticleView particalView;// 自訂ViewSurfaceHolder surfaceHolder;boolean flag = false;// 線程標識int sleepSpan = 15;// 線程休眠long start = System.nanoTime();// 其即時間,用於計算畫面播放速率int count = 0;// 計算幀率public DrawThread(ParticleView particalView, SurfaceHolder surfaceHolder) {super();this.particalView = particalView;this.surfaceHolder = surfaceHolder;this.flag = true;}@Overridepublic void run() {Canvas canvas = null;while (flag) {try {canvas = surfaceHolder.lockCanvas();// 擷取canvas.synchronized (surfaceHolder) {particalView.doDraw(canvas);// 進行繪製ballView.}} catch (Exception e) {e.printStackTrace();} finally {if (canvas != null) {surfaceHolder.unlockCanvasAndPost(canvas);// 解鎖}}this.count++;if (count == 20) { // 如果計滿20幀count = 0; // 清空計數器long tempStamp = System.nanoTime();// 擷取目前時間long span = tempStamp - start; // 擷取時間間隔start = tempStamp; // 為start重新賦值double fps = Math.round(100000000000.0 / span * 20) / 100.0;// 計算畫面播放速率particalView.fps = "FPS:" + fps;// 將計算出的畫面播放速率設定到BallView的相應字串對象中}try {Thread.sleep(sleepSpan); // 線程休眠一段時間} catch (Exception e) {e.printStackTrace(); // 捕獲並列印異常}}}}

接下來調用展示View,就不寫了,相信大家都明白如何操作,

現在我簡單講解一下原理:首先我們建立DrawThread線程,目的是相隔sleepSpan進行繪製doDraw方法.其實就好比就是刷屏操作.而我們的ParticleThread物理引擎則每隔sleepSpan都要添加5個粒子進去.然後在通過DrawThread線程進行不停的更新UI從而實現粒子系統.

煙火粒子樣本:
      

其實我們稍微整理下邏輯就可以變為瀑布效果.

// double horizontal_v = 10 - 20 * (Math.random());// 水平速度(火焰效果)double horizontal_v = 10 + 20 * (Math.random());// 水平速度(瀑布效果)

瀑布:

關於粒子系統就說到這裡,有不足的地方,請指示.

這個相比物理小球運動簡單一點,不涉及太多的邏輯判斷.總而言之:這套實現的步驟和方案值得參考.



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.