最近项目上线完,正好有空搞点新花样,记得有个粒子爆炸效果,一直没弄过,现在正好撸一下。。。
下面先看一下实现效果:
20200527203126.gif
当手指在屏幕上按下,会生成随机颜色的粒子,然后向上移动,在高处爆炸,看上去就像放烟花一样,还挺好看。。。。。
现在开始说一下实现流程:
一.每一个粒子都是一个实体,有自己的属性,所以需要定义一个实体类:
/**
* 上升粒子
*/
public class ParticalBean {
//画笔
private Paint paint;
//x位置
private int x;
//y位置
private int y;
//速率
private int speed;
//移动距离
private int distance;
//是否爆炸
private boolean isBoom;
//爆炸后粒子数据
private List<BoomParicalBean> boomParicalBeans;
public ParticalBean(Paint paint, int x, int y, int speed, int distance) {
this.paint = paint;
this.x = x;
this.y = y;
this.speed = speed;
this.distance = distance;
}
public Paint getPaint() {
return paint;
}
public void setPaint(Paint paint) {
this.paint = paint;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
this.distance = distance;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public boolean isBoom() {
return isBoom;
}
public void setBoom(boolean boom) {
isBoom = boom;
}
public List<BoomParicalBean> getBoomParicalBeans() {
return boomParicalBeans;
}
public void setBoomParicalBeans(List<BoomParicalBean> boomParicalBeans) {
this.boomParicalBeans = boomParicalBeans;
}
}
这个实体类就是上升粒子的实体类,详细属性有写。
二.每一个爆炸粒子也是一个实体,所以也要定义一个实体类:
/**
* 爆炸粒子
*/
public class BoomParicalBean {
//x位置
private int x;
//y位置
private int y;
//速率
private int speed;
//移动距离
private int distance;
//粒子半径
private int raduis;
public BoomParicalBean(int x, int y, int raduis, int speed, int distance) {
this.x = x;
this.y = y;
this.raduis = raduis;
this.speed = speed;
this.distance = distance;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getRaduis() {
return raduis;
}
public void setRaduis(int raduis) {
this.raduis = raduis;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
this.distance = distance;
}
}
三.生成实体粒子与爆炸粒子,需要一个制造它们的工厂:
/**
* 粒子工厂
*/
class ParticalFactory {
/** 生成上升粒子
* @param paint
* @param x
* @param y
* @param speed
* @param distance
* @return
*/
static ParticalBean createPartical(Paint paint, int x, int y, int speed, int distance){
return new ParticalBean(paint, x, y, speed, distance);
}
/** 生成爆炸粒子
* @param x
* @param y
* @param raduis
* @param speed
* @param distance
* @return
*/
static BoomParicalBean createBoomPartical(int x, int y, int raduis, int speed, int distance){
return new BoomParicalBean(x, y, speed, raduis, distance);
}
}
四.有了这些基本元素之后,开始绘制逻辑:
1.当手指按下新增一个粒子,将粒子添加到集合,并刷新画布。
gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onDown(MotionEvent e) {
ViewCompat.postInvalidateOnAnimation(ParticalView.this);
list.add(ParticalFactory.createPartical(cratePaint(), (int) e.getX(), (int)e.getY(), (int) (Math.random() * (15-5)+5), (int) (Math.random() * 1000)));
return true;
}
});
2.在onDraw()方法绘制圆形粒子,当粒子移动到设定的位置(范围内随机)时,设置为爆炸粒子。
for (ParticalBean particalBean : list) {
if(!particalBean.isBoom()){
canvas.drawCircle(particalBean.getX(), particalBean.getY(), 50, particalBean.getPaint());
particalBean.setY(particalBean.getY() - particalBean.getSpeed());
}
}
for (int i=0; i<list.size(); i++){
ParticalBean particalBean = list.get(i);
if(!particalBean.isBoom()){
if (particalBean.getY() <= particalBean.getDistance()){
//碎片个数
int fragments = (int) (Math.random() * (100 - 60) + 60);
List<BoomParicalBean> boomParicalBeans = new ArrayList<>();
for (int j=0; j < fragments ;j++){
double angle = (j * 2 * Math.PI) / fragments;
int raduis = (int) (Math.random() * fragmentsRaduis);
int x = (int) (Math.cos(angle) * raduis) + particalBean.getX();
int y = (int) (Math.sin(angle) * raduis) + particalBean.getY();
BoomParicalBean boomPartical = ParticalFactory.createBoomPartical(x, y, boomParicalSpeed, (int) (Math.random() * particalRaduis), y + boomParticalMoveY);
boomParicalBeans.add(boomPartical);
}
particalBean.setBoomParicalBeans(boomParicalBeans);
particalBean.setBoom(true);
}
}
}
3.根据上升粒子的位置,计算爆炸粒子的位置(范围内随机),爆炸粒子数量(范围内随机),爆炸粒子下落距离(预设),开始绘制爆炸粒子。
//爆炸粒子
for (int p=0; p< list.size(); p++){
ParticalBean particalBean = list.get(p);
if(particalBean.isBoom()){
List<BoomParicalBean> boomParicalBeans = particalBean.getBoomParicalBeans();
for (int i=0; i<boomParicalBeans.size() ;i++){
BoomParicalBean boomParicalBean = boomParicalBeans.get(i);
canvas.drawCircle(boomParicalBean.getX(), boomParicalBean.getY(), boomParicalBean.getRaduis(), particalBean.getPaint());
boomParicalBean.setY(boomParicalBean.getY() + boomParicalBean.getSpeed());
if(boomParicalBean.getY() >= boomParicalBean.getDistance()){
boomParicalBeans.remove(boomParicalBean);
}
if(boomParicalBeans.isEmpty()){
list.remove(particalBean);
ViewCompat.postInvalidateOnAnimation(ParticalView.this);
}
}
}
}
4.当爆炸粒子下落完设定距离后,清除集合中的粒子,画布停止刷新。
有点意思
完、、、。
完整代码:
github: