关闭

用C++和EasyX图形库编写一个简单的打砖块游戏(下)

标签: C++EasyX小游戏打砖块
796人阅读 评论(0) 收藏 举报
分类:

  大家好,我终于更新啦。昨天是国庆节最后一天,我也回到了学校,决定趁势把这篇文章更新完,结果也是花了一天多的时间才完成呢。
  回顾上篇,我们已经完成了砖块类和木板类的定义,现在只缺少一个活蹦乱跳的小球,这个小游戏就算完成了。话不多说,我们现在马上开始。
  对于一个小球的话,让我们先想想我们需要定义些什么,处理些什么。
  首先是小球的尺寸和位置,这个容易,用r表示小球半径,ballx,bally代表小球坐标,用addx,addy描述小球在xOy坐标系上的运动方向。另外在初始化小球坐标时,可以将小球摆在木板的上表面的中心位置处;
  其次要处理的问题,也是最核心的两个问题是,小球与砖块的碰撞、小球与木板的碰撞,具体计算的我们稍后讨论。
  以上便是我们定义小球类的思路。首先我们给出小球类的部分。  

class Ball
{
public:
    const int r = 8;        //定义球的半径
    const int speed = 1;    //定义球的飞行速度
    int ballx, bally;       //定义球的坐标
    int addx, addy;         //表示球的飞行方向

    //设置两个个标志量
    bool go;            //小球是否发射
    bool iscatch;       //木板是否捕捉到了小球

    //构造函数 使小球初始时位于木板中心上 参数是木板的宽
    Ball(int board_wide)
    {
        ballx = WINDOW_WIDE / 2;
        bally = WINDOW_HEIGHT - board_wide - r - 1;
        //初始时小球向右上方发射
        addx = 1;
        addy = -1;

        go = 0;         //初始化状态 小球未发射出去
        iscatch = 1;    //初始化状态 球被木板接住
    };
}

  类中定义的两个标志量,将会在接下来的成员函数中用到。
  下面我用一张图解释小球与砖块的碰撞关系,理解了这以后,小球和木板的碰撞同理。
  这里写图片描述

  除此之外,还有小球碰到边界后反弹,这个倒也容易。
  另外关于小球与木板或是砖块间的碰撞,大家可以多画图,多试验。下面的代码我自己确实摸索了很久,能有现在这个效果我也还是挺开心了。
  具体代码如下。

class Ball
{
public:
    const int r = 8;        //定义球的半径
    const int speed = 1;    //定义球的飞行速度
    int ballx, bally;       //定义球的坐标
    int addx, addy;         //表示球的飞行方向

    //设置两个个标志量
    bool go;            //小球是否发射
    bool iscatch;       //木板是否捕捉到了小球

    //构造函数  使小球初始化时位于木板中心上
    Ball(int board_wide)
    {
        ballx = WINDOW_WIDE / 2;
        bally = WINDOW_HEIGHT - board_wide - r - 1;
        //初始时小球向右上发射
        addx = 1;
        addy = -1;

        go = 0;         //初始化状态 小球未发射出去
        iscatch = 1;    //初始化状态 球被木板接住
    };

    //小球移动函数
    void Move(Bricks &brick, Board &board)
    {
        BeginBatchDraw();       //开启批量画图模式 目的是消除闪烁

        //处理边界:左,右,上边界要反弹
        if (ballx >= WINDOW_WIDE - r || ballx <= r) { addx *= -1; }
        if (bally <= r) { addy *= -1; }
        //若小球触及下边界 说明木板板没有接住小球 退出
        if (bally >= WINDOW_HEIGHT - r) { iscatch = 0; return; }
        //判断小球和木板的碰撞(小球发射出去后才能判断 即go = 1)
        if (go&&ballx + 1 >= board.x - r&&ballx - 1 <= board.x + board.length + r&&bally + 1 >= board.y - r)
        {
            go = 0;                            //小球未发射
            if (bally + 1 <= board.y)           //接住了 小球反向
                addy *= -1;
            else if (bally < WINDOW_HEIGHT - r) //这里是对小球碰撞到木板左右侧面的情况进行处理
            {
                addx *= -1;
                addy *= -1;
            }
        }
        int flag = 0;   //表示未小球击中任一砖块
        for (int i = 0; i < brick.y && !flag; i++)
        {
            for (int j = 0; j < brick.x && !flag; j++)
            {
                //此处有砖块 且小球在该砖块的碰撞范围内
                if (brick.bricks[i][j] == 0 && ballx + 1 >= j*brick.length - r&&ballx - 1 <= (j + 1)*brick.length + r&&bally + 1 >= i*brick.wide - r&&bally - 1 <= (i + 1)*brick.wide + r)
                {
                    //左右两边
                    if (bally + 1 > i*brick.wide - r&&bally - 1 < (i + 1)*brick.wide)
                        addx *= -1;
                    //上下两边(图中两灰色直线之间的部分)
                    else if (ballx + 1 >= j*brick.length && ballx - 1 <= (j + 1)*brick.length)
                        addy *= -1;
                    //四个顶角处
                    else
                        continue;
                    brick.bricks[i][j] = 1; //此处砖块被打掉了
                    brick.count--;          //砖块数减一
                    flag = 1;               //击中了 不用继续遍历
                    setfillcolor(BLACK);    //将击中的砖块用黑色覆盖掉
                    fillrectangle(j*brick.length, i*brick.wide, (j + 1)*brick.length, (i + 1)*brick.wide);
                }
            }//
        }//for
        setfillcolor(BLACK);    //擦除小球当前位置
        solidcircle(ballx, bally, r);
        ballx += addx*speed;    //更新位置
        bally += addy*speed;
        if (bally + 1 < board.y - r)
            go = 1;             //小球成功发射
        setfillcolor(RED);      //在新位置画小球
        solidcircle(ballx, bally, r);

        FlushBatchDraw();       //把之前所有的绘图内容显示出来,与BeginBatchDraw()对应
        Sleep(3);               //休眠,就是暂停,使小球慢慢地运动。修改参数的值,可以变相改变游戏速度
    }
};

  至此,我们只需要在自定义函数Gaming中调用以上的类就行了。这其中我们还需要一些按钮选择,比如退出或是重试,使用函数MessageBox即可。下面贴出完整的源代码,同时我也会把源代码上传到百度网盘,地址我会留在文章结尾处的。

#include<graphics.h>
#include<conio.h>

const int WINDOW_HEIGHT = 600;  //定义窗口的高
const int WINDOW_WIDE = 400;    //定义窗口的宽

class Bricks
{
public:
    int bricks[12][12];                 //用二维数组保存所有砖块
    int count;                          //记录砖块总数
    const int x = 10, y = 5;            //确定砖块有几排(y)几列(x)
    const int length = WINDOW_WIDE / x; //计算每个砖块的长和宽
    const int wide = 20;

    //构造函数
    Bricks()
    {
        memset(bricks, 0, sizeof(bricks));  //初始化 0表示有砖块
        count = x*y;                        //计算砖块总数
    }

    //画出所有的砖块
    void drawallbricks()
    {
        setfillcolor(YELLOW);   //设置砖块颜色
        setlinecolor(BLACK);    //设置边框颜色
        for (int i = 0; i < y; i++)
            for (int j = 0; j < x; j++)
                fillrectangle(j*length, i*wide, (j + 1)*length, (i + 1)*wide);
    }
};

class Board                 //定义木板类
{
public:
    int x, y;               //定义板的坐标
    const int length = 60;  //定义板的长度
    const int wide = 15;    //定义板的宽度

    //构造函数 将木板的坐标初始化在中心位置
    Board()
    {
        x = WINDOW_WIDE / 2 - length / 2;
        y = WINDOW_HEIGHT - wide;
    }

    //木板移动函数
    void Move()
    {
        int ch;         //接受一个键值
        ch = _getch();

        setfillcolor(BLACK);    //将木板当前位置用背景色黑色覆盖
        solidrectangle(x, y, x + length, y + wide);

        switch (ch)
        {
        case 75:        //每次左移木板长度的1/3
        case 'A':
        case 'a':
            x -= length / 3;
            break;
        case 77:        //每次右移木板长度的1/3
        case 'D':
        case 'd':
            x += length / 3;
            break;
        }
        //木板左右移动的边界限制
        if (x <= 0) x = 0;
        if (x >= WINDOW_WIDE - length) x = WINDOW_WIDE - length;
        setfillcolor(BLUE);     //更新坐标后画新木板
        solidrectangle(x, y, x + length, y + wide);
    }
};

class Ball
{
public:
    const int r = 8;        //定义球的半径
    const int speed = 1;    //定义球的飞行速度
    int ballx, bally;       //定义球的坐标
    int addx, addy;         //表示球的飞行方向

    //设置两个个标志量
    bool go;            //小球是否发射
    bool iscatch;       //木板是否捕捉到了小球

    //构造函数  使小球初始化时位于木板中心上
    Ball(int board_wide)
    {
        ballx = WINDOW_WIDE / 2;
        bally = WINDOW_HEIGHT - board_wide - r - 1;
        //初始时小球向右上发射
        addx = 1;
        addy = -1;

        go = 0;         //初始化状态 小球未发射出去
        iscatch = 1;    //初始化状态 球被木板接住
    };

    //小球移动函数
    void Move(Bricks &brick, Board &board)
    {
        BeginBatchDraw();       //开启批量画图模式

        //处理边界:左,右,上边界要反弹
        if (ballx >= WINDOW_WIDE - r || ballx <= r) { addx *= -1; }
        if (bally <= r) { addy *= -1; }
        //若小球触及下边界 说明木板板没有接住小球
        if (bally >= WINDOW_HEIGHT - r) { iscatch = 0; return; }
        //判断小球和木板的碰撞(小球发射出去后才能判断 即go = 1)
        if (go&&ballx + 1 >= board.x - r&&ballx - 1 <= board.x + board.length + r&&bally + 1 >= board.y - r)
        {
            go = 0;                             //小球未发射
            if (bally + 1 <= board.y)           //接住了 小球反向
                addy *= -1;
            else if (bally < WINDOW_HEIGHT - r) //这里是对小球碰撞到木板左右侧面的情况进行处理
            {
                addx *= -1;
                addy *= -1;
            }
        }
        int flag = 0;   //表示未小球击中任一砖块
        for (int i = 0; i < brick.y && !flag; i++)
        {
            for (int j = 0; j < brick.x && !flag; j++)
            {
                //此处有砖块 且小球在该砖块的碰撞范围内
                if (brick.bricks[i][j] == 0 && ballx + 1 >= j*brick.length - r&&ballx - 1 <= (j + 1)*brick.length + r&&bally + 1 >= i*brick.wide - r&&bally - 1 <= (i + 1)*brick.wide + r)
                {
                    //左右两边
                    if (bally + 1 > i*brick.wide - r&&bally - 1 < (i + 1)*brick.wide)
                        addx *= -1;
                    //上下两边
                    else if (ballx + 1 >= j*brick.length && ballx - 1 <= (j + 1)*brick.length)
                        addy *= -1;
                    //四个顶角处
                    else
                        continue;
                    brick.bricks[i][j] = 1; //此处砖块被打掉了
                    brick.count--;          //砖块数减一
                    flag = 1;               //击中了 不用继续遍历
                    setfillcolor(BLACK);    //将击中的砖块用黑色覆盖掉
                    fillrectangle(j*brick.length, i*brick.wide, (j + 1)*brick.length, (i + 1)*brick.wide);
                }
            }//
        }//for
        setfillcolor(BLACK);    //擦除小球当前位置
        solidcircle(ballx, bally, r);
        ballx += addx*speed;    //更新位置
        bally += addy*speed;
        if (bally + 1 < board.y - r)
            go = 1;             //小球成功发射
        setfillcolor(RED);      //在新位置画小球
        solidcircle(ballx, bally, r);

        FlushBatchDraw();       //把之前所有的绘图内容显示出来
        Sleep(3);               //休眠,就是暂停,使小球慢慢地运动
    }
};

int Gaming()
{
    Bricks brick;
    brick.drawallbricks();

    Board board;
    setfillcolor(BLUE);
    solidrectangle(board.x, board.y, board.x + board.length, board.y + board.wide);

    Ball ball(board.wide);
    setfillcolor(RED);
    solidcircle(ball.ballx, ball.bally, ball.r);

    while (1)
    {
        //游戏结束条件
        if (!ball.iscatch || brick.count == 0)
        {
            //本局结束后把当前小球和木板清除掉
            setfillcolor(BLACK);
            solidcircle(ball.ballx, ball.bally, ball.r);
            solidrectangle(board.x, board.y, board.x + board.length, board.y + board.wide);

            if (brick.count > 0)
                return MessageBox(NULL, L"You Lose!", L"打砖块", MB_RETRYCANCEL);
            else if (brick.count == 0)
                return MessageBox(NULL, L"You Win!", L"打砖块", MB_RETRYCANCEL);
        }

        if (_kbhit())   //判断你是否按下键 按下返回1 没有返回0
        {
            board.Move();
        }
        ball.Move(brick, board);
    }
}

int main()
{
    initgraph(WINDOW_WIDE, WINDOW_HEIGHT);  //初始化窗口
    while (1)
    {
        if (Gaming() == IDCANCEL)           //点击 取消
            return 0;
    }
}

  终于结束啦,我很高兴这次能与大家一起分享这个小游戏,最后谢谢大家了。
  
  百度网盘 源码下载链接:http://pan.baidu.com/s/1gfIk6av 密码:obw4

1
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

#利用C语言-EasyX图形设计-制作简易计算器#

花了大概一周的时间,今天终于完成了简易版的计算器的制作,不过这计算器只能实现一些简单的加减乘除,不能进行复杂的运算,有兴趣的小伙伴们可以在这基础上进行添加修改,一起努力,一起进步!!#include ...
  • shu_lance
  • shu_lance
  • 2016-06-02 23:11
  • 2501

C语言游戏_弹弹乐(打砖块)

自从学了C语言,总想着写点好玩的东西出来,由于我比较喜欢玩游戏,所以对写游戏一直情有独钟。 这次花费了一个月左右的时间用纯C语言写了一个我比较喜欢的一款游戏《弹弹乐》出来,在这里分享给大家,希望能给大...
  • u011134502
  • u011134502
  • 2015-06-27 14:18
  • 2705

纯C语言写的拼图游戏源码

#include #include #include #include int step=0; void map()//游戏菜单函数。 { printf("▇▇▇▇▇▇▇▇▇▇▇▇▇▇\n")...
  • u011131296
  • u011131296
  • 2013-12-12 17:44
  • 2518

点灯小游戏 平台:VS2015 需要安装图形库EasyX(600K左右)基于C++语言的win32控制台应用程序

点灯小游戏 开发平台:VS2015 需要安装图形库EasyX(600K左右) 基于C++语言的win32控制台应用程序
  • qq_29861815
  • qq_29861815
  • 2017-12-07 12:45
  • 83

C++课程实践飞机大战(基于easyx图形库)

  • 2018-01-08 21:18
  • 17.40MB
  • 下载

C/C++ 拼图游戏 代码简单 带有graphics图形库

代码: #include #include #include #include #include #include int map[4][3]; int num = 0; IMAGE image1, ...
  • zggzgw
  • zggzgw
  • 2017-07-13 15:51
  • 617

C/C++ 拼图游戏 代码简单 鼠标点击版拼图游戏 带有graphics图形库

#include #include #include #include #include #include int map[4][3]; int num = 0; int x, y; IMAGE im...
  • zggzgw
  • zggzgw
  • 2017-07-15 21:17
  • 460

VS2015配置EasyX图形库

首先下载安装好VS2015 下载Easyx图形库 链接: https://pan.baidu.com/s/1c1YsVS0 密码: y2r7 1、首先打开Easyx文件夹,双击打开include文件夹...
  • Leo_whj
  • Leo_whj
  • 2017-12-10 18:22
  • 181

graphics.py python的一个简单图形库

  • 2013-11-15 12:30
  • 27KB
  • 下载

基于EasyX图形库的天天爱消除

基于EasyX图形库的天天爱消除 什么是EasyX图形库 EasyX 是针对 C++ 的图形库,可以帮助 C++语言初学者快速上手图形和游戏编程。 http://www.easyx.c...
  • weixin_40739833
  • weixin_40739833
  • 2017-12-29 19:28
  • 86
    个人资料
    • 访问:2352次
    • 积分:126
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档