欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-07 17:30:58
...

  大家好,这里先祝大家月饼节快乐了!博主我呢,目前是名大二学生,学校在本学期开设了C++的课程。为了能练习C++,我尝试着完成了一个简易的打砖块游戏。本着记录心得和同大家交流的想法,我决意写下这篇博客。需要说明的是,游戏的主要思路借鉴了某培训机构的公开课视频,我在此对老师表示感谢。不过老师是用纯C语言完成的,在我用C++重写时,遇到了不少问题,也做了很多学习和思考,最后完成得也算是比较满意吧。希望这个简单的项目能让初学的我们更好地学习和理解C++吧。
  整个代码不过200行,这里先贴出几张效果图吧。
用C++和EasyX图形库编写一个简单的打砖块游戏(上)

  我目前打算把这篇博客写成上下两篇,毕竟我也是第一次打算写这么长的文章。若其中有疏漏,欢迎大家指出,当然也包括之后代码里可能出现的各种bug啦等等。
  不过,还需说明的是,我使用的编译器是VS2015,另需用到EasyX。这里附上它的下载地址吧。EasyX下载请点击这里.
  在下载好了以后,选择和你相对应的编译器进行安装就好了。
  那么,准备工作完成后,让我们开始教程吧。
  打开编译器后,自然是要先创建一个空项目,项目名称用“打砖块”就好了。创建好了以后,我们就可以开始书写代码了。
  首先调用以下头文件。前者是图形库文件,后者主要用于进行键盘操作。

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

  接着我们要确定游戏界面的大小,这需要调用函数  

initgraph(int width, int height, int flag)

  它的作用是初始化一个图形区域,前两个参数是图形区域的宽和高,后一个参数是绘图环境的样式,常设置为空(具体作用我也不明白…)。而我的设定是一个600*400像素单位的矩形,代码如下。

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

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

int main()
{
    initgraph(WINDOW_WIDE, WINDOW_HEIGHT);  //初始化窗口
    _getch();
    return 0;
}

  那么编译运行后我们应该得到一个600*400像素的矩形界面了,如下图所示。
用C++和EasyX图形库编写一个简单的打砖块游戏(上)

  现在框架已经确定好啦,就让我们在其中添砖加瓦吧。要知道,在这个打砖块的游戏中,无非只有砖块,木板,小球这三种游戏元素。那么在编程时,显然我们应该将他们定义成三种不同的类。不过在这之前,我们得先了解几个用于作图的函数,他们分别是:

  1. setfillcolor(COLORREF color);
    设置图形颜色,参数可以用RBG设定,也可以直接写颜色,如RED, BLACK等。
  2. fillrectangle(int left, int top, int right, int bottom);
    画一个带边框的矩形,其四个参数分别指两个顶点的坐标。
    如图,当我们确定A, D两点的坐标后,这个矩形的位置是不是就可以确定了呢。
    用C++和EasyX图形库编写一个简单的打砖块游戏(上)

  3. solidrectangle(int left, int top, int right, int bottom);
    画一个不带边框的矩形,其参数含义与上一个函数相同。

  4. solidcircle(int x, int y, int radius);
    画一个圆形,参数x,y,radius分别表示圆心的横坐标,纵坐标和圆的半径

  ok,简单了解就行。下面让我们从最简单的写起,首先来定义砖块的类,想一想这其中应该包含哪些成员变量和成员函数。
  我用一个二维数组存储砖块的位置,我们可以暂定砖块是5排10列,那么砖块总数,以及每个砖块的长和宽都可以计算出来了。另外,除了初始化函数外,我们还需要一个成员函数把所有的砖块都画出来,这只需在对数组循环遍历时调用上述作图函数即可。不过我们需要知道的是,对于第i行第j个(列)砖块,它的坐标又是多少呢。具体可见下图,方便理解。
  用C++和EasyX图形库编写一个简单的打砖块游戏(上)
  易知,当得出A点坐标后,B点的横坐标就是在A点横坐标上加上矩形的长度,B点的纵坐标就是在A点纵坐标上加上矩形的宽度了。现给出砖块类的定义如下。

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);
    }
};

  需要说明的是,函数setlinecolor(COLORREF color),它的作用是设置图形边框颜色,如果我们试着把它在成员函数drawAllbricks()中的调用注释掉的话,它将默认砖块的边框为白色,但是我们的背景是黑色,结果运行后一点儿也不美观,所以我们把边框颜色设置成背景色黑色。不过需要注意的是,每个砖块的边框的长度是1,这在以后处理细节时需要用到,现在先不用理会。

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

  
  在定义完砖块类后,我们紧接着来定义木板类。对于木板而言,我们只需要考虑它的长度和宽度,以及它得根据玩家的控制来左右移动。而实现运动的原理,就是不停地在新位置画木板,同时用背景色覆盖掉原先位置的木板,这样木板看起来就像是在运动了,小球运动也是同理。另外,关于类中的成员变量x,y,即木板的坐标,并非指木板中心点的坐标,而是指这个矩形木板左上角的顶点的坐标,所以对于类中木板初始位置的计算,以及边界限制的计算,都应该是很好理解的。

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()
    {
        //键盘的每个按键都对应一个确定的键值,如方向键 → 对应77, ← 对应75
        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);
    }
};

  现在,我们已经完成了砖块类和木板类的定义了,是不是想快点检验成果呢。我们在主函数前编写自定义函数,用来实现整个游戏的逻辑控制,并在主函数中调用。代码如下:

#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);
    }
};

void Gaming()
{
    Bricks brick;           //声明砖块对象
    brick.drawAllbricks();  //调用成员函数,画出所有的砖块

    Board board;            //声明木板对象
    setfillcolor(BLUE);     //设置木板颜色
    solidrectangle(board.x, board.y, board.x + board.length, board.y + board.wide);                        //画出木板

    while (1)
    {
        if (_kbhit())       //用该函数判断你是否按下某个键,按下返回1,否则返回0
        {
            board.Move();   //按下键后,调用木板类的成员函数,控制木板的移动
        }
    }
}

int main()
{
    initgraph(WINDOW_WIDE, WINDOW_HEIGHT);  //初始化窗口
    Gaming();
    _getch();
    return 0;
}

  如果一切顺利的话,运行后你将得到如下画面,同时木板可以在你的控制下左右移动。
  用C++和EasyX图形库编写一个简单的打砖块游戏(上)

  至此,我们的教程已经完成了将近一半,剩下的只有游戏中最关键的部分—小球了。因为小球类是代码中相对难写的部分,所以这部分我将放在下一篇里详细介绍。
  hh,也不知道在这一篇里我讲的怎么样,说的好不好。呀,不管怎样,希望大家都能从中有所得有所学吧。
  至于下篇,乘着国庆放假,我会尽快完成的!(认真脸…)回见啦。