Android游戏开发学习②焰火绽放效果实现方法

时间:2022-05-18 09:30:04

本文实例讲述了android游戏开发学习②焰火绽放效果实现方法。分享给大家供大家参考。具体如下:

本节介绍在游戏开发中常用到的数学物理应用——粒子系统。粒子系统与上一节的小球有类似的地方,都是通过数学方法和物理公式模拟客观世界中的物体的运动轨迹。不同的是小球更强调个体运动,而焰火粒子等粒子系统更注重整体感觉。

一、焰火粒子效果

1.粒子对象类particle类和粒子集合类particleset类

每个粒子都为一个particle类的对象,程序中产生的所有particle对象都由一个particleset对象来管理。

particle类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.particle;
public class particle {
  int color; // 粒子颜色
  int r; // 粒子半径
  double vertical_v; // 垂直速度
  double horizontal_v; // 水平速度
  int startx; // 初始x坐标
  int starty; // 初始y坐标
  int x; // 实时x坐标
  int y; // 实时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类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.particle;
import java.util.arraylist;
import android.graphics.color;
public class particleset {
  arraylist<particle> particleset;
  public particleset() {
    particleset = new arraylist<particle>();
  }
  /**
   * 向粒子集合中添加指定数量的粒子对象
   */
  public void add(int count, double starttime) {
    for (int i = 0; i < count; i++) {
      int tempcolor = this.getcolor(i);
      int tempr = 1; // 粒子半径
      double tempv_v = -30 + 10 * (math.random()); // 随机产生粒子竖直方向的速度
      double tempv_h = 10 - 20 * (math.random()); // 随机产生粒子水平方向的速度
      int tempx = 160;
      int tempy = (int) (100 - 10 * (math.random())); // 随机产生粒子y坐标,90到100之间
      particle particle = new particle(tempcolor, tempr, tempv_v,
          tempv_h, tempx, tempy, starttime);
      particleset.add(particle);
    }
  }
  /**
   * 获取指定索引的颜色
   */
  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.gray;
      break;
    }
    return color;
  }
}

产生的粒子竖直初速度为-30至-20,方向向上;水平初速度为-10至10,方向向左或向右。

2.物理引擎particlethread类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.particle;
import java.util.arraylist;
public class particlethread extends thread {
  boolean flag;
  particleview father;
  int sleepspan = 80;
  double time = 0; // 物理引擎的时间轴
  double span = 0.15; // 每次计算粒子位移时采用的时间间隔
  public particlethread(particleview father) {
    this.father = father;
    this.flag = true;
  }
  @override
  public void run() {
    while (flag) {
      father.ps.add(5, time); // 每次添加5个粒子
      arraylist<particle> tempset = father.ps.particleset; // 获取粒子集合
      for (int i = tempset.size() - 1; i >= 0; i--) {
        particle particle = tempset.get(i);
        double timespan = time - particle.starttime; // 计算从程序开始到现在经过的时间
        int tempx = (int) (particle.startx + particle.horizontal_v * timespan);
        int tempy = (int) (particle.starty + 4.9 * timespan * timespan + particle.vertical_v * timespan);
        if (tempy > particleview.die_out_line) { // 如果粒子超过屏幕下边沿
          tempset.remove(particle);
        }
        particle.x = tempx;
        particle.y = tempy;
      }
      time += span;
      try {
        thread.sleep(sleepspan);
      } catch (exception e) {
        e.printstacktrace();
      }
    }
  }
}

本例中的物理引擎没有采用获取系统时间的方式,而是自己定义了一个时间轴(成员变量time)。这样可以自己确定时间轴行进的快慢程度(通过改变成员变量span的值),而不必依赖于系统的时间。

3.视图类particleview类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.particle;
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.surfaceholder.callback;
import android.view.surfaceview;
public class particleview extends surfaceview implements callback {
  public static final int die_out_line = 300;
  drawthread dt;
  particleset ps;
  particlethread pt;
  string fps = "fps:n/a";
  public particleview(context context) {
    super(context);
    this.getholder().addcallback(this);
    dt = new drawthread(this, getholder());
    ps = new particleset();
    pt = new particlethread(this);
  }
  public void dodraw(canvas canvas) {
    canvas.drawcolor(color.black); // 清屏
    arraylist<particle> particleset = ps.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;
      int tempy = p.y;
      int tempradius = p.r;
      rectf oval = new rectf(tempx, tempy, tempx + 2 * tempradius, tempy
          + 2 * tempradius);
      canvas.drawoval(oval, paint); // 绘制椭圆粒子
    }
    paint.setcolor(color.white);
    paint.settextsize(18);
    paint.setantialias(true);
    canvas.drawtext(fps, 15, 15, paint);
  }
  @override
  public void surfacechanged(surfaceholder arg0, int arg1, int arg2, int arg3) {
  }
  @override
  public void surfacecreated(surfaceholder arg0) {
    if (!dt.isalive()) {
      dt.start();
    }
    if (!pt.isalive()) {
      pt.start();
    }
  }
  @override
  public void surfacedestroyed(surfaceholder arg0) {
    dt.flag = false;
    dt = null;
    pt.flag = false;
    pt = null;
  }
}

4.绘图类drawthread及activity类

基本与上节相同

drawthread类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.particle;
import android.graphics.canvas;
import android.view.surfaceholder;
public class drawthread extends thread {
  particleview pv;
  surfaceholder surfaceholder;
  boolean flag=false;
  int sleepspan=30;
  long start =system.nanotime(); //记录起始时间,该变量用于计算帧速率
  int count=0 ; //记录帧数
  public drawthread(particleview pv,surfaceholder surfaceholder) {
    this.pv=pv;
    this.surfaceholder=surfaceholder;
    this.flag=true;
  }
  public void run() {
    canvas canvas=null;
    while(flag) {
      try {
        canvas=surfaceholder.lockcanvas(null); //获取ballview的画布
        synchronized (surfaceholder) {
          pv.dodraw(canvas);
        }
      } catch (exception e) {
        e.printstacktrace();
      } finally {
        if(canvas!=null) {
          surfaceholder.unlockcanvasandpost(canvas); // surfaceholder解锁,并将画布传回
        }
      }
      this.count++;
      if(count==20) { //计满20帧时计算一次帧速率
        count=0;
        long tempstamp=system.nanotime();
        long span=tempstamp-start;
        start=tempstamp;
        double fps=math.round(100000000000.0/span*20)/100.0;
        pv.fps="fps:"+fps;
      }
      try {
        thread.sleep(sleepspan);
      } catch (interruptedexception e) {
        e.printstacktrace();
      }
    }
  }
}

mainactivity类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.particle;
import android.app.activity;
import android.os.bundle;
import android.view.window;
import android.view.windowmanager;
public class mainactivity extends activity {
  particleview pv;
  @override
  public void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    requestwindowfeature(window.feature_no_title); //设置不显示标题
    getwindow().setflags(windowmanager.layoutparams.flag_fullscreen, windowmanager.layoutparams.flag_fullscreen); //设置全屏
    pv=new particleview(this);
    setcontentview(pv);
  }
}

效果图:

Android游戏开发学习②焰火绽放效果实现方法

Android游戏开发学习②焰火绽放效果实现方法

二、瀑布粒子效果

瀑布粒子和焰火粒子十分类似,二者的运动都是带有初速度的下落运动。所不同的是焰火粒子水平方向和竖直方向的速度均不为零,而瀑布粒子只有水平方向初速度,竖直方向初速度为零。只需在焰火粒子的生成部分particleset类中修改即可。

particleset类add方法修改如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 向粒子集合中添加指定数量的粒子对象(瀑布粒子效果)
*/
public void add2(int count, double starttime) {
    for (int i = 0; i < count; i++) {
      int tempcolor = this.getcolor(i);
      int tempr = 1; // 粒子半径
      double tempv_v = 0; // 粒子竖直方向的速度为0
      double tempv_h = 10 + 20 * (math.random()); // 随机产生粒子水平方向的速度
      int tempx = 50;
      int tempy = (int) (50 - 10 * (math.random())); // 随机产生粒子y坐标,90到100之间
      particle particle = new particle(tempcolor, tempr, tempv_v,
          tempv_h, tempx, tempy, starttime);
      particleset.add(particle);
    }
}

效果图:

Android游戏开发学习②焰火绽放效果实现方法

Android游戏开发学习②焰火绽放效果实现方法

希望本文所述对大家的android程序设计有所帮助。