C++ 弹幕游戏
可能会持续更新吧,,
我们说一下固定弹,直线轨迹的做法 .
首先放一个 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\),弧度制),它不断的随时间转动,而坐标增量的计算(斜率)则是简单的正余弦,我们可以列出表达式:
\[\begin{cases}\Delta x = 0.7\cos\alpha\\ \Delta y = 0.7\sin\alpha\end{cases}
\]
于是直线的方程即可写作(\((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\),你也可以看作是弹幕速度 .
通过这些奥妙重重的东西,我们就生成了一个波与粒的境界!
一些比较有意思的魔改(put):
魔改 1 (2, y0, y1)
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 = 2 * y0(a * pi / 180);
(*tmp).dy = 2 * y1(a * pi / 180);
}
魔改 2(0.7,tanh,tan)
虽然敌机上面是安定但是安定点其实很难到达(准备改成自机狙
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 * tanh(a * pi / 180);
(*tmp).dy = 0.7 * tan(a * pi / 180);
}
魔改 3(0.7, cos, sin 加扰动)
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;
double p = 0.01 * cosh(1 / M_E * acos(fmod(a, 2) - 1)), q = 0.01 * sinh(1 / M_E * asin(fmod(a, 2) - 1));
int T = 100;
while (T--)
{
double old_p = p, old_q = q;
p = fmod(sin(old_p) * cos(old_q) + 114514, 2) - 1;
q = fmod(acos(old_q) * asin(old_q) + 1919810, 2) - 1;
} p = 1 - 0.1 * p; q = 1 + 0.2 * q;
(*tmp).dx = 0.8 * p * sin((a + log(1 / q)) * pi / 180);
(*tmp).dy = 0.8 * q * cos((a - log(1 / p)) * pi / 180);
}
增加重开机制
#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;
bool fuck = false;
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;
}
};
int main();
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);
system("cls");
puts("You lose!");
puts("Again? ");
fuck = true;
main();
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");
if (fuck) Sleep(500);
_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);
}
以下是博客签名,正文无关
本文来自博客园,作者:Jijidawang,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/16410110.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ