forked from Kiritouse/TouHouInc--
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParticleManager.cpp
180 lines (170 loc) · 5.09 KB
/
ParticleManager.cpp
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include "ParticleManager.h"
#include "Map.h"
#include <time.h>
#include <list>
#include <graphics.h>
long ret_useless = 0; // Capture the _getwch() return value to eliminate warnings
const int GW = WIDTH_MAP; // Screen width屏幕的宽度
const int GH = HEIGHT_MAP; // Screen height屏幕的高度
const double g = 9.8; // Acceleration of gravity重力
//const double PI = 3.1415926;
const int len_max = 130; // The maximum length of LightLine光线的最大长度
const int h_max = GH - len_max; // The maximum height that LightLine can reach光线能到达的最高高度
const double v_max = sqrt(2 * g * h_max / 10); // Maximum initial velocity of LightLine最大初速度 mgh=mv^2 重力势能=动能
//除以10的缘故是公式是用m做单位,1m代表10个像素点
const int n_max = 5; // Maximum number of fireworks on the screen烟花在屏幕上同时存在最多的数量
class ParticleSwarm
{
struct Particle
{
int x; //表示粒子的运动过程的x坐标
int y; //表示粒子的运动过程的y坐标
int z = 0; // Z axis vertical screen inword Z轴垂直屏幕输入
double vy; // The y axis is positiva for the velocity结构体里面的vy是每个粒子的y方向速度
Particle(int xx, int yy, double vv) :x(xx), y(yy), vy(vv) {}
};
public:
ParticleSwarm(int, int, float);
void Draw() const;
void Move();
bool Finish() const { return vec.size() <= 1; }
private:
double vx;
double vz = 0;
float hsv_h;
clock_t ct = 0;
std::list<Particle> vec;
};
ParticleSwarm::ParticleSwarm(int x, int y, float colorh = float(rand() % 256))
{
hsv_h = colorh + rand() % 20;
hsv_h = hsv_h > 255 ? hsv_h - 256 : hsv_h;//保证颜色值在0-255之间
//Z轴的负向对着人,即人对着屏幕的方向为Z轴的正向
double vm = v_max / 2 * (rand() % 5 + 15.0) / 25.0;
double radian_xz = (rand() % 360) * PI / 180;//X轴偏向Z轴的角度0--2*PI
double radian_xy = (rand() % 90) * PI / 180 + PI / 2;//X轴偏向Y轴的角度PI/2--PI
vx = vm * cos(radian_xy) * cos(radian_xz);//向量在X轴的投影
vz = vm * cos(radian_xy) * sin(radian_xz);//向量在Z轴的投影
double vy = vm * sin(radian_xy); //向量在Y轴的投影
//len表示粒子运动轨迹的长度,也可以认为是装填粒子的数量
int len = rand() % 30 + 20;//rand() % 30 + 50这个是源代码的数值,数值越大,烟花爆炸的范围,散开的范围就越大。
//这一段刻画的是爆炸花束粒子中的其中一条线
while (len)
{
// Use len as time parameter
//目标像素位置=初始像素位置+偏移米×10
int xx = x + int(10 * vx * len / 200.0);
//int zz = int(10 * vz * len / 200.0);
double cvy = vy - g * len / 200.0;
int yy = y + int(10 * (cvy * cvy - vy * vy) / 2 / g);
vec.push_back(Particle(xx, yy, cvy));
--len;
}
}
void ParticleSwarm::Draw() const
{
int n = 0;
auto size = vec.size();
for (auto& x : vec)
{
if (x.x >= 0 && x.x < GW && x.y >= 0 && x.y < GH)
{
//烟花线条的尾端亮度最低,反之首端是比较亮的
float cv = 0.2f + 0.8f * (size - n) / size - x.z; //原来的float cv = 0.2f + 0.8f * (size - n) / size - x.z / 40 * 0.1f
auto color = HSVtoRGB(hsv_h, 1.0f, cv > 0 ? cv : 0);
if (x.z < 0) // Z axis vertical screen inword如果烟花是往屏幕外扩散的话,就把像素点变大
{
setfillcolor(color);
solidcircle(x.x, x.y, abs(x.z) / 80 > 1 ? 2 : 1);
}
else
putpixel(x.x, x.y, color);
}
++n;
}
}
void ParticleSwarm::Move()
{
if (ct == 0)
{
ct = clock();
Draw();
return;
}
for (int i = 0; i < 3 && vec.size() > 1; i++)//
vec.pop_back(); // Delete particles for shortening length画面每次刷新删除3个末尾粒子
clock_t t = clock() - ct;
ct = clock();
for (auto& x : vec)//爆炸花束之中一条光纤的粒子持续运动
{
double vy_cur = x.vy - g * t / 1000.0;
x.x += int(10 * vx * t / 1000.0);
x.y += int(10 * (vy_cur * vy_cur - x.vy * x.vy) / 2 / g);
x.z += int(10 * vz * t / 1000.0);
x.vy = vy_cur;
}
Draw();
}
class Fireworks
{
public:
Fireworks(int, int);
void Move();
bool Empty() const { return vec.empty(); }
private:
std::list<ParticleSwarm> vec;
};
Fireworks::Fireworks(int x, int y)
{
bool colorful = rand() % 100 < 20 ? true : false;//1/5的几率判断
float h = float(rand() % 256);
int n = rand() % 5 + 45;//烟花升到顶点后,爆炸出来的光线量
for (int i = 0; i < n; i++)
{
if (colorful)//决定烟花的爆炸光线,每一条是否是同一颜色的。1/5的几率判断
vec.push_back(ParticleSwarm(x, y));
else
vec.push_back(ParticleSwarm(x, y, h));
}
}
void Fireworks::Move()
{
std::list<decltype(vec.begin())> toDel;
for (auto it = vec.begin(); it != vec.end(); ++it)
{
if (it->Finish())//如果该粒子群里的粒子数只剩下一个,则跳过
{
toDel.push_back(it);
continue;
}
it->Move();//如果粒子群里的粒子数不只是剩下一个,则继续描画它的轨迹
}
for (auto& x : toDel)
vec.erase(x);
}
std::list<Fireworks> vec2;
clock_t ct = clock();
void createFireworks(Enemy::EnemyNode** pp_curEnemy) {
Enemy::EnemyNode(*curEnemy) = *pp_curEnemy;
if (curEnemy->health <= 0)
vec2.push_back(Fireworks(curEnemy->x, curEnemy->y));//从光线顶部开始爆炸,创建烟花对象
}
void update_Particle() {
if (clock() - ct > 10)
{
//cleardevice();
ct = clock();
std::list<decltype(vec2.begin())> toDel2;
for (auto it = vec2.begin(); it != vec2.end(); ++it)
{
if (it->Empty())
{
toDel2.push_back(it);//一句话来说就是储存哪个位置需要删除
continue;
}
it->Move();
}
for (auto& it : toDel2)
vec2.erase(it);
}
}