1.第一次接觸粒子是在html5的canvas,說是html的canvas,倒不如說是JavaScript的canvas,畢竟核心都在js。
2.通過長久的醞釀,感受Java實現粒子運動好像也不是什麼難事,Android粒子篇將用Android做爲視口,帶你領略粒子的炫酷。
3.關於性能方面,我想只要合理控制粒子的消失,仍是能夠接受的。只要不是無限級別,和遊戲比起來,這點性能九牛一毛啦。
4.粒子效果的核心有三個點:收集粒子、更改粒子、顯示粒子
5.爲了純粹,本文只實現下圖的粒子效果:html
通過個人思索,既然能夠用二維數組實現數字的粒子化:見:Android原生繪圖之炫酷倒計時,
那麼一個Bitmap不是自然包含一個二維的像素數組嗎?二話不說,將圖片調成黑字無底,遍歷添加。html5
/**
* 做者:張風捷特烈<br/>
* 時間:2018/11/16 0016:21:51<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:粒子對象
*/
public class Ball implements Cloneable {
public float aX;//加速度
public float aY;//加速度Y
public float vX;//速度X
public float vY;//速度Y
public float x;//點位X
public float y;//點位Y
public int color;//顏色
public float r;//半徑
public long born;//誕生時間
public Ball clone() {
Ball clone = null;
try {
clone = (Ball) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
複製代碼
這裏遍歷一下bitmap將全部的黑色像素收集到粒子集合中:git
//成員變量:
private List<Ball> mBalls = new ArrayList<>();//粒子集合
//加載圖片
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.thank_you);
for (int i = 0; i < bitmap.getWidth(); i++) {
for (int j = 0; j < bitmap.getHeight(); j++) {
int pixel = bitmap.getPixel(i, j);
if (pixel < 0) {//此處過濾掉其餘顏色,避免所有產生粒子
Ball ball = new Ball();//產生粒子---每一個粒子擁有隨機的一些屬性信息
ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random()
ball.vY = rangeInt(-15, 35);
ball.aY = 0.98f;
ball.x = i * 4;
ball.y = j * 4;
ball.color = pixel;
ball.born = System.currentTimeMillis();
mBalls.add(ball);
}
mColArr[i][j] = bitmap.getPixel(i, j);
}
}
複製代碼
也就是將粒子集合中的每一個粒子繪製出來,很是簡單
但這時它已經不是文字或圖片了,而是可操縱的粒子,是否是很興奮github
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(mCoo.x, mCoo.y);
for (Ball ball : mBalls) {//繪製小球集合
mPaint.setColor(ball.color);
canvas.drawCircle(ball.x, ball.y, 2, mPaint);
}
canvas.restore();
}
複製代碼
結核運動學的一點知識,讓小球擁有位移,速度,加速度的模擬,來實現運動,這裏不過多贅述
個人這篇文章講得很是細緻。canvas
其實也不復雜,就是在恆定時間流下對位移和速度進行運動學的累加數組
/**
* 更新小球
*/
private void updateBall() {
for (int i = 0; i < mBalls.size(); i++) {
Ball ball = mBalls.get(i);
ball.x += ball.vX;
ball.y += ball.vY;
ball.vY += ball.aY;
ball.vX += ball.aX;
}
}
複製代碼
昨天在思考怎麼可以更好控制粒子的湮滅呢?
粒子的湮滅提及來就是在必定的條件下將粒子從集合中移除,今早忽然靈光一閃,能夠用時間啊!bash
/**
* 更新小球
*/
private void updateBall() {
for (int i = 0; i < mBalls.size(); i++) {
Ball ball = mBalls.get(i);
if (System.currentTimeMillis() - mClickTime > 3000)
mBalls.remove(i);
}
ball.x += ball.vX;
ball.y += ball.vY;
ball.vY += ball.aY;
ball.vX += ball.aX;
}
}
複製代碼
//初始化時間流ValueAnimator
mAnimator = ValueAnimator.ofFloat(0, 1);
mAnimator.setRepeatCount(-1);
mAnimator.setDuration(2000);
mAnimator.addUpdateListener(animation -> {
updateBall();//更新小球位置
invalidate();
});
複製代碼
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mClickTime = System.currentTimeMillis();//記錄點擊時間
mAnimator.start();
break;
}
return true;
}
複製代碼
這樣粒子運動的效果就實現了,固然你也能夠用任意的圖片來進行粒子運動
關於Bitmap的粒子運動會新寫一篇來詳細的論述,敬請期待。dom
如今到了粒子所有湮滅的監聽了,在一張圖片的全部粒子湮滅後進入下一個圖片:
很容易想到在移除粒子是監聽粒子集合是否爲空ide
private List<Ball> mBalls = new ArrayList<>();//粒子集合
private ValueAnimator mAnimator;//時間流
private long mRunTime;//粒子運動時刻
private boolean isOK;//結束的flag
private int curBitmapIndex = 0;//當前圖片索引
private Bitmap[] mBitmaps;//圖片數組
複製代碼
/**
* 將一個圖片粒子化
* @param bitmap
*/
public void bitmap2Ball(Bitmap bitmap) {
for (int i = 0; i < bitmap.getWidth(); i++) {
for (int j = 0; j < bitmap.getHeight(); j++) {
int pixel = bitmap.getPixel(i, j);
if (pixel < 0) {//此處過濾掉其餘顏色,避免所有產生粒子
Ball ball = new Ball();//產生粒子---每一個粒子擁有隨機的一些屬性信息
ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random());
ball.vY = rangeInt(-15, 35);
ball.aY = 0.98f;
ball.x = i * 4;
ball.y = j * 4;
ball.color = pixel;
ball.born = System.currentTimeMillis();
mBalls.add(ball);
}
}
}
}
複製代碼
//加載圖片數組
mBitmaps = new Bitmap[]{
BitmapFactory.decodeResource(getResources(), R.mipmap.thank_you),
BitmapFactory.decodeResource(getResources(), R.mipmap.bye),
BitmapFactory.decodeResource(getResources(), R.mipmap.go_on)
};
bitmap2Ball(mBitmaps[curBitmapIndex]);//初始化第一張圖
複製代碼
isOK這個flag讓我頭疼了幾分鐘,總算找到了什麼時候的位置post
/**
* 更新小球
*/
private void updateBall() {
for (int i = 0; i < mBalls.size(); i++) {
Ball ball = mBalls.get(i);
if (System.currentTimeMillis() - mRunTime > 2000) {
mBalls.remove(i);
}
if (mBalls.isEmpty()) {//表示本張已結束
if (curBitmapIndex == 2) {
mAnimator.end();
return;
}
curBitmapIndex++;
bitmap2Ball(mBitmaps[curBitmapIndex]);
isOK = true;
invalidate();
mRunTime = System.currentTimeMillis();
mAnimator.pause();
}
if (isOK) {//若是本張結束---返回掉
isOK = false;
return;
}
ball.x += ball.vX;
ball.y += ball.vY;
ball.vY += ball.aY;
ball.vX += ball.aX;
}
}
複製代碼
至此,本文的效果就已經實現了,是否是沒有想象中的那麼複雜,相信你也能夠作到
這些天感謝柚子茶的幫助,無覺得報,以文記之,祝掘金愈來愈好,幫助更多的技術開發者。
本文無捷文規範
,不會再作任何修改。項目源碼見→_→ ~ GitHub ~ ←_← ----------------------------2018.11.17--捷特 &安徽