Android製作粒子爆炸特效
簡介
最近在閒逛的時候,發現了一款粒子爆炸特效的控制元件,覺得比較有意思,效果也不錯。
但是程式碼不好擴充套件,也就是說如果要提供不同的爆炸效果,需要修改的地方比較多。於是我對原始碼進行了一些重構,將爆炸流程和粒子運動分離。
對於原始碼,大家可以參考以下連結
連結1
連結2
上面兩套程式碼,其實結構都是一樣的,但是實現的效果不同(其實就是粒子運動的演算法不同)。
本篇文章,將給大家介紹粒子爆炸特效的實現方式,替大家理清實現思路。
實現效果如下:
類設計
類設計圖如下:
ExplosionField,爆炸效果發生的場地,是一個View。當一個控制元件需要爆炸時,需要為控制元件生成一個ExplosionField,這個ExplosionField**覆蓋整個螢幕**,於是我們才能看到完整的爆炸效果。
ExplosionAnimator,爆炸動畫,其實是一個計時器,繼承自ValueAnimator。1024s內,完成爆炸動畫,每次計時,就更新所有粒子的運動狀態。draw()方法是它最重要的方法,也就是使所有粒子重繪自身,從而實現動畫效果。
ParticleFactory,是一個抽象類。用於產生粒子陣列,不同的ParticleFactory可以產生不同型別的粒子陣列。
Particle,抽象的粒子類。代表粒子本身,必須擁有的屬性包括,當前自己的cx,cy座標和顏色color。必須實現兩個方法,d**raw()方法選擇怎麼繪製自身(圓形還是方形等),**caculate()計算當前時間,自己所處的位置。
控制元件的使用
控制元件使用很簡單,首先要實現不同的爆炸效果,需要給ExplosionField傳入不同的ParticleFactory工廠,產生不同的粒子。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">ExplosionField explosionField = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ExplosionField(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> FallingParticleFactory());</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
然後哪個控制元件需要爆炸效果,就這樣新增
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">explosionField<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addListener</span>(findViewById(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.text</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> explosionField<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addListener</span>(findViewById(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layout</span>1))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
這樣就為兩個控制元件新增了爆炸效果,注意layout1代表的是一個viewgroup,那麼我們就會為viewgroup中的每個view新增爆炸效果。
我們可以想象,在ExplosionField的建構函式中,傳入不同的ParticleFactory,就可以生成不同的爆炸效果。
爆炸實現思路
1、獲取當前控制元件背景bitmap
例如,例子中使用的是imageview,對於這個控制元件,我提供了一個工具類,可以獲得其背景的Bitmap物件
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Bitmap <span class="hljs-title" style="box-sizing: border-box;">createBitmapFromView</span>(View view) { view.clearFocus(); Bitmap bitmap = createBitmapSafely(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (bitmap != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (sCanvas) { Canvas canvas = sCanvas; canvas.setBitmap(bitmap); view.draw(canvas); canvas.setBitmap(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>); } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> bitmap; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Bitmap <span class="hljs-title" style="box-sizing: border-box;">createBitmapSafely</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> width, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> height, Bitmap.Config config, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> retryCount) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> Bitmap.createBitmap(width, height, config); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (OutOfMemoryError e) { e.printStackTrace(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (retryCount > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { System.gc(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> createBitmapSafely(width, height, config, retryCount - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>
上面的方法,簡而言之,就是將控制元件的Bitmap物件複製了一份,然後返回。
我們知道,bitmap可以看成是一個畫素矩陣,矩陣上面的點,就是一個個帶有顏色的畫素,於是我們可以獲取每個點(未必需要每個)的顏色和位置,組裝成一個物件Particle,這麼一來,Particle就代表帶有顏色的點了。
2、將背景bitmap轉換成Particle陣列
獲取Bitmap以後,我們交給ParticleFactory進行加工,根據Bitmap生產Particle陣列。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">abstract</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> ParticleFactory { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">abstract</span> Particle[][] <span class="hljs-title" style="box-sizing: border-box;">generateParticles</span>(Bitmap bitmap, Rect bound); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
例如我們來看一個簡單實現類,也是gif圖中,第一個下落效果的工廠類
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">FallingParticleFactory</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ParticleFactory</span>{</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> PART_WH = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//預設小球寬高</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Particle[][] <span class="hljs-title" style="box-sizing: border-box;">generateParticles</span>(Bitmap bitmap, Rect bound) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w = bound.width();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//場景寬度</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h = bound.height();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//場景高度</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> partW_Count = w / PART_WH; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//橫向個數</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> partH_Count = h / PART_WH; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//豎向個數</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> bitmap_part_w = bitmap.getWidth() / partW_Count; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> bitmap_part_h = bitmap.getHeight() / partH_Count; Particle[][] particles = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Particle[partH_Count][partW_Count]; Point point = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> row = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; row < partH_Count; row ++) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//行</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> column = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; column < partW_Count; column ++) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//列</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//取得當前粒子所在位置的顏色</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> color = bitmap.getPixel(column * bitmap_part_w, row * bitmap_part_h); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> x = bound.left + FallingParticleFactory.PART_WH * column; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> y = bound.top + FallingParticleFactory.PART_WH * row; particles[row][column] = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> FallingParticle(color,x,y,bound); } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> particles; } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li></ul>
其中Rect型別的bound,是代表原來View控制元件的寬高資訊。
根據我們設定的每個粒子的大小,和控制元件的寬高,我們就可以計算出,有多少個粒子組成這個控制元件的背景。
我們取得每個粒子所在位置的顏色,位置,用於生產粒子,這就是FallingParticle。
3、生成爆炸場地,開始爆炸動畫流程
爆炸時需要場地的,也就是繪製粒子的地方,我們通過給當前螢幕,新增一個覆蓋全螢幕的ExplosionField來作為爆炸場地。
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ExplosionField</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">View</span>{</span> ... <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 給Activity加上全屏覆蓋的ExplosionField */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">attach2Activity</span>(Activity activity) { ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT); ViewGroup.LayoutParams lp = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rootView.addView(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, lp); } ... }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
爆炸場地新增以後,我們響應控制元件的點選事件,開始動畫
首先是震動動畫
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 爆破 *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> view 使得該view爆破 */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">explode</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> View view) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//防止重複點選</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(explosionAnimatorsMap.get(view)!=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>&&explosionAnimatorsMap.get(view).isStarted()){ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(view.getVisibility()!=View.VISIBLE||view.getAlpha()==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>){ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//為了正確繪製粒子</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Rect rect = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Rect(); view.getGlobalVisibleRect(rect); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//得到view相對於整個螢幕的座標</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> contentTop = ((ViewGroup)getParent()).getTop(); Rect frame = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Rect(); ((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> statusBarHeight = frame.top; rect.offset(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, -contentTop - statusBarHeight);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//去掉狀態列高度和標題欄高度</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//震動動畫</span> ValueAnimator animator = ValueAnimator.ofFloat(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>f, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f).setDuration(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">150</span>); animator.addUpdateListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ValueAnimator.AnimatorUpdateListener() { Random random = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Random(); <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onAnimationUpdate</span>(ValueAnimator animation) { view.setTranslationX((random.nextFloat() - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f) * view.getWidth() * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.05</span>f); view.setTranslationY((random.nextFloat() - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f) * view.getHeight() * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.05</span>f); } }); animator.addListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AnimatorListenerAdapter() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onAnimationEnd</span>(Animator animation) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onAnimationEnd(animation); explode(view, rect);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//爆炸動畫</span> } }); animator.start(); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul>
震動動畫很簡單,就是x,y方向上,隨機產生一些位移,使原控制元件發生移動即可。
在震動動畫的最後,呼叫了爆炸動畫,於是爆炸動畫開始。
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">explode</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> View view,Rect rect) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> ExplosionAnimator animator = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ExplosionAnimator(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, Utils.createBitmapFromView(view), rect,mParticleFactory); explosionAnimators.add(animator); explosionAnimatorsMap.put(view, animator); animator.addListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AnimatorListenerAdapter() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onAnimationStart</span>(Animator animation) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//縮小,透明動畫</span> view.animate().setDuration(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">150</span>).scaleX(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>f).scaleY(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>f).alpha(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>f).start(); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onAnimationEnd</span>(Animator animation) { view.animate().alpha(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f).scaleX(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f).scaleY(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f).setDuration(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">150</span>).start(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//動畫結束時從動畫集中移除</span> explosionAnimators.remove(animation); explosionAnimatorsMap.remove(view); animation = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; } }); animator.start(); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>
爆炸動畫首先將原控制元件隱藏。
我們來看爆炸動畫的具體實現
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ExplosionAnimator</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ValueAnimator</span> {</span> ... <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ExplosionAnimator</span>(View view, Bitmap bitmap, Rect bound,ParticleFactory particleFactory) { mParticleFactory = particleFactory; mPaint = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Paint(); mContainer = view; setFloatValues(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.0</span>f, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>f); setDuration(DEFAULT_DURATION); mParticles = mParticleFactory.generateParticles(bitmap, bound); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//最重要的方法</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">draw</span>(Canvas canvas) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(!isStarted()) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//動畫結束時停止</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//所有粒子運動</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (Particle[] particle : mParticles) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (Particle p : particle) { p.advance(canvas,mPaint,(Float) getAnimatedValue()); } } mContainer.invalidate(); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">start</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.start(); mContainer.invalidate(); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul>
實現很簡單,就是根據工廠類,生成粒子陣列。
而其實質是一個ValueAnimator,在一定時間內,從0數到1。
然後提供了一個draw()方法,方法裡面調用了每個粒子的advance()方法,並且傳入了當前數到的數字(是一個小數)。
advance()方法裡,其實呼叫了draw()方法和caculate()方法。
上面的實現,其實是一個固定的流程,新增了爆炸場地以後,我們就開始從0數到1,在這個過程中,粒子會根據當前時間,繪製自己的位置,所以粒子的位置,其實是它自己決定的,和流程無關。
也就是說,我們只要用不同的演算法,繪製粒子的位置即可,實現了流程和粒子運動的分離。
4、怎麼運動?粒子自己最清楚
舉個例子,gif圖中,下落效果的粒子是這樣運動的
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">FallingParticle</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Particle</span>{</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Random random = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Random(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> radius = FallingParticleFactory.PART_WH; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> alpha = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>f; Rect mBound; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> color 顏色 *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> x *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> y */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">FallingParticle</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> color, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> x, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> y,Rect bound) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>(color, x, y); mBound = bound; } ... <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">caculate</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> factor){ cx = cx + factor * random.nextInt(mBound.width()) * (random.nextFloat() - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f); cy = cy + factor * random.nextInt(mBound.height() / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); radius = radius - factor * random.nextInt(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); alpha = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f - factor) * (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> + random.nextFloat()); } } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul>
caculate(float factor)方法,根據當前時間,計算粒子的下一個位置
我們可以看到,在這個粒子中,cy也就是豎直方向上是不斷增加的,cx也就是水平方向上,是隨機增加或者減少,這樣就形成了下落效果。
計算出當前位置以後,粒子就將自己繪製出來
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">draw</span>(Canvas canvas,Paint paint){ paint.setColor(color); paint.setAlpha((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) (Color.alpha(color) * alpha)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//這樣透明顏色就不是黑色了</span> canvas.drawCircle(cx, cy, radius, paint); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
怎麼擴充套件?
從上面的程式碼結構可以看出,爆炸流程和粒子具體運動無關,最重要的是,我們要實現自己的caculate()方法,決定粒子的運動形態。
而不同的粒子可以由對應的工廠產生,所以要擴充套件爆炸特性,只需要定義一個粒子類,和生成粒子類的工廠即可。
轉自:http://blog.csdn.net/crazy__chen/article/details/50149619
相關文章
- 2-66. 製作石頭和稻草的粒子特效特效
- 粒子類特效SDK,電影級的逼真特效特效
- Android在canvas中實現高效能的煙花/粒子特效AndroidCanvas特效
- mac動畫特效製作軟體Mac動畫特效
- 可以隨心所欲的canvas粒子特效Canvas特效
- 如何使用AE製作破碎文字特效特效
- 動畫特效製作軟體:Express Animate mac動畫特效ExpressMac
- 應用噪聲函式製作火焰特效函式特效
- 遊戲特效有哪些製作的分類遊戲特效
- Android粒子篇之文字的粒子化運動Android
- 多個物體模型快速製作爆炸圖?試一試ThingJS!模型JS
- 電影特效合成製作NUKE 13中文特效
- 紅巨星粒子特效合集外掛:Trapcode Suite 18 for Mac特效UIMac
- 影片特效製作軟體:After Effects 2024中文特效
- Android開源庫的製作Android
- 手把手教你做一個超寫實爆炸特效特效
- 5分鐘學會製作 CSS 波浪文字動畫特效CSS動畫特效
- Lottie Android 動畫製作與使用Android動畫
- CSS中的混合模式,製作高階特效的必備技巧CSS模式特效
- Motion 5 for Mac - 蘋果視訊後期特效製作軟體Mac蘋果特效
- 【轉】5分鐘學會製作 CSS 波浪文字動畫特效CSS動畫特效
- 紅巨人粒子特效套裝外掛Trapcode Suite 2024啟用版特效UI
- 風場視覺化:繪製粒子視覺化
- Android OpenGL ES 系列連載:(14)粒子(Particles)Android
- Android粒子篇之Bitmap畫素級操作Android
- 《永劫無間》金箍棒武器特效製作覆盤【設計乾貨】特效
- 紅巨星粒子特效合集外掛:Trapcode Suite 18 Mac版(支援m1)特效UIMac
- After Effects 2023 for Mac(Ae影片特效製作) v23.6中文版Mac特效
- 必備的影片後期特效製作軟體:motion 5 for mac中文版特效Mac
- 紅巨人粒子特效套裝外掛:Trapcode Suite for Mac v2024.0.1啟用版特效UIMac
- DaVinci Resolve Studio 19.0.3 (macOS, Windows) - 剪輯、調色、特效和音訊後期製作MacWindows特效音訊
- 剪映字型閃光怎麼弄? 剪映閃光文字特效的製作方法特效
- 新手小白適用的效果好又簡單視訊剪輯特效製作軟體特效
- 【實戰】這個炫酷的播放粒子效果,你也可以學會!使用Web動畫API製作Web動畫API
- android簡單的圖形特效處理Android特效
- 遊戲優化系列二:Android Studio製作圖示教程遊戲優化Android
- DaVinci Resolve Studio 19.0 正式版 (macOS, Windows) - 剪輯、調色、特效和音訊後期製作MacWindows特效音訊
- The Foundry NUKE 12 mac版(電影特效合成製作軟體)支援m1v12.2v10Mac特效
- Blender 效果製作:製作起伏不平的路面