2048制作

在这张图片里面我们看第一列数字{ 2 2 0 4 },这其实就是一个一维数组,然后当玩家按下W或者↑键时我们需要对这个一维数组进行数据处理,就是将{ 2 2 0 4 }变成{ 4 4 0 0 }。

然后我是怎么实现的呢,分两步,先将数字{ 2 2 0 4 }变成{ 2 2 4 0 },然后循环判断相邻的两个数字是否相同,相同就合并。

我们来看一下代码中的实现方式

case 72://上
case'W':
case'w':
    //把0向下移动
    for (int j = 0; j < 4; j++)     //4列分别操作
    {
        len = 4;
        for (int i = 0; i < len - 1; i++)
        {
            if (map[i][j] == 0)
            {
                //下面的数字往上移一个格子
                for (int k = i; k < 3; k++)
                {
                    map[k][j] = map[k + 1][j];
                    map[k + 1][j] = 0;
                }
                len--;  //出现一个 0 len减一
                i--;    //返回原位置检测是否有 0
            }
        }
        for (int i = 0; i < len - 1; i++)
        {
            if (map[i][j] == 0) break;      //第一行为0 后面都是0,不进行操作
            if (map[i][j] == map[i + 1][j]) //检测相邻两个数字是否相同,相同就合并
            {
                map[i][j] *= 2;     //合并
                //合并之后后面的数字往前移动一位
                for (int k = i + 1; k < 3; k++)
                {
                    map[k][j] = map[k + 1][j];
                    map[k + 1][j] = 0;
                }
                //进行打分
                *score += map[i][j];
            }
        }
    }
    break;

别看代码挺长的,其实理解起来特别简单,并且四个方向的代码都是一个模型,复制粘贴,修改点东西,整个游戏的核心代码就掌握了,然后就是界面弄好看点。由于图方便快捷,我没有去找图片资源,所以做的界面可能比较,嗯,垃圾。这个呢仅供学习,别当真,千万别一根筋的说我要通关,我要2048,微信小程序搜索2048,那个界面好看点。

02

游戏三部曲

主函数 int main() 

int main()
{
    initgraph(MAP_ROW * PIXEL + 100, MAP_COL * PIXEL + 100);    //加载窗口
    init(map, &score);          //初始化地图数据
    while (1)
    {
        DrawMap(map, score);    //绘制地图
        Play(map, &score);      //玩家操作
        switch (Judg(map))      //判断输赢  对结果进行匹配
        {
        case 0://赢
            break;
        case -1://输
            break;
        case 1://没有空位置
            break;
        case 2://还有空位置
            break;
        default:
            break;
        }
    }
    closegraph();
    return 0;
}

这个没啥好说的,游戏三部曲

1、加载游戏数据初始化   init() ;)

2、绘制图形(绘图     DrawMap() ;)

3、玩家操作(数据更新  Play() ;)

初始化   init()

void init(int map[][MAP_COL], int *score)
{
    int x, y;   //随机位置参数
    *score = 0; //对成绩进行初始化
    memset(map, 0, sizeof(int)*MAP_ROW*MAP_COL);    //初始化地图
    //对地图进行初始化
    for (int i = 0; i < 2;)
    {
        x = rand() % 4;
        y = rand() % 4;
        if (map[x][y] == 0)
        {
            if (rand() % 9 == 0)
                map[x][y] = 4;
            else
                map[x][y] = 2;
            i++;
        }
    }
}

2048由于游戏简单,没有什么图片资源啊什么的各种资源的加载,所以初始化函数只需要初始化一些基本的数据。

绘图  DrawMap()

void DrawMap(int map[][MAP_COL],int score)
{
    wchar_t arr[20];                //临时参数
    setbkcolor(RGB(0, 0, 0));       //背景颜色
    setlinecolor(RGB(0, 255, 0));   //线条颜色
    setlinestyle(PS_SOLID, 3);      //线条风格
    settextcolor(RGB(0, 255, 0));   //字体颜色
    settextstyle(20, 0, L"宋体");   //字体风格 和 字体大小
    cleardevice();                  //清屏
    BeginBatchDraw();               //开始绘制地图
    for (int i = 0; i <= 4; ++i)
    {
        line(PIXEL * i, 0 + 50, PIXEL * i, PIXEL * 4 + 50);//竖线
        line(0, PIXEL * i + 50, PIXEL * 4, PIXEL * i + 50);//横线
    }
    for (int i = 0; i < 4; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            wsprintf(arr, L"%d", map[i][j]);                    //将数字写入字符串
            outtextxy(j * PIXEL + 32, i * PIXEL + 50 + 30, arr);//指定位置输出字符串
        }
    }
    //分数
    settextcolor(RGB(0, 255, 0));   //字体颜色 红色
    wsprintf(arr, L"score: %d", score);
    outtextxy(0, 15, arr);          //指定位置输出字符串
    //最高分
    outtextxy(MAP_ROW * PIXEL + 10 , 5, L"最高分:");         //指定位置输出字符串
    wsprintf(arr, L"%d", MaxScore);
    outtextxy(MAP_ROW * PIXEL + 15 , 25, arr);              //指定位置输出字符串
    outtextxy(MAP_ROW * PIXEL + 10, 80, L"↑↓←→");           //指定位置输出字符串
    outtextxy(MAP_ROW * PIXEL + 10, 120, L"WSAD");          //指定位置输出字符串
    outtextxy(MAP_ROW * PIXEL + 10, 160, L"控制游戏");       //指定位置输出字符串
    outtextxy(80, 360, L"微信公众号:编程学习基地");         //指定位置输出字符串
    EndBatchDraw();     //结束绘制地图
}

绘制地图就是设置一些字体啊,背景颜色啊,然后就是将16宫格画上去,地图里面的数字显示到16宫格上,虽然很繁琐,但是也很简单,调用这些个函数就可以了。

数据更新  Play()

void Play(int map[][MAP_COL], int * score)
{
    int len;
    switch (getch())
    {
    case 75://左
    case'A':
    case'a':
        for (int i = 0; i < 4; i++)
        {
            len = 4;
            for (int j = 0; j < len - 1; j++)
            {
                if (map[i][j] == 0)
                {
                    for (int k = j; k < 3; k++)
                    {
                        map[i][k] = map[i][k + 1];
                        map[i][k + 1] = 0;
                    }
                    len--;
                    j--;
                }
            }
            for (int j = 0; j < 3; j++)
            {
                if (map[i][j] == 0) break;
                if (map[i][j] == map[i][j + 1])
                {
                    map[i][j] *= 2;
                    for (int k = j + 1; k < 3; k++)
                    {
                        map[i][k] = map[i][k + 1];
                        map[i][k + 1] = 0;
                    }
                    *score += map[i][j];
                }
            }
        }
        break;
    default:break;
    }
}

在游戏设计里面已经说得挺明白了,也示例了W和↑键的代码,这里就复制下左和←键的代码凑个牌面。

这里简单提下↑↓←→键的ASCII码值

ASCII
72
80
75
77

添加数字  Add()

void Add(int map[][MAP_COL])
{
    //添加数字
    int x, y;
    do
    {
        x = rand() % 4;
        y = rand() % 4;
    } while (map[x][y] != 0);   //找到数字为零的位置
    if (rand() % 9 == 0)        //设置4出现的概率为1/9
        map[x][y] = 4;
    else
        map[x][y] = 2;
}

2048游戏就是通过没次添加一个数字逼迫玩家消灭数字,函数的功能实现也简单,直接看代码就能看得懂,在这里我就加了个限制来控制2和4出现的概率。

判断输赢  Judg()

int Judg(int map[][MAP_COL])
{
    int num = 0;    //记录0的个数
    int flag = 0;   //如果存在一组可以合并的元素 那么flag置为1
    for (int i = 0; i < 4; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            if (map[i][j] >= 2048) return 0;//赢
            if (map[i][j] == 0) num++;      //记录0的个数
            if (j + 1 < 4 && map[i][j] == map[i][j + 1]) flag = 1;//右边是不是一样
            if (i + 1 < 4 && map[i][j] == map[i + 1][j]) flag = 1;//下方是不是一样
        }
    }
    if (num == 0 && flag == 0)  return -1;  //满了并且不能合并  输
    if (num == 0) return 1;                 //满了 但是可以合并
    return 2;
}

判断输赢里面赢最好判断了,出现2048就赢了,输的话就是flag=0,num=0也就是地图中没有0,并且每个数字的左边和下面没有相同的数字就是输,把逻辑整明白,代码写起来就简单。

保存数据  WriteData() ReadData()

void WriteData(int map[][MAP_COL], int score)
{
    FILE*fp = fopen("D:\\2048.dat", "wb");
    if (fp == NULL) return;
    fwrite(map, sizeof(int)*MAP_ROW*MAP_COL, 1, fp);
    fwrite(&score, sizeof(int), 1, fp);
    fwrite(&MaxScore, sizeof(int), 1, fp);
    fclose(fp);
}

void ReadData(int map[][MAP_COL], int* score)
{
    FILE*fp = fopen("D:\\2048.dat", "rb");
    if (fp==NULL) return;
    fread(map, sizeof(int)*MAP_ROW*MAP_COL, 1, fp);
    fread(score, sizeof(int), 1, fp);
    fread(&MaxScore, sizeof(int), 1, fp);
    fclose(fp);
}

这个就是将地图中的数据写入到磁盘中,然后怎么写入的怎么读取,我也就简单地实现了下数据保存功能,详细的文件操作请看

         

               C语言语法篇之文件操作

03

游戏优化

1. 用带颜色的图片替代简陋的数字,不图啥,就图界面好看。

2. 可以加载一张图片做背景,可以是你女朋友友的,如果没有,那用你自己的也可以

3. 学过数据结构,知道栈的同学可以实现操作回退功能,这个我准备年后用推箱子来做个实例演示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值