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

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

程序员文章站 2022-04-14 18:18:05
/***************************项目 2048**********************c语言编写 图形库制作时间:2019.04.03 准备工具: vs2013 图形库 ico素材(作为exe的图标) 背景图(jpg格式)知识点: 循环 数组 函数 随机数 项目步骤分析: ......

 /***************************项目 2048**********************
c语言编写 图形库制作
时间:2019.04.03

准备工具: vs2013 图形库 ico素材(作为exe的图标) 背景图(jpg格式)
知识点: 循环 数组 函数 随机数

项目步骤分析:
2048 通过方向键 wasd控制方向合并相同数字直到生成2048 游戏结束
1、4x4的棋盘 存放数字 ---->数组 游戏操作 ---->键盘操作 界面 ---->需要操作结果


2、步骤
a、准备数组 生成两个隋杰的位置和随机的数字(2或4) //初始化操作
b、等待用户输入 根据上下左右处理数组
//添加一个判断输赢e
c、生成新的随机位置 和新的数字(2或4)
d、打印界面 当前输出结果 等待下一轮输入
e、输赢条件 输-->数组满,不能移动 赢-->出现2048,游戏就赢了


3、拆分函数 如果同一个功能或者相似的功能可以写成一个函数,减少代码量和难点
a 初始化

函数声明:

void init(int map[][4]); 

函数定义:

void init(int map[][4])
{

rand();
int x, y;
for (int i = 0; i < 2;)
{
x = rand() % 4; 
y = rand() % 4;
if (map[x][y] == 0) 
{
map[x][y] = rand()%2*2+2; 
}
}
}

在主函数中测试效果:

int main()
{
int map[4][4];
init(map); 
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("%d\t", map[i][j]);
}
printf("%\n");
}

getchar();
return 0;
}

效果如图所示:

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

b 等待用户输入操作 随机位置

用switch进行键盘消息判断

各方向键的代码比对如下:

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏) C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏) C++学习(三十九)(C语言部分)之 游戏项目(2048游戏) 

 

也可以用枚举法定义方向键并对其进行消息的判断

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

 

对比如下:

 C++学习(三十九)(C语言部分)之 游戏项目(2048游戏) C++学习(三十九)(C语言部分)之 游戏项目(2048游戏) 

 C++学习(三十九)(C语言部分)之 游戏项目(2048游戏) C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

 

c 判断输赢


d 打印结果 显示地图

打印地图的函数:

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

 

暂时测试结果如下:

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

 


目的:
复习 总结 综合运用
***************************项目 2048**********************/

 

测试代码笔记如下:

  1 //**************************头文件部分*********************
  2 //头文件 宏定义 类型定义 全局变量
  3 
  4 //头文件
  5 #include<stdio.h>
  6 #include<memory.h>  //memset的头文件 或者string.h
  7 #include<stdlib.h>  //srand函数  rand函数
  8 #include<time.h>  //time函数
  9 #include<conio.h>  //getch函数
 10 #include<graphics.h>  //图形库
 11 //#define color1 rgb(238,106,80)
 12 //#define color2 rgb(238,169,184)
 13 //#define color3 rgb(131,139,131)
 14 //#define color4 rgb(193,205,205)
 15 
 16 //类型定义 枚举
 17 enum dir
 18 {
 19     up = 72, down = 80, left = 75, right = 77
 20 };  //定义方向键
 21 
 22 image img;//存放图片变量
 23 
 24 //**************************函数声明***********************
 25 //写个函数的声明
 26 void init(int map[][4]);  //用函数给数组赋值初始化
 27 
 28 void play(int map[][4]);  //处理用户输入
 29 
 30 void drawmap(int map[][4]);  //打印 画图
 31 
 32 void newnum(int map[][4]);  //随机一个新元素
 33 
 34 int isgameover(int map[][4]);//判断游戏是否结束的一个函数
 35 
 36 //**************************主函数*************************
 37 //main函数
 38 int main()
 39 {
 40     int map[4][4];  //准备数组 大小4x4的地图
 41     init(map);  //传参(实参) 传的是数组名
 42     
 43     while (1)  //死循环
 44     {
 45         drawmap(map);
 46         play(map);
 47         //system("cls");  //清屏函数 用于控制台
 48         //newnum(map);
 49         if (isgameover(map) != 0)  break;//结束循环
 50     }
 51 
 52     if (isgameover(map) == 1)
 53     {
 54         //赢得游戏
 55         drawmap(map);
 56         //printf("赢得游戏\n");
 57         messagebox(gethwnd(), l"ok", l"win", mb_ok);
 58         //第一个 是窗口句柄  表示显示在这个窗口前面   可以写null 或者0
 59         //第二个参数 是文本框内容
 60         //第三次参数 窗口标题
 61         //最后一个参数是按钮形式
 62         
 63     }
 64     else
 65     {
 66         //输了游戏
 67         drawmap(map);
 68         //printf("输了游戏\n");
 69         messagebox(gethwnd(), l"oops", l"lose", mb_ok);
 70     }
 71 
 72     //getchar();
 73     closegraph();//关闭窗口
 74     return 0;
 75 }
 76 
 77 //**************************函数定义************************
 78 //上述函数的定义放在这里
 79 
 80 //给数组赋值 初始化
 81 void init(int map[][4])  //int (*map[4])(形参)  是数组指针 两种形式都可以
 82 {
 83     //给数组赋值 第一种方式用循环
 84     //for (int i = 0; i < 4; ++i)  //数组用 下标进行循环
 85     //{
 86     //    for (int j = 0; j < 4; ++j)
 87     //    {
 88     //        map[i][j] = 0;  //刚开始全部赋值为0
 89     //    }
 90     //}
 91 
 92     //第二种方式用函数 memset 初始化一块内存  头文件是stdlib,h
 93     memset(map, 0, sizeof(int)* 4 * 4); //三个参数 内存首地址 初值 字节大小
 94     //随机两个2和4  null用于指针 随机数 借用两个函数srand  rand --->头文件stlib.h  还需要一个函数 time(时间函数)--->头文件time.h
 95     srand((unsigned)time(null));  //设置随机数种子  不要写在循环里面 设置一次就够了
 96     //得到某个范围内的随机数 用求余控制范围  0-->100之间 int x=rand()%101; 66-->100之间 -->66+(0-->43)  rand()%35+66
 97     //得到随机位置
 98     int x, y;
 99     for (int i = 0; i < 2;)
100     {
101         x = rand() % 4;  //下标3至3  所以对4求余
102         y = rand() % 4;
103         if (map[x][y] == 0)  //这个位置没有元素
104         {
105             map[x][y] = rand()%2*2+2; //2或4 2=1*2   4=2*2
106             i++;  //赋值之后才算一次
107         }
108         //++i放上面 只能确保循环两次 不能确保赋值两次 所以放下面
109     }
110 }
111 
112 //处理用户输入
113 void play(int map[][4])
114 {
115     //方式 键盘操作
116     //getch  读取键盘中的一个字符 conio.h
117     //kbhit  conio.h  检测当前是否有键盘消息
118     //dir di;  //枚举变量
119     switch (getch())  //判断键盘消息
120     {
121     case 'w':
122     case 'w'://往上
123         for (int j = 0; j < 4; ++j)  //四列
124         {
125             for (int i = 0; i < 3; ++i)  //判断前三个能否和后面的合并
126             {
127                 if (map[i][j] == 0) //判断是否为0
128                 {
129                     //到后面找一个不是0的元素 换过来
130                     int k = i + 1;
131                     for (; k < 4; ++k)
132                     {
133                         if (map[k][j] != 0)
134                         {
135                             map[i][j] = map[k][j];
136                             map[k][j] = 0;
137                             break;
138                         }
139                     }
140                     if (k == 4)break;  //表明这一行全是0
141                 }
142                 //判断map[i][j]和后面的元素是否可以合并
143                 for (int k = i + 1; k < 4; ++k)  //判断后面的元素
144                 {
145                     if (map[k][j] == 0) continue;
146                     else if (map[i][j] == map[k][j])
147                     {
148                         //相同 合并
149                         map[i][j] *= 2;  //合并
150                         map[k][j] = 0;
151                         break;
152                     }
153                     else break;  //不相等 往后找 退出
154                 }
155             }
156         }
157         newnum(map);
158         break;
159     case 's':
160     case 's'://往下
161         for (int j = 0; j < 4; ++j)//四列
162         {
163             //每一行进行合并
164             for (int i = 3; i >0; --i)//判断前三个能否和后面的进行合并
165             {
166                 if (map[i][j] == 0)//判断map[i][j]是否为0
167                 {
168                     //到后面找一个不是0的元素 换到这个位置
169                     int k = i - 1;
170                     for (; k >= 0; --k)
171                     {
172                         if (map[k][j] != 0)
173                         {
174                             map[i][j] = map[k][j];
175                             map[k][j] = 0;
176                             break;
177                         }
178                     }
179                     if (k == 0)break;//表明这一行全是0  直接找下一行
180                 }
181                 //判断map[i][j] 和后面的元素能否合并
182                 for (int k = i - 1; k >= 0; --k)//判断后面的几个元素
183                 {
184                     if (map[k][j] == 0) continue;
185                     else if (map[i][j] == map[k][j])
186                     {
187                         map[i][j] *= 2;//合并
188                         map[k][j] = 0;
189                         break;
190                     }
191                     else  break;//不相等 往后找 退出
192                 }
193             }
194         }
195         newnum(map);
196         break;
197     case 'a':  
198     case 'a'://往左
199         for (int i = 0; i < 4; ++i)  //四行
200         {
201             //每一行进行合并 从左往右 1、判断第一个元素是不是0,如果是0,就到右边找到第一个不是0的元素,放到为0的位置上 不是0,就进行下一步,(没有找到 说明全是0,那么就直接下一行)
202             //2、找到剩下的位置中不是0的元素 如果和这个位置的相同的话合并到下一个位置
203             for (int j = 0; j < 3; ++j)  //判断前三个能否和后面的合并
204             {
205                 if (map[i][j] == 0) //判断是否为0
206                 {
207                     //到后面找一个不是0的元素 换过来
208                     int k = j + 1;
209                     for (; k < 4; ++k)
210                     {
211                         if (map[i][k] != 0)
212                         {
213                             map[i][j] = map[i][k];
214                             map[i][k] = 0;
215                             break;
216                         }
217                     }
218                     if (k == 4)break;  //表明这一行全是0
219                 }
220                 //判断map[i][j]和后面的元素是否可以合并
221                 for (int k = j + 1; k < 4; ++k)  //判断后面的元素
222                 {
223                     if (map[i][k] == 0) continue;  
224                     else if (map[i][j] == map[i][k])
225                     {
226                         //相同 合并
227                         map[i][j] *= 2;  //合并
228                         map[i][k] = 0;
229                         break;
230                     }
231                     else break;  //不相等 往后找 退出
232                 }
233             }
234         }
235         newnum(map);
236         break;
237     case 'd':  
238     case 'd'://往右
239         for (int i = 0; i < 4; ++i) //四行
240         {
241             for (int j = 3; j >0; --j)  //判断前三个能否和后面的合并
242             {
243                 if (map[i][j] == 0) //判断是否为0
244                 {
245                     //到后面找一个不是0的元素 换过来
246                     int k = j - 1;
247                     for (; k >=0; --k)
248                     {
249                         if (map[i][k] != 0)
250                         {
251                             map[i][j] = map[i][k];
252                             map[i][k] = 0;
253                             break;
254                         }
255                     }
256                     if (k == -1)break;  //表明这一行全是0
257                 }
258                 //判断map[i][j]和后面的元素是否可以合并
259                 for (int k = j - 1; k >=0; --k)  //判断后面的元素
260                 {
261                     if (map[i][k] == 0) continue;
262                     else if (map[i][j] == map[i][k])
263                     {
264                         //相同 合并
265                         map[i][j] *= 2;  //合并
266                         map[i][k] = 0;
267                         break;
268                     }
269                     else break;  //不相等 往后找 退出
270                 }
271             }
272         }
273         newnum(map);
274         break;
275     case 224:  //表示使用方向键  方向键是组合件 用getch视为两个部分
276         switch (getch())
277         {
278         case up:
279             for (int j = 0; j < 4; ++j)//四列
280             {
281                 //每一行进行合并
282                 for (int i = 0; i < 3; ++i)//判断前三个能否和后面的进行合并
283                 {
284                     if (map[i][j] == 0)//判断map[i][j]是否为0
285                     {
286                         //到后面找一个不是0的元素 换到这个位置
287                         int k = i + 1;
288                         for (; k<4; ++k)
289                         {
290                             if (map[k][j] != 0)
291                             {
292                                 map[i][j] = map[k][j];
293                                 map[k][j] = 0;
294                                 break;
295                             }
296                         }
297                         if (k == 4)break;//表明这一行全是0  直接找下一行
298                     }
299                     //判断map[i][j] 和后面的元素能否合并
300                     for (int k = i + 1; k < 4; ++k)//判断后面的几个元素
301                     {
302                         if (map[k][j] == 0) continue;
303                         else if (map[i][j] == map[k][j])
304                         {
305                             map[i][j] *= 2;//合并
306                             map[k][j] = 0;
307                             break;
308                         }
309                         else  break;//不相等 往后找 退出
310                     }
311                 }
312             }
313             newnum(map);
314             break;
315         case down:
316             for (int j = 0; j < 4; ++j)//四列
317             {
318                 //每一行进行合并
319                 for (int i = 3; i >0; --i)//判断前三个能否和后面的进行合并
320                 {
321                     if (map[i][j] == 0)//判断map[i][j]是否为0
322                     {
323                         //到后面找一个不是0的元素 换到这个位置
324                         int k = i - 1;
325                         for (; k >= 0; --k)
326                         {
327                             if (map[k][j] != 0)
328                             {
329                                 map[i][j] = map[k][j];
330                                 map[k][j] = 0;
331                                 break;
332                             }
333                         }
334                         if (k == 0)break;//表明这一行全是0  直接找下一行
335                     }
336                     //判断map[i][j] 和后面的元素能否合并
337                     for (int k = i - 1; k >= 0; --k)//判断后面的几个元素
338                     {
339                         if (map[k][j] == 0) continue;
340                         else if (map[i][j] == map[k][j])
341                         {
342                             map[i][j] *= 2;//合并
343                             map[k][j] = 0;
344                             break;
345                         }
346                         else  break;//不相等 往后找 退出
347                     }
348                 }
349             }
350             newnum(map);
351             break;
352         case left:
353             for (int i = 0; i < 4; ++i)//四行
354             {
355                 //每一行进行合并
356                 for (int j = 0; j < 3; ++j)//判断前三个能否和后面的进行合并
357                 {
358                     if (map[i][j] == 0)//判断map[i][j]是否为0
359                     {
360                         //到后面找一个不是0的元素 换到这个位置
361                         int k = j + 1;
362                         for (; k<4; ++k)
363                         {
364                             if (map[i][k] != 0)
365                             {
366                                 map[i][j] = map[i][k];
367                                 map[i][k] = 0;
368                                 break;
369                             }
370                         }
371                         if (k == 4)break;//表明这一行全是0  直接找下一行
372                     }
373                     //判断map[i][j] 和后面的元素能否合并
374                     for (int k = j + 1; k < 4; ++k)//判断后面的几个元素
375                     {
376                         if (map[i][k] == 0) continue;
377                         else if (map[i][j] == map[i][k])
378                         {
379                             map[i][j] *= 2;//合并
380                             map[i][k] = 0;
381                             break;
382                         }
383                         else  break;//不相等 往后找 退出
384                     }
385                 }
386             }
387             newnum(map);
388             break;
389         case right:
390             for (int i = 0; i < 4; ++i)//四行
391             {
392                 //每一行进行合并
393                 for (int j = 3; j >0; --j)//判断前三个能否和后面的进行合并
394                 {
395                     if (map[i][j] == 0)//判断map[i][j]是否为0
396                     {
397                         //到后面找一个不是0的元素 换到这个位置
398                         int k = j - 1;
399                         for (; k >= 0; --k)
400                         {
401                             if (map[i][k] != 0)
402                             {
403                                 map[i][j] = map[i][k];
404                                 map[i][k] = 0;
405                                 break;
406                             }
407                         }
408                         if (k == -1)break;//表明这一行全是0  直接找下一行
409                     }
410                     //判断map[i][j] 和后面的元素能否合并
411                     for (int k = j - 1; k >= 0; --k)//判断后面的几个元素
412                     {
413                         if (map[i][k] == 0) continue;
414                         else if (map[i][j] == map[i][k])
415                         {
416                             map[i][j] *= 2;//合并
417                             map[i][k] = 0;
418                             break;
419                         }
420                         else  break;//不相等 往后找 退出
421                     }
422                 }
423             }
424             newnum(map);
425             break;
426         default:
427             break;
428         }
429         break;
430     default:
431         break;
432     }
433 
434 }
435 
436 //打印  贴图
437 void drawmap(int map[][4])
438 {
439     /*for (int i = 0; i < 4; ++i)
440     {
441         for (int j = 0; j < 4; ++j)
442         {
443             printf("%d\t", map[i][j]);
444         }
445         printf("\n");
446     }
447     printf("\n\n");*/
448 
449     //cleardevice();//图形库清除屏幕内容  //如果加上 有闪屏的问题
450     putimage(0, 0, &img);//贴背景图
451     char arr[10];//准备字符串
452     for (int i = 0; i < 4; ++i)
453     {
454         for (int j = 0; j < 4; ++j)
455         {
456             //加数字进来
457             //outtextxy根据坐标输出字符串
458             //itoa 将int转换成字符串
459             /*if (map[i][j] != 0)
460             {
461             sprintf(arr,"%d",map[i][j]);
462             outtextxy(160 * j+20, 160 * i+20, arr);
463             }*/
464 
465             //有素材  switch 根据不同数字进行贴图
466             //通过数字确定背景
467             //238 106 80
468             //238 169 184
469             //131 139 131
470             //193 205 205
471 
472             /*switch (map[i][j])
473             {
474             case 0:
475             case 32:
476             setfillcolor(color1);
477             fillrectangle(160 * j, 160 * i, 160 * j + 160, 160 * i + 160);
478             break;
479             case 2:
480             case 64:
481             setfillcolor(color2);
482             fillrectangle(160 * j, 160 * i, 160 * j + 160, 160 * i + 160);
483             break;
484             case 4:
485             case 128:
486             setfillcolor(color3);
487             fillrectangle(160 * j, 160 * i, 160 * j + 160, 160 * i + 160);
488             break;
489             case 8:
490             case 256:
491             setfillcolor(color4);
492             fillrectangle(160 * j, 160 * i, 160 * j + 160, 160 * i + 160);
493             break;
494             }*/
495 
496             sprintf(arr, "%d", map[i][j]);
497             outtextxy(160 * j + 20, 160 * i + 20, arr[10]);
498             //根据数字 确定不同的背景图  然后在背景图上 写数字
499             //if ()
500             //2^1  2^2  2^3 2^4
501             //2^5  2^6
502 
503             //debug 调试版本  比较慢
504             //release 发行版本   -->主要发给别人用的
505         }
506     }
507 }
508 
509 //随机一个新元素
510 void newnum(int map[][4])
511 {
512     //判断是不是满
513     int empty = 0;
514     for (int i = 0; i < 4; ++i)
515     {
516         for (int j = 0; j < 4; ++j)
517         {
518             if (map[i][j] == 0) empty = 1;
519         }
520         if (empty == 1) break;//如果找到这个空的位置  不需要继续循环
521     }
522     if (empty == 0) return;
523 
524     int x, y;
525     do
526     {
527         x = rand() % 4;
528         y = rand() % 4;
529     } while (map[x][y] != 0);
530     map[x][y] = rand() % 2 * 2 + 2;  //随机2和4
531     //如果地图满的话 我们不能随机元素 所以最后 加上一个判断地图满的函数
532 }
533 
534 //判断游戏是否结束
535 int isgameover(int map[][4])
536 {
537     //赢  返回1    输 -1  还没赢 还没输 返回0
538     //游戏输赢条件
539     //出现2048  游戏赢
540     //如果游戏不能走动  游戏输掉
541     int empty = 0;//如果判断的时候 map[i][j]==0  empty置为1  
542     //如果有相邻元素 并且相同的话  也将empty置为1
543     for (int i = 0; i < 4; ++i)
544     {
545         for (int j = 0; j < 4; ++j)
546         {
547             if (map[i][j] >= 2048)//赢的条件
548             {
549                 //赢得游戏
550                 return 1;
551             }
552         }
553     }
554     //条件1  数字全满 并且 相邻没有同样的数字
555     for (int i = 0; i < 4; ++i)
556     {
557         for (int j = 0; j < 4; ++j)
558         {
559             if (map[i][j] == 0)  empty = 1;
560             if (i + 1<4 && map[i][j] == map[i + 1][j]) empty = 1;
561             if (j + 1<4 && map[i][j] == map[i][j + 1]) empty = 1;
562         }
563     }
564     if (empty == 1)
565     {
566         //游戏还没有结束
567         return 0;
568     }
569     else
570     {
571         //游戏结束 //输
572         return -1;
573     }
574 }

结果展示:

C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

 

注:代码部分仅供学习参考,完全复制下来不一定能够实现

 

 

2019-04-03  12:04:42