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);
}
posted @ 2022-06-24 20:25  Jijidawang  阅读(277)  评论(0编辑  收藏  举报
😅​