C语言实战:弹球小游戏

这是一个适合初学者学习的c语言弹球小游戏,基于easyX图形库。

一、游戏概述

  1. 小球生成位置随机,小球初始运动方向随机。

  1. 小球碰到上边界、左右边界、矩形挡板时反弹。

  1. 游戏中可通过键盘上的A、D键控制挡板向左移动或向右移动。

  1. 小球碰到下边界则游戏结束。

  1. 游戏结束时界面显示“游戏结束”,两秒后初始化游戏数据,重启游戏。

二、储存游戏数据的结构体

游戏中需要用到的的游戏数据有:小球圆心x,y坐标、小球x,y方向分速度、小球半径、矩形挡板左上角坐标及右下角坐标。

为方便后续使用这些数据,我们将其定义为结构体,代码如下。

typedef struct {
    int x, y;//小球圆心x,y坐标
    int vx, vy;//小球x,y方向分速度
    int R;//小球半径
    int l, t, r, b;//矩形挡板左上角坐标及右下角坐标
}lyn;

为了使主函数内容更加精炼、有逻辑,我们定义先三个函数,再在主函数中依次调用这三个函数。

三、初始化游戏数据的函数

游戏中我们建立一个800*600像素的窗体,并使用物理坐标,即窗体左上角为坐标原点,x轴正方向向右,y轴正方向向下。

函数的返回值为void类型,形式参数为lyn*a

我们希望小球在左上角坐标为(200,150)、右下角坐标为(600,450)的矩形区域内随机生成。

即小球x坐标取值范围为200到600,小球y坐标取值范围为150到450。

我们可以引入rand()函数,它的作用是生成大于0的随机的整数,代码如下。

a->x = rand() % 401 + 200;
a->y = rand() % 301 + 150;

其次,我们想让小球的初始运动方向随机,代码如下。

a->vx = 5;
a->vy = 5;
if (rand() % 2 == 0)
    a->vx = -a->vx;
else
    a->vy = -a->vy;

然后再初始化其他数据,代码如下。

a->R = 40;
    a->l = 300;
    a->t = 580;
    a->r = 400;
    a->b = 600;

四、键盘控制挡板移动的函数

要用A、D键控制挡板移动,就需要程序读取字符,我们很快会想到getchar()函数,但是,getchar()函数有一个局限性,就是按下A/D键后必须再按下enter键才会刷新缓存,可是我们希望实现键盘与游戏的实时交互,怎么办呢?

这里介绍getch()函数。

getch()是平台实现的函数,不是c语言自带的函数。近年来,VS编译器为了区分平台实现的函数与c语言自带的函数,平台实现的函数前通常加上下划线,写成_getch()。_getch会将用户输入的数据直接放入缓存区中,不用按下enter键。头文件是conio.h。

但是,_getch()是阻塞函数,缓存区中没有数据时,会阻塞程序运行,等待用户输入数据。

kbhit()函数可以解决_getch()的阻塞问题。当缓存区中没有数据时,函数返回0,有数据返回非0。头文件是conio.h。

以下为函数代码及注释。

void direction(lyn*a)
{
    if (_kbhit() != 0)
    {
        char c = _getch();
        switch (c)
        {
        case 'a'://键盘输入a
            if (a->l >= 0)//挡板不能超过窗体最左侧
            {
                a->l -= 20;//挡板左移20像素
                a->r -= 20;
                break;
            }
        case 'd'://键盘输入d
            if (a->r <= 800)//挡板不能超过窗体最右侧
            {
                a->l += 20;//挡板右移20像素
                a->r += 20;
                break;
            }
        }
    }
}

五、小球反弹及判断游戏是否结束的函数

小球碰到上边界或矩形挡板时,x轴方向分速度不变,y抽方向分速度反向。

if (a->y <= 40 || (a->y >= 540 && a->x >= a->l && a->x <= a->r))
        a->vy = -a->vy;

小球碰到左右边界时,y轴方向分速度不变,x抽方向分速度反向。

if (a->x <= 40 || a->x >= 760)
        a->vx = -a->vx;

小球碰到下边界则游戏结束,游戏结束时界面显示“游戏结束”,两秒后初始化游戏数据,重启游戏。

代码及注释如下。

if (a->y >= 560)
    {
        cleardevice();
        settextcolor(BLACK);//设置文字颜色
        settextstyle(80, 0, "楷体");//设置文字样式
        outtextxy(190, 200, "游 戏 结 束");//打印文字
        Sleep(2000);//程序休眠2000毫秒
        game(a);//调用初始化游戏数据的函数重启游戏
    }

六、主函数

定义好了上述三个函数后,主函数的内容相对来说就比较简单了,利用循环条件为1的while死循环加上Sleep()函数每帧休眠30毫秒,再不断重复地清空窗体并绘制挡板和小球即可。

代码及注释如下。

int main()
{
    initgraph(800, 600);
    setbkcolor(RGB(118, 189, 255));//设置背景色为浅蓝色
    cleardevice();
    lyn a;//定义结构体
    game(&a);//初始化游戏数据的函数
    srand(unsigned int(time(NULL)));//设置当前时间为随机数种子
    while (1)
    {
        cleardevice();//清空窗体
        solidcircle(a.x, a.y, a.R);//绘制小球
        solidrectangle(a.l, a.t, a.r, a.b);//绘制挡板
        Sleep(30);//每帧休眠30毫秒
        a.x += a.vx;//小球移动
        a.y += a.vy;
        direction(&a);//键盘控制挡板移动的函数
        gameover(&a);//小球反弹及判断游戏是否结束的函数
    }
    getchar();
    closegraph();
    return 0;
}

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,以下是一个简单的扫雷小游戏的 C++ 代码: #include <iostream> #include <ctime> #include <cstdlib> using namespace std; const int MAXN = 100; const int MAXM = 100; int n, m; char mine[MAXN][MAXM]; // 存储地图信息 bool vis[MAXN][MAXM]; // 标记是否已经翻开 int dx[] = {0, 0, 1, -1, 1, -1, 1, -1}; // 方向数组 int dy[] = {1, -1, 0, 0, 1, -1, -1, 1}; void init() { // 初始化地图 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { mine[i][j] = '0'; vis[i][j] = false; } } // 随机生成地雷 int cnt = n * m / 10; while (cnt--) { int x = rand() % n; int y = rand() % m; mine[x][y] = '*'; } } void print() { // 打印地图 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (vis[i][j]) { cout << mine[i][j] << " "; } else { cout << "- "; } } cout << endl; } } void dfs(int x, int y) { // 深度优先搜索 vis[x][y] = true; if (mine[x][y] == '*') { // 踩到地雷,游戏结束 cout << "Game Over!" << endl; print(); exit(0); } if (mine[x][y] == '0') { // 如果周围没有地雷,继续搜索 for (int i = 0; i < 8; i++) { int nx = x + dx[i]; int ny = y + dy[i]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !vis[nx][ny]) { dfs(nx, ny); } } } } int main() { srand(time(NULL)); cout << "请输入地图大小(n m):"; cin >> n >> m; init(); while (true) { print(); int x, y; cout << "请输入要翻开的格子坐标(x y):"; cin >> x >> y; if (x < 0 || x >= n || y < 0 || y >= m) { cout << "坐标不合法,请重新输入!" << endl; continue; } if (vis[x][y]) { cout << "这个格子已经翻开了,请重新输入!" << endl; continue; } dfs(x, y); bool win = true; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (mine[i][j] != '*' && !vis[i][j]) { win = false; break; } } if (!win) break; } if (win) { cout << "You Win!" << endl; print(); break; } } return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值