🚀write in front🚀
🔎大家好,我是翻斗花园牛爷爷★。希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
🆔本文由 翻斗花园牛爷爷★ 原创 CSDN首发🐒 如需转载还请通知⚠
📝个人主页:翻斗花园牛爷爷★—CSDN博客
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏:翻斗花园牛爷爷★的系列专栏——CSDN博客
✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本
目录
程序打包
很多小伙伴说了,游戏写好了,但是不知道怎么发给别人。因此在学习两个游戏前,先带大家了解一下如何将写好的程序打包成exe文件;
工具:VS2022
1.首先打开VS2022,打开拓展
2.选择管理拓展,再搜索install;下载箭头所指的包。
3.然后关闭VS所有的程序,包就会开始自动下载,下载完之后,重新进入VS;按照箭头指向进行。
4.搜索Setup Project
5.选择路径,这里我把它放到桌面上了
6.出现类似这个界面,右键第一个,先添加想要打包的.c文件
7.再选择项目输出,然后确定
8.回到解决方案资源管理器那里,右键setup,选择重新生成
9.此时回到桌面,打开setup1的文件夹,发现有两个,用Dubug进行调试的,就在Dubug里,反之就在Release里,我的在Release里
10.发现生成了安装包,打开第一个,进行安装。路径选到了桌面
11.第一个就是你打包的文件了,之后你可以将这些再打包成压缩包发给朋友们
第一个小游戏:猜数字
思路
1.首先我们可以根据游戏名字知道既然是猜数字,那麽一定是随机的数。因此可以得知用到rand函数,rand生成的是伪随机数,是根据srand设置的一个返回起点返回一个随机值,这个起点也叫随机数种子,rand就是根据随机数种子为基准来计算随机数的,且默认种子为1。srand是随机数发生器的初始化函数;
2.还要了解一个知识,关于时间戳的认识:从计算机诞生到现在时间的秒数,持续变化,是个随机值。
3.因为rand要返回一个随机数,而起点默认为srand设置,因为rand是根据随机数种子为基准来计算随机数的,所以为我们想让它生成不同的随机数,就是要让种子也随机。因此可以在srand函数中需要放一个随机数,所以通过时间戳来生成随机数放入srand函数中。这时利用了time函数
4.当然漫无目的的猜数不是我们的目的,因此我们可以缩小猜数的范围rand()%100+1,把它的范围设立到1-100.如果想生成0-99间的话,就是rand()%100;如果想生成100-200间的话,就是rand()%100+(200-100+1);所以我们如果想要自定义随机数的范围,可以这样写rand()%100+(b-a+1),即为a-b的范围。
实现
1.先编写菜单页面
void menu() //函数调用
{
printf("----------------------------------\n");
printf("--------1.game------2.exit--------\n"); //表示两个选择
printf("----------------------------------\n");
}
2. 编写游戏流程
void game() //函数调用
{
int num, input;
num = rand() % 100 + 1; //限定随机数范围
while (1) //无限循环
{
printf("请输入数字\n");
scanf_s("%d", &input);
if (num == input)
{
printf("恭喜,你猜对了\n");
break;
}
else if (num < input)
{
printf("你猜大了");
}
else
{
printf("你猜小了");
}
}
}
3.编写主程序
int main()
{
int choice;
srand((unsigned int)time(NULL));
do //do...while在这里可以让游戏多次玩
{
menu();
printf("请输入正确的选项:\n"); scanf_s("%d", &choice);
switch (choice) //选择1,进入游戏,0则退出程序,其他数字则显示错误,并重新输入。
{
case 1:game();
break;
case 0:
break;
default:
printf("错误,请输入正确的数字");
break;
}
} while (choice);
return 0;
}
4.完整代码
#include <stdio.h>
#include <windows.h>
#include <time.h>
void game()
{
int num, input;
num = rand() % 100 + 1;
while (1)
{
printf("请输入数字\n");
scanf_s("%d", &input);
if (num == input)
{
printf("恭喜,你猜对了\n");
break;
}
else if (num < input)
{
printf("你猜大了");
}
else
{
printf("你猜小了");
}
}
}
void menu()
{
printf("----------------------------------\n");
printf("--------1.game------2.exit--------\n");
printf("----------------------------------\n");
}
int main()
{
int choice;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入正确的选项:\n"); scanf_s("%d", &choice);
switch (choice)
{
case 1:game();
break;
case 0:
break;
default:
printf("错误,请输入正确的数字");
break;
}
} while (choice);
return 0;
}
第二个小游戏:扫雷
扫雷这个游戏大家可谓是耳熟能详,当年可是风靡全网;很多小伙伴都好奇它是怎末实现的,今天我就为大家带来初级版的扫雷游戏;
游戏规则
输入一个坐标,如果有雷,那么就会被炸死,游戏失败,重新开始。如果没有雷,则继续,并会在坐标处显示出周围八个格子的雷的数量。根据这个不断排雷,直到所有雷排除,游戏胜利。
实现流程
准备工作
首先,要先创建两个.c文件:game.c和test.c;分别存储游戏实现部分和主函数部分的代码;再创建头文件game.h,用于存放函数声明;
具体步骤
我们已经知道了扫雷的流程,但是我们应该如何实现它呢???
不要着急,慢慢来;首先我们进入游戏应该有一个主菜单吧;而主菜单如何打印呢,我们在上面猜数字的游戏里其实已经学习过了,它们的框架其实都差不多。
1.打印主菜单
首先,我们要有进入和退出游戏两个选项吧,我们设立1为进入游戏;0为退出游戏;
void menu()
{
printf("----------------------------\n");
printf("-----------1.game-----------\n");
printf("-----------2.exit-----------\n");
printf("----------------------------\n");
}
再写出主函数,来进行调用
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//先不要管,后面会讲到,为什莫用它
do
{
menu();
printf("请选择:");
scanf_s("%d", &input);
switch (input)
{
case 1:game();
break;
case 2:
printf("退出游戏");
break;
default:
printf("选择错误,重新选择");
break;
}
} while (input);
return 0;
}
这里的do...while可以让我们多次运行游戏;
此时的效果图就是如下
2.初始化棋盘
对于棋盘的初始化,小伙伴们都很疑惑,该如何创建呢???既然是棋盘,那肯定是方方正正的啊,那么我们首先利用#define设立一下棋盘的行和列,这里我把行称为row,列称为col.
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
大家一定很好奇后面两行是什么意思,我举个例子,如果坐标在最右上角,那麽现在想要知道它周围八个格子类的数量,是不是不可取,这时就发生了数组越界问题;因此我们要为棋盘四周加上一层;左右各一个即列,上下各一个即行是不是行列各加2啊;
OK,定义完行列后就要开始进行棋盘的初始化了;
char mine[ROWS][COLS];
char show[ROWS][COLS];//定义数组,防止越界
Initboard(mine, ROWS, COLS, '0');//0代表没有雷
Initboard(show, ROWS, COLS, '*');//*代表隐藏排雷区
这里要说一下,0代表没有雷。1则代表所处位置有雷;mine你可以理解为管理者看到的即可以看到地雷的位置,show则是游戏者看到的;不懂不要紧,慢慢往下看,你一定能懂的;
再进行初始化棋盘的函数
void Initboard(char board[ROWS][COLS], int rows, int cols,char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;//set表示接收定义的符号,好处是方便改变符号;
}
}
}
然后要在game.h中进行声明,就是把上面那句话给复制过去;
大家一定也疑惑一个地方,为什么有的大写,有的小写呢;那是因为大写的是宏,而小写则是传参;小伙伴们,你们理解了吗!!!
//初始化棋盘
void Initboard(char board[ROWS][COLS], int rows, int cols, char set);//记得加上分号哦
好的,现在棋盘已经初始化完了,我们可以开始打印棋盘了;
3.打印棋盘
这时我们就要在主函数的game()模块创建一个新函数了;我把它叫做Displayboard。接受三个参数show、ROW和COL;用于展示布局;
Displayboard(show, ROW, COL);
那么,开始正式的编写打印棋盘的代码,回到game.c中,因为这里是对棋盘的打印,所以行和列为row和col。
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= col; i++)//将i初始化为0,目的是让最外面那层防止越界的从0-9刚好包住棋盘的从1-9
{
printf("%d ", i);//打印列号
}
puts(" ");
for (i = 1; i <= row; i++)
{
printf("%d ", i);//打印行号
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
如果第一个for循环将i初始化为1的话,就会出现下图的情况。
好的,我们看一下效果图;下面的0和1暂时不用管,后面会说。主要看一下效果图。
这样是不是感觉有点不太清爽的样子;没有一点边界感🤙🤙🤙,这可不行,我们再稍微改一下。
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("------------扫雷游戏------------\n");
for (i = 0; i <= col; i++)//打印列号
{
printf("%d ", i);
}
puts(" ");
for (i = 1; i <= row; i++)
{
printf("%d ", i);//打印行号
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------------扫雷游戏------------\n");
}
效果如下:
嘿嘿,是不是好多了;但是又有小伙伴说了,人家的棋盘两符号之间都有框在隔着。不多说,安排;😈😈😈
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("------------扫雷游戏------------\n");
for (i = 0; i <= col; i++)//打印列号
{
if (i == 0)
{
printf("%d ", i);//空格要注意,自己调整。
}
else
{
printf("%d ", i);
}
}
printf("\n");
for (i = 0; i <= col; i++)//打印每一列的框架
{
if (i == 0)
{
printf(" |");
}
else
{
printf("--|");
}
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);//打印行号
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c |", board[i][j]);
}
printf("\n");
for (int k = 1; k <= row; k++)//打印每一行的框架
{
if (k == 1)
{
printf(" ");
}
if (k == 1)
printf("|--|");
else
{
printf("--|");
}
}
printf("\n");
}
printf("------------扫雷游戏------------\n");
}
哼哼,经过N长时间的修改,终于改好了😬😬😬;下面来看一下效果图吧。
是不是高端、大气、上档次😈😈😈
还有,不要忘记在game.h里面进行声明哦;
//打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col);
那么,棋盘已经布置好了,就要开始布置雷了;
4.布置雷
首先我们可以想到,雷的位置一定是随机的,那我们就要用到随机数的知识了,上面的猜数字游戏主要是利用它来解决的。不懂的小伙伴可以看看上面的。♥️♥️♥️
而对于布置雷我又创建了一个新的函数
Setmine(mine, ROW, COL);
然而,我要先设置一下雷的数量,在哪里设置呢???当然是在game.h中利用#define设置了;
#define EASY_COUNT 10//这里EASY_COUNT就是雷的数量
接着开始正题
void Setmine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1; //随机一个数,使其在0-9的范围,作为行
int y = rand() % col + 1; //随机一个数,使其在0-9的范围,作为列
if (mine[x][y] == '0') //如果坐标处为0,说明无炸弹。
{
mine[x][y] = '1'; //既然没有炸弹,所以在这个坐标下安放炸弹。
count--; //每安装一个,炸弹数量减一,直到全部安装完毕。
}
}
}
根据前面学习,rand()函数生成的是伪随机数。因此我们要利用时间戳使随机数种子随机才行;就要利用time.h了;
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//把它放在do...while循环前面
do
{
menu();
printf("请选择:");
scanf_s("%d", &input);
switch (input)
{
case 1:game();
break;
case 2:
printf("退出游戏");
break;
default:
printf("选择错误,重新选择");
break;
}
} while (input);
return 0;
}
好了,雷已经布置好了,这时候如果我们想看一下雷在哪个地方怎么办呢???可以在game()函数中布置雷的下面添加Displayboard
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');
//打印棋盘
Displayboard(show, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
Displayboard(mine, ROW, COL);//mine代表雷的布局,所以我们可以看到雷的布局
}
这也就是我上面的图中为什么会出现0和1的原因;1为雷,0为安全位置;小伙伴们,都懂了吗🤙🤙🤙
仍然要记得声明
//布置雷
void Setmine(char mine[ROWS][COLS], int row, int col);
5.排雷
既然布置雷已经了解了,那我们就开始最后一个步骤吧。再创建一个函数Findmine
Findmine(mine, show, ROW, COL);
接着我们捋一下思路;首先输入坐标后有三种可能:
1.坐标处有雷,游戏失败,重新开始
2.坐标处没有雷,已排除数量+1.
3.输入的坐标超出范围。
再者定义一个win,来表示已排除炸弹数量;它的范围是什么呢;大家不妨想一想,当时我们游戏设立的行和列是多少,再减去炸弹数量不就是已排除数量吗;当win==row*col-EASY_COUNT的时候,就说明炸弹已经排完,游戏胜利。
win<row*col-EASY_COUNT
我们来用代码实现一下这个过程
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win<row*col-EASY_COUNT)//实现循环操作
{
printf("请输入坐标:\n");
scanf_s("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("你被炸死了,游戏结束\n");
Displayboard(mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(mine, x, y);//获取x,y坐标周围有几个雷
show[x][y] = count + '0';//'0'的Ascii值为48,count假如为1,值为49,转换为数字为1;
Displayboard(show, ROW, COL);//这句话就是把通过GetMineCount函数获取到的周围的类的数量显示出来。
win++;
}
}
else
{
printf("坐标非法,重新输入");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功");
Displayboard(mine,ROW, COL);
}
}
至于这里为什么要+‘0’呢,我放一张ASCII码让大家看看。
我们可以看到'0'是48,如果我们所选坐标周围的雷的数量为1,48+1换为字符是不是1呢。说到这里
大家应该都懂了吧。🌝🌝🌝
然后我们发现这里调用了GetMineCount,因此我们需要写出函数主体。
static int GetMineCount(char mine[ROWS][COLS], int x, int y) //static可以让我们不用再声明这个函数
{
return (mine[x][y - 1] +
mine[x][y + 1] +
mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x - 1][y + 1] +
mine[x + 1][y] +
mine[x + 1][y - 1] +
mine[x + 1][y + 1] - 8 * '0'); //为啥这么做呢?字符数据相减,对应其ASCII相减,就是为了方便统计排雷处周围的雷数
}
再把Findmine进行声明
//排雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
写到这里,初级版的扫雷就已经结束了。各位看官是否学会了呢???😬😬😬
还有一个知识点,我们可以把库函数都写在game.h中,game.c和test.c中只用写#include "game.h"就可以了。
完整代码
<game.h>
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
//初始化棋盘
void Initboard(char board[ROWS][COLS], int rows, int cols, char set);
// 打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col);
//布置雷
void Setmine(char mine[ROWS][COLS], int row, int col);
//排雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
<game.c>
#include "game.h"
void Initboard(char board[ROWS][COLS], int rows, int cols,char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("------------扫雷游戏------------\n");
for (i = 0; i <= col; i++)//打印列号
{
if (i == 0)
{
printf("%d ", i);
}
else
{
printf("%d ", i);
}
}
printf("\n");
for (i = 0; i <= row; i++)
{
if (i == 0)
{
printf(" |");
}
else
{
printf("--|");
}
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);//打印行号
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c |", board[i][j]);
}
printf("\n");
for (int k = 1; k <= row; k++)
{
if (k == 1)
{
printf(" ");
}
if (k == 1)
printf("|--|");
else
{
printf("--|");
}
}
printf("\n");
}
printf("------------扫雷游戏------------\n");
}
void Setmine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')//如果坐标处为0,说明无炸弹。
{
mine[x][y] = '1';
count--;
}
}
}
static int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return (mine[x][y - 1] +
mine[x][y + 1] +
mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x - 1][y + 1] +
mine[x + 1][y] +
mine[x + 1][y - 1] +
mine[x + 1][y + 1] - 8 * '0');
}
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win<row*col-EASY_COUNT)//实现循环操作
{
printf("请输入坐标:\n");
scanf_s("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("你被炸死了,游戏结束\n");
Displayboard(mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(mine, x, y);//获取x,y坐标周围有几个雷
show[x][y] = count + '0';//'0'的Ascii值为48,count假如为1,值为49,转换为数字为1;
Displayboard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标非法,重新输入");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功");
Displayboard(mine,ROW, COL);
}
}
<test.c>
#include "game.h"
void menu()
{
printf("----------------------------\n");
printf("-----------1.game-----------\n");
printf("-----------2.exit-----------\n");
printf("----------------------------\n");
}
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');
//打印棋盘打印
Displayboard(show, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
Displayboard(mine, ROW, COL); //布置雷后放,让你看到雷的位置
//排雷
Findmine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf_s("%d", &input);
switch (input)
{
case 1:game();
break;
case 2:
printf("退出游戏");
break;
default:
printf("选择错误,重新选择");
break;
}
} while (input);
return 0;
}
最后,大家欣赏一下效果图
创作不易,希望大佬们以及未来的大佬们给个三连再走吧
创作不易,希望大佬们以及未来的大佬们给个三连再走吧
创作不易,希望大佬们以及未来的大佬们给个三连再走吧
同时,也希望各位大佬能够指正文章的错误,(^_^)∠※