可能会持续更新吧,,
首先放一个 Kaguya 的波粒:
since C++98,系统要求 Windows .
#include <cmath> #include <cstdio> #include <conio.h> #include <cstdlib> #include <windows.h> using namespace std; const int hs = 28, vs = 65; const double pi = 3.1415926, sx = 14, sy = 17; char ed[hs]; char sqr[hs][vs]; void *bin = NULL; struct nol_bul { nol_bul *last, *next; double x, y, dx, dy; bool move() { this->x += this->dx; this->y += this->dy; int ix = (int)this->x, iy = (int)(this->y * 2 + 0.5); if (ix >= hs || ix < 0 || iy >= vs || iy < 0) { (*(this->last)).next = (this->next); if (this->next != NULL) (*(this->next)).last = this->last; return true; } if (iy > ed[ix]) ed[ix] = iy; sqr[ix][iy] = '.'; return false; } }; struct player { int x, y; void move() { int in = 0; while (_kbhit()) { in = _getch(); if (in == 72) this->x--; else if (in == 80) this->x++; else if (in == 75) this->y--; else if (in == 77) this->y++; } int tmp = this->y << 1; if (this->x >= hs) this->x = hs - 1; if (this->x < 0) this->x = 0; if (tmp >= vs) this->y = (vs >> 1) - 1; if (tmp < 0) this->y = 0; if (sqr[this->x][tmp] == '.') { Sleep(1200); exit(0); } if (tmp > ed[this->x]) ed[this->x] = tmp; sqr[this->x][tmp] = '0'; return; } }; void put(nol_bul&, int); int main() { //初始化 for (int i = 0; i < hs; i++) { for (int j = 0; j < vs; j++) sqr[i][j] = ' '; ed[i] = -1; } int k = 5, a = 5, wait = 0; nol_bul emp; nol_bul *p = NULL, *net = NULL; emp.x = sx; emp.y = sy; emp.dx = emp.dy = 0; emp.last = emp.next = NULL; player sel; sel.x = hs - 2; sel.y = (int)sy; printf ("press to start"); _getch(); while (1) { system("cls"); for (int i = 0; i < hs; i++) { for (int j = 0; j <= ed[i]; j++) { putchar(sqr[i][j]); sqr[i][j] = ' '; } putchar('\n'); ed[i] = -1; } if (wait == 1) { k += 4; if (k >= 360) k -= 360; a += k; if (a >= 360) a -= 360; for (int i = 0; i < 360; i += 72) put(emp, a + i); wait = 0; }else wait = 1; p = &emp; while (p) { net = (*p).next; if ((*p).move()) delete p; p = net; } sel.move(); Sleep(10); } return 0; } void put(nol_bul &emp, int a) { nol_bul *tmp = new nol_bul; (*tmp).last = &emp; (*tmp).next = emp.next; if (emp.next) (*(emp.next)).last = tmp; emp.next = tmp; (*tmp).x = sx; (*tmp).y = sy; (*tmp).dx = 0.7 * cos(a * pi / 180); (*tmp).dy = 0.7 * sin(a * pi / 180); }
我们仔细分析这个代码,可以发现 hs, vs
是屏幕大小,sx, sy
是敌机坐标 .
nol_bul
是子弹类(直线移动),x, y
是目前坐标,dx, dy
是移动变动量(\(x\gets x + dx\),\(y\gets y + dx\)),那个 this->y * 2 + 0.5
是为了让屏幕看起来方一点 .
然后就是显示之类,本质相同,核心部分就在于 put
函数,它接收一个子弹 emp
和一个随时间变化的参数 a
,然后将 emp
初始化 .
在波粒中,a
就是一个角度变量(后面我们把它叫做 \(\alpha\),弧度制),它不断的随时间转动,而坐标增量的计算(斜率)则是简单的正余弦,我们可以列出表达式:
于是直线的方程即可写作(\((s_x,s_y)\) 是初始坐标)
\[y-s_y=\dfrac{\Delta y}{\Delta x}\cdot(x - s_x) \]即
\[y=Fx+s_y-Fs_x \]其中 \(F=\dfrac{\cos\alpha}{\sin\alpha}=\dfrac{1}{\tan{\alpha}}\) .
我们发现这个 \(0.7\) 根本没有用!然而事实上,直线是连续的,屏幕是离散的,我们在控制台中只能设置整数点,于是就有了这个 \(0.7\),你也可以看作是弹幕速度 .
通过这些奥妙重重的东西,我们就生成了一个波与粒的境界!
马上更.