模拟一定范围内用挡板使小球不下落的经典小游戏。
目录
宽高在此修改
设置小球可能出现的形状
其他全局参数
建立挡板类
建立小球类
实现与挡板碰撞
考虑小球间的相互碰撞
实现小球移动
打印界面
主程序
完整源代码及注释
首先需要初始化游戏参数:宽度,高度,小球数,挡板长度。
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
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;
}
}
}
效果图:
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;
}
}
效果图:
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;
}
欢迎大家测试游玩,你们的反馈就是我创作的动力,来试试挑战模式你能得多少分?