图形学 推箱子

用TC搭建一个推箱子游戏(计算机图形学练习)

一、对于图形游戏的分析

 对游戏图形进行简化,该游戏主要是有正方形的方块构成,图形主要有,我们分别用不同颜色的方块来表示这些元素

1.       背景       (白色)  WHITH  15

2.                   (浅灰)       LIGHTGRAY 7

3.                   (蓝色)       BLUE 1

4.       位置        (红色)       RED 4

5.       没有在位置上的箱子(绿色) GREEN 2

6.       在位置上的箱子(黄色)YELLOW 14

7.       在位置上的人 (淡蓝) LIGHTBLUE

  图片

由于简化后的图形所以绘图程序只需要一个函数

void FillRect(int x0,int y0,int x1,int y1,int color)

{

       int x,y;

       for(x=x0;x<x1;x+=2)

       {

              for(y=y0;y<y1;y+=2)

              {

                     putpixel(x,y,color);

              }

       }

}

二、对游戏逻辑进行分析

1.游戏过程的描述

       Step1:玩家打开程序进入游戏

Step2:玩家按’W,A,S,D’键控制人物推动方块,如果按下’Q’键退出游戏

Step3:如果没有将所有的方块移动到位置上则继续Step2

Step4:游戏胜利显示胜利信息

Step5:退出游戏

2.流程图

3.游戏中的数据存放在一个二维矩阵中(8*8

#define MAXSIZE 8

int matrix[MAXSIZE][ MAXSIZE];

       由于箱子和位置有重复的时候(箱子在位置上),所以我们用int的一个二进制位来代表该位置上是否有元素。

这里我们约定:

0x0000          该位置上什么也没有(只是背景)

0x0001           该位置有是墙

0x0002         该位置有是人

0x0004       该位置有箱子

0x0008       该位置有位置

先初始化这个矩阵

 

void initMatrix(int level)

{

       int i , j;

       int map[1][MAXSIZE][MAXSIZE]={

              {

                     {0,1,1,1,1,1},

                     {0,1,0,2,0,1,1,1},

                     {1,1,0,1,4,0,0,1},

                     {1,0,12,8,0,8,0,1},

                     {1,0,0,4,4,0,1,1},

                     {1,1,1,0,1,8,1},

                     {0,0,1,0,0,0,1},

                     {0,0,1,1,1,1,1},

              }

       };

       for(i=0;i<MAXSIZE;i++)

       {

              for(j=0;j<MAXSIZE;j++)

              {

                     matrix[i][j] = map[level][j][i];

              }

       }

}

所以这里先确定一个draw方法来绘制这个矩阵(界面)

先定义一个格子的大小

#define BOXSIZE 40

void draw()

{

       int i , j;

       for (i = 0 ; i < MAXSIZE ; i ++)

       {

              for(j = 0 ;j <MAXSIZE;j++)

              {

                    

                     int color = BLACK;

                     switch(matrix[i][j])

                     {

                            case 0 : /*背景用白色*/       

                                  color  = 15;break;

                            case 1:/*墙用灰色*/

                                   color = LIGHTGRAY;break;

                            case 2:/*人用蓝色*/

                                   color = BLUE;break;

                            case 4:/*箱子用绿色*/

                                  color = GREEN;break;

                            case 8:/*位置用红色*/

                                  color = RED;break;

                            case 12:/*在位置上的箱子用黄色*/

                                  color = YELLOW;break;

                           case 10:/*人在位置上淡蓝*/

                               color = LIGHTBLUE;break;

 

                     }

                     /*确定在屏幕上的位置并绘画出来*/

                     FillRect(i*BOXSIZE,j*BOXSIZE,(i+1)*BOXSIZE,(j+1)*BOXSIZE,color);

 

              }

       }

}对于接受的输入我们用一个cmd变量来存储

char cmd;

在游戏中能移动的有人和箱子我们统一一个函数来移动,移动箱子和人其实就是改变矩阵中的数据。

这里我们先看看有情况:

1.       人可以推动一个箱子(也就是所人所推动的箱子的前面不能有箱子);

2.       人不能穿墙(人的前面是墙,则人不能移动)

3.       箱子不能穿墙(箱子前面是墙,则箱子不能移动);

4.       箱子不能推动箱子

/*移动 dir 位方向 w’为上 a 为左 s’为下 d’为右 i,j 确定要移动的位置

返回是否移动成功

*/

int  move(char dir,int i,int j)

{

       int ni = i ,nj = j;

       /*计算要移动到的位置*/

       switch(dir)

       {

              case 'w':   nj--;break;

              case 'a':   ni--;break;

              case 's':   nj++;break;

              case 'd':   ni++;break;

       }

      

       /*如果前面是墙 则人和箱子都不能移动*/

       if((matrix[ni][nj] & 1) == 1)

       {

              return 0;

       }

      

              /*当前要移动的是人*/

       if((matrix[i][j] & 2) == 2)

       {

              int flag = 1;

              /*如果前面是箱子*/

              if((matrix[ni][nj] & 4) == 4){

                            /*移动箱子 看是否成功*/

                     flag = move(dir,ni,nj);

                    

              }

              if(flag)

              {

             

                   /*如果成功则一个人*/

                     /*将前面的位置标志加上人*/

                     matrix[ni][nj] = matrix[ni][nj] | 2;

                     /*将本地的位置去除人*/

                     matrix[i][j] = matrix[i][j] & ~2;

                     return 1;/*移动成功*/

                    

              }

             

       }

       /*当前要移动的是箱子*/

       if((matrix[i][j] & 4)==4)

       {

              /*如果前面是箱子 不能移动*/

              if((matrix[ni][nj] & 4) == 4)return 0;

              /*将前面的位置标志加上箱子*/

              matrix[ni][nj] = matrix[ni][nj] | 4;

              /*将本地的位置去除箱子*/

              matrix[i][j] = matrix[i][j] & ~4;

              return 1;/*移动成功*/

       }

 

}

然后我们还要检查是否成功

如果matrix矩阵中没有一个是单独的箱子那么就成功了

int check()

{

       int i ,j;

       for(i=0;i<MAXSIZE;i++)

       {

              for(j=0;j<MAXSIZE;j++)

              {

                     /*如果有单独的箱子 没有成功*/

                      if(matrix[i][j] == 4)return 0;

              }

       }

/*都没有 就成功了*/

return 1;

}

在写这个函数写一个移动人的函数

void moveHero(char dir)

{

 

       int i,j;

       int x,y;

       /*先要找到人的位置*/

       for(i=0;i<MAXSIZE;i++)

       {

              for(j=0;j<MAXSIZE;j++)

              {

                     if((matrix[i][j] & 2) == 2){

                     x = i ;

                     y = j ;

                     break;

                     }

              }

       }

      

       move(dir,x,y);

}

这里我们来处理游戏逻辑(主函数中的代码)

int main()

{

       int graphdirver = DETECT;

       int graphmode = 0;

       char cmd;

       initgraph(&graphdirver,&graphmode,"C:\\JMSOFT\\CYuYan\\tc3\\BGI");

       initMatrix(0);

       cleardevice();

      

       while(1){

              draw();
 
              cmd = getch();

              switch(cmd)

              {

                     case 'q':exit(0);break;

                     case 'w':

                     case 'a':

                     case 's':

                     case 'd':

                            moveHero(cmd);

                            /*检查是否成功*/

                            if(check())

                            {

                             printf("胜利");

                            }

                            break;

              }

                    

       }

       closegraph();  

}

 

 

三、还没有实现的功能 ,以及缺陷

       1.悔步的功能,该功能可以用一个栈来存储移动步骤,然后通过这个历史栈来撤销操作。

       2.关卡功能 ,在initMatrix函数中已经预留了关卡功能,只要在map中添加关卡地图,然后再修改下 游戏的逻辑便可以实现。

3.缺陷。由于屏幕的刷新产生的 描述现象

四.题目 以供大家交流学习
        1)。请组装以上代码 ,在tc2012环境中运行 

2)。替换元素

原方案是:

不同颜色的方块来表示这些元素

1背景  (白色)  WHITH  15

2        (浅灰)       LIGHTGRAY 7

3        (蓝色)       BLUE 1

4位置            (红色)       RED 4

5没有在位置上的箱子(绿色) GREEN 2

6在位置上的箱子(黄色)YELLOW 14

7在位置上的人 (淡蓝) LIGHTBLUE

现在请你:

修改FillRect函数,分别用 矩形代表墙 圆形代表人 棱形代表位置 三角形代表箱子来表示这些元素,以降低putpixel的调用次数

3)。实现关卡功能

       提示:只需在initMatrix函数中添加map地图数据

       然后当游戏胜利后调用initMatrix(级别)就可以了,

       不过你可以实现一个选择关卡的功能

4)。实现悔步功能

       提示:用栈来存储 这涉及数据结构的知识

       由于每次操作都可以使人和箱子移动则 这个栈里面的数据结构可以定义为

      

#define MAXHISTORY 100

typedef struct operate

{

       char dir;/*方向*/

       int hero;/*人是否移动过*/

       int box;/*箱子是否移动过*/

}OPERATE;

typedef struct stack

{

       int top;

       OPERATE[MAXHISTORY] data;

}STACK;

 

然后游戏逻辑和栈的操作就该你写了(我的思想也不一定对,没有实现过)

 

附录:

以下是这个库所支持的函数列表。恩,仅仅是列表。
void initgraph(int Width, int Height); //
初始化图形环境
void initgraph(int Width, int Height, int Flag);
void closegraph(); //
关闭图形环境
void cleardevice(); //
清屏
COLORREF getcolor(); //
获取当前绘图前景色
void setcolor(COLORREF color); //
设置当前绘图前景色
COLORREF getbkcolor(); //
获取当前绘图背景色
void setbkcolor(COLORREF color); //
设置当前绘图背景色
void getviewsettings(struct viewporttype *viewport); //
获取视图信息
void setviewport(int left, int top, int right, int bottom, int clip); //
设置视图
void clearviewport(); //
清空视图
void getlinesettings(struct linesettingstype *lineinfo); //
获取当前线形
void setlinestyle(int linestyle, unsigned int upattern, int thickness); //
设置当前线形
void getfillsettings(struct fillsettingstype *fillinfo); //
获取填充类型
void setfillstyle(int pattern, int color); //
设置填充类型
void getfillpattern(char *pattern); //
获取自定义填充类型
void setfillpattern(const char *upattern, int color); //
设置自定义填充类型
void getaspectratio(int *xasp, int *yasp); //
获取当前缩放因子
void setaspectratio(int xasp, int yasp); //
设置当前缩放因子
void setwritemode(int mode); //
设置绘图位操作模式
void graphdefaults(); //
重置所有绘图设置为默认值
COLORREF getpixel(int x, int y); //
获取点的颜色
void putpixel(int x, int y, COLORREF color); //
画点
void moveto(int x, int y); //
移动当前点(绝对坐标)
void moverel(int dx, int dy); //
移动当前点(相对坐标)
void line(int x1, int y1, int x2, int y2); //
画线
void linerel(int dx, int dy); //
画线(至相对坐标)
void lineto(int x, int y); //
画线(至绝对坐标)
void rectangle(int left, int top, int right, int bottom); //
画矩形
void getarccoords(struct arccoordstype *arccoords); //
获取圆弧坐标信息
void arc(int x, int y, int stangle, int endangle, int radius); //
画圆弧
void circle(int x, int y, int radius); //
画圆
void pieslice(int x, int y, int stangle, int endangle, int radius); //
画填充圆扇形
void ellipse(int x, int y, int stangle, int endangle, int xradius, int yradius);//
画椭圆弧线
void fillellipse(int x, int y, int xradius, int yradius); //
画填充椭圆
void sector(int x, int y, int stangle, int endangle, int xradius, int yradius); //
画填充椭圆扇形
void bar(int left, int top, int right, int bottom); //
画无边框填充矩形
void bar3d(int left, int top, int right, int bottom, int depth, int topflag); //
画有边框三维填充矩形
void drawpoly(int numpoints, const int *polypoints); //
画多边形
void fillpoly(int numpoints, const int *polypoints); //
画填充的多边形
void floodfill(int x, int y, int border); //
填充区域
void outtext(LPCTSTR textstring); //
在当前位置输出文字
void outtextxy(int x, int y, LPCTSTR textstring); //
在指定位置输出文字
int textwidth(LPCTSTR textstring); //
获取字符串占用的像素宽
int textheight(LPCTSTR textstring); //
获取字符串占用的像素高
void SetFont(int nHeight,int nWidth,int nEscapement,int nOrientation,int fnWeight,BYTE fdwItalic,BYTE fdwUnderline,BYTE fdwStrikeOut,LPCTSTR lpszFace); //
设置当前字体样式
void SetFont(const LOGFONT *font); //
设置当前字体样式
void GetFont(LOGFONT *font); //
获取当前字体样式
void getimage(int left, int top, int right, int bottom, IMAGE *imgdst); //
从屏幕获取图像
void getimage(const char *imagefile, IMAGE *imgdst); //
BMP 文件获取图像
void getimage(const IMAGE *imgsrc, int left, int top, int right, int bottom, IMAGE *imgdst); //
IMAGE 对象获取图像
void putimage(int left, int top, IMAGE *img, int op); //
绘制图像
int getmaxcolor(); //
获取最大颜色值
int getmaxx(); //
获取最大 x 坐标
int getmaxy(); //
获取最大 y 坐标
int getx(); //
获取当前 x 坐标
int gety(); //
获取当前 y 坐标
int GetVer(); //
获取当前版本

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值