C++ 简易弹球游戏(分块解释、源码、注释)

模拟一定范围内用挡板使小球不下落的经典小游戏。

目录

宽高在此修改

设置小球可能出现的形状

其他全局参数

建立挡板类

建立小球类

实现与挡板碰撞

考虑小球间的相互碰撞

实现小球移动

打印界面

主程序

完整源代码及注释

首先需要初始化游戏参数:宽度,高度,小球数,挡板长度。

宽高在此修改

static int length = 24, height = 12;              //宽度要大于挡板

设置小球可能出现的形状

static string Shape = "abcdefghijklmnopqrstuvwxyz"; //小球形状库

其他全局参数

static int score = 0, gclock = 2 * height, flat; //gclock判断游戏是否继续,flat为简单模式,不会结束

其中原始得分为0,gclock用以判断游戏是否结束,我们用小球上下一个来回都没有得分判断游戏结束,gclock初值为两个高度,得分后重新赋予两个高度的值,再在循环里递减,小于0时结束。

flat的值在程序准备阶段确定,设置游戏是否有底部,若选休闲模式(1)则有挑战模式(0)则无。因此,只有选择了挑战模式(0)才会出现游戏结束,结算得分界面,休闲模式(1)为无限循环

int n;
cout << "小球数:";
cin >> n;
cout << "模式选择:" << endl << "挑战模式(0)" << endl << "休闲模式(1)" << endl;
cin >> flat;
ball* p = new ball[n];

建立挡板类

class plate {
public:
	int l, x, y, vx, vy;
	plate(int tl = 3, int tx = 1, int ty = height, int tvx = 3, int tvy = 1) :l(tl), x(tx), y(ty), vx(tvx), vy(tvy) {}
	void move();
};

初始化臂长l = 3出生坐标左下角(x = 1,y = height),默认速度:水平(vx = 3),竖直(vy = 1)

(在tl参数修改臂长,tvx、tvy修改板移速)

实现挡板的上下左右移动(挑战模式只能左右),用头文件为#include下的_kbhit()函数判断键盘有无输入,用_getch()函数得到输入的键值(ASCII码值),经判断后作变量更改。

void plate::move() {
	if (_kbhit()) {                           //键盘输入w、s、a、d控制挡板上下左右
		int ch = _getch();
		if (ch == 97) {                       //a的ASCII码
			if (x > vx) x -= vx;
			else if (x > 1) x = 1;
		}
		else if (ch == 100) {                 //d的ASCII码
			if (x <= length - 2 * l - vx) x += vx;
			else if (x < length - 2 * l) x = length - 2 * l;
		}
		else if (ch == 115 && flat) {                 //s的ASCII码
			if (y < height - vy) y += vy;
			else y = height;
		}
		else if (ch == 119 && flat) {                 //w的ASCII码
			if (y > vy) y -= vy;
			else y = 1;

		}
	}
}

效果图:

C++ 简易弹球游戏(分块解释、源码、注释)_第1张图片

建立小球类

​class ball {
public:
	int x, y, vx, vy;
	char shape;
	ball(int tx = rand() % (length - 1) + 1, int ty = rand() % (height / 2) + 1, int tvx = rand() % 3 - 1, int tvy = rand() % 3 - 1, char ts = Shape[rand() % 26]) :x(tx), y(ty), vx(tvx), vy(tvy), shape(ts) {}
	void crash_edge();
	void crash_board(plate board);
	bool crash_ball(ball& tb);
	void Swap(ball& tb);
	void next();
};

​

初始化横坐标随机1~length - 1,纵坐标随机1~height/2,防止开局掉落,水平和竖直速度均随机-1~1

实现边缘反弹:(休闲模式flat = 1,触底反弹)

void ball::crash_edge() {
	if (x + vx == 0 || x + vx == length + 1)vx *= -1;
	if (y + vy == 0 || (y + vy == height + 1 && flat))vy *= -1;

}

效果图:

实现与挡板碰撞

void ball::crash_board(plate board) {                  //考虑与挡板碰撞,只有上反弹得分
	if (y + vy == board.y && abs(x + vx - board.x - board.l) <= board.l) {
		vy *= -1;
		if(y == board.y - 1)
		score++;
		gclock = 2 * height;                           //用一个来回不得分判断游戏结束
	}
	if (y == board.y) {
		if ((x == board.x - 1 && vx == 1) || (x == board.x + 2 * board.l + 1 && vx == -1)) vx *= -1;
		else if (x >= board.x && x <= board.x + 2 * board.l) vy *= -1;
	}
}

效果图:

C++ 简易弹球游戏(分块解释、源码、注释)_第2张图片

考虑小球间的相互碰撞

bool ball::crash_ball(ball& tb) {                      //判断小球间碰撞
	if (((x + vx == tb.x) && (tb.x + tb.vx == x) && (y + vy == tb.y) && (tb.y + tb.vy == y)) || (x == tb.x && y == tb.y)) {
		return true;
	}
	return false;
}
void ball::Swap(ball& tb) {                            //交换两球速度
	swap(vx, tb.vx);
	swap(vy, tb.vy);
}

设小球质量都相同,这里只简单地做出速度交换和碰撞反馈。

实现小球移动

void ball::next() {
	x += vx;
	y += vy;
}

加一次现速度。

打印界面

void display(plate board, ball *p, int n) {          //打印边界、挡板和球
	for (int i = 0; i <= height + 1; i++) {
		for (int j = 0; j <= length; j++) {
			if (i == 0 || (i == height + 1 && flat))cout << "0";
			else {
				int flag = 1;
				for (int k = 0; k < n; k++) {
					if (p[k].x == j && p[k].y == i) {          //两球碰撞合成X
						for (int l = k + 1; l < n; l++) {
							if (flag && p[l].x == j && p[l].y == i) {
								cout << "X";
								flag = 0;
								break;
							}
						}
						if (flag) {
							cout << p[k].shape;
							flag = 0;
							break;
						}
					}
				}
				if (flag && (i == board.y && abs(j - board.x - board.l) <= board.l))cout << "-";
				else if (j == 0) cout << "0";
				else if (flag || (!flag && j == length)) cout << " "; //打边界会凸起
			}
		}
		cout << "0" << endl;
	}
}

逐帧打印小球、挡板位置,建议小球数不要设置太多,宽高也不要太大,会有些闪QAQ

可以看到使用了多层循环,优化极差,设计打到右边界会凸起以至于没那么死板,若出现同一个位置的碰撞打印反馈为“X”。

主程序

int main() {
	plate board;
	int n;
	cout << "小球数:";
	cin >> n;
	cout << "模式选择:" << endl << "挑战模式(0)" << endl << "休闲模式(1)" << endl;
	cin >> flat;
	ball* p = new ball[n];
	while (1) {
		board.move();
		system("cls");
		display(board,p,n);
		cout << "得分数:" << score;
		Sleep(100);
		for (int i = 0; i < n; i++) {                   //检查相撞情况
			for (int j = i + 1; j < n; j++) {
				if (p[i].crash_ball(p[j])) {
					p[i].Swap(p[j]);
					break;
				}
			}
			p[i].crash_board(board);
			p[i].crash_edge();
			p[i].next();
		}
		gclock--;
		if (gclock < 0 && !flat) {
			system("cls");
			break;
			delete[]p;
		}
	}
	cout << "游戏结束,最终得分:" << score;
	string s;
	cin >> s;
	return 0;
}

完整源代码及注释

#include 
#include 
#include 
using namespace std;
static int length = 24, height = 12;              //宽度要大于挡板
static string Shape = "abcdefghijklmnopqrstuvwxyz"; //小球形状库
static int score = 0, gclock = 2 * height, flat; //gclock判断游戏是否继续,flat为简单模式,不会结束
class plate {                                      //建立挡板类
public:
	int l, x, y, vx, vy;
	plate(int tl = 3, int tx = 1, int ty = height, int tvx = 3, int tvy = 1) :l(tl), x(tx), y(ty), vx(tvx), vy(tvy) {}
	void move();
};
class ball {                                       //建立球类
public:
	int x, y, vx, vy;
	char shape;
	ball(int tx = rand() % (length - 1) + 1, int ty = rand() % (height / 2) + 1, int tvx = rand() % 3 - 1, int tvy = rand() % 3 - 1, char ts = Shape[rand() % 26]) :x(tx), y(ty), vx(tvx), vy(tvy), shape(ts) {}
	void crash_edge();
	void crash_board(plate board);
	bool crash_ball(ball& tb);
	void Swap(ball& tb);
	void next();
};
void display(plate board, ball *p, int n) {          //打印边界、挡板和球
	for (int i = 0; i <= height + 1; i++) {
		for (int j = 0; j <= length; j++) {
			if (i == 0 || (i == height + 1 && flat))cout << "0";
			else {
				int flag = 1;
				for (int k = 0; k < n; k++) {
					if (p[k].x == j && p[k].y == i) {          //两球碰撞合成X
						for (int l = k + 1; l < n; l++) {
							if (flag && p[l].x == j && p[l].y == i) {
								cout << "X";
								flag = 0;
								break;
							}
						}
						if (flag) {
							cout << p[k].shape;
							flag = 0;
							break;
						}
					}
				}
				if (flag && (i == board.y && abs(j - board.x - board.l) <= board.l))cout << "-";
				else if (j == 0) cout << "0";
				else if (flag || (!flag && j == length)) cout << " "; //打边界会凸起
			}
		}
		cout << "0" << endl;
	}
}
void plate::move() {
	if (_kbhit()) {                           //键盘输入w、s、a、d控制挡板上下左右
		int ch = _getch();
		if (ch == 97) {                       //a的ASCII码
			if (x > vx) x -= vx;
			else if (x > 1) x = 1;
		}
		else if (ch == 100) {                 //d的ASCII码
			if (x <= length - 2 * l - vx) x += vx;
			else if (x < length - 2 * l) x = length - 2 * l;
		}
		else if (ch == 115 && flat) {                 //s的ASCII码
			if (y < height - vy) y += vy;
			else y = height;
		}
		else if (ch == 119 && flat) {                 //w的ASCII码
			if (y > vy) y -= vy;
			else y = 1;

		}
	}
}
void ball::crash_edge() {                             //考虑与边界碰撞
	if (x + vx == 0 || x + vx == length + 1)vx *= -1;
	if (y + vy == 0 || (y + vy == height + 1 && flat))vy *= -1;

}
void ball::crash_board(plate board) {                  //考虑与挡板碰撞,只有上反弹得分
	if (y + vy == board.y && abs(x + vx - board.x - board.l) <= board.l) {
		vy *= -1;
		if(y == board.y - 1)
		score++;
		gclock = 2 * height;                           //用一个来回不得分判断游戏结束
	}
	if (y == board.y) {
		if ((x == board.x - 1 && vx == 1) || (x == board.x + 2 * board.l + 1 && vx == -1)) vx *= -1;
		else if (x >= board.x && x <= board.x + 2 * board.l) vy *= -1;
	}
}
bool ball::crash_ball(ball& tb) {                      //判断小球间碰撞
	if (((x + vx == tb.x) && (tb.x + tb.vx == x) && (y + vy == tb.y) && (tb.y + tb.vy == y)) || (x == tb.x && y == tb.y)) {
		return true;
	}
	return false;
}
void ball::Swap(ball& tb) {                            //交换两球速度
	swap(vx, tb.vx);
	swap(vy, tb.vy);
}
void ball::next() {
	x += vx;
	y += vy;
}
int main() {
	plate board;
	int n;
	cout << "小球数:";
	cin >> n;
	cout << "模式选择:" << endl << "挑战模式(0)" << endl << "休闲模式(1)" << endl;
	cin >> flat;
	ball* p = new ball[n];
	while (1) {
		board.move();
		system("cls");
		display(board,p,n);
		cout << "得分数:" << score;
		Sleep(100);
		for (int i = 0; i < n; i++) {                   //检查相撞情况
			for (int j = i + 1; j < n; j++) {
				if (p[i].crash_ball(p[j])) {
					p[i].Swap(p[j]);
					break;
				}
			}
			p[i].crash_board(board);
			p[i].crash_edge();
			p[i].next();
		}
		gclock--;
		if (gclock < 0 && !flat) {
			system("cls");
			break;
			delete[]p;
		}
	}
	cout << "游戏结束,最终得分:" << score;
	string s;
	cin >> s;
	return 0;
}

欢迎大家测试游玩,你们的反馈就是我创作的动力,来试试挑战模式你能得多少分?

你可能感兴趣的:(小游戏,c++,开发语言,游戏程序)