【C++】基于EasyX库的2048小游戏

news2024/11/23 9:26:31

文章目录

  • 0 前言
  • 1 先看一下最终的效果图
  • 2 2048核心
  • 2 EasyX库
    • 2.1 配色
    • 2.2 文字
    • 2.3 填充
  • 3 总结

0 前言

  最近比较迷2048小游戏,于是想自己写代码实现出来,恰好也在网上找到一个现成的2048的VS工程,但是界面做得很难看,且运行逻辑存在一定问题,于是花了一天时间把原2048工程完善了一下,记录一下实践要点。

1 先看一下最终的效果图

在这里插入图片描述

2 2048核心

  既然要做2048游戏,首先是要实现2048这个游戏规则。由于C语言中没有Python语言中便捷操作矩阵的方法,因此只能老实定义二维数组、然后用循环去实现。因此代码相对复杂。

#include <iostream>
#include <conio.h>
#include <stdlib.h>
using namespace std;

//#include"2048base.h"

/*矩阵转置*/
void transform(int *p, int len)
{
    for (int i = 0; i < len; i++)
        for (int j = 0; j < len; j++)
            if (i>j) //转置时只需要更新对角部分即可
            {
                int tmp = *(p + i*len + j);
                *(p + i*len + j) = *(p + j*len + i);
                *(p + j*len + i) = tmp;
            }
}

/*删除某一行数据中的零元素——把零元素根据rev往一个方向去堆叠*/
void delZeros(int *p, int len, bool rev)
{
    int k = rev ? (len - 1) : 0;
    int step = rev ? -1 : 1;
    for (int j = rev ? (len - 1) : 0; j < len && j >= 0;)
    {
        if (*(p + j) != 0)
        {
            *(p + k) = *(p + j);
            k += step;
        }
        j += step;
    }
    for (int j = k; j < len && j >= 0;)
    {
        *(p + j) = 0;
        j += step;
    }
}

/*合并一行数据的相同元素,返回得分*/
int combine(int *p, int len, bool rev)
{
    int score = 0;				 // 得分
    int k = rev ? (len - 1) : 0; // 主要的顺序变量
    int step = rev ? -1 : 1;	 // 步长,和是否反向有关
    for (int i = rev ? (len - 1) : 0; i < len && i >= 0; i += step)
    {
        if ((*(p + i) != *(p + i + step)) || (i == (rev ? 0 : (len - 1))))
        {
            *(p + k) = *(p + i);
            k += step;
        }
        else
        {
            *(p + k) = *(p + i) * 2;
            i += step; // i跳过重复数字的位置
            k += step;
            score += *(p + i) * 2;
        }
    }
    for (int j = k; j < len && j >= 0; j += step)
        *(p + j) = 0; // k没遍历完,补零
    return score;
}

/*输出二维数组*/
void out(int *p, int len)
{
    for (int i = 0; i < len; i++)
    {
        for (int j = 0; j < len; j++)
            cout << *(p + i * len + j) << ' ';
        cout << endl;
    }
    cout << endl;
}

/*判断移动前后数组是否发生改变*/
bool ifchange(int *p, int *q, int len)
{
    bool flag = false;
    for (int i = 0; i < len; i++)
        for (int j = 0; j < len; j++)
            if (*(p + i*len + j) != *(q + i*len + j)) flag = true;
    return flag;
}

/*对数组进行堆叠。p为需要堆叠的一行/列数据,len为边长,rev判断是否反向[从左至右], transform判断是否需要转置[上/下]。
 *默认的矩阵顺序:行从上到下;列从左至右。计算时,遍历每一行,堆叠每一列
 *返回数组堆叠前后是否发生变化
 */
bool pileRows(int *p, int len, bool rev, bool trans, int *score)
{
    int *q = new int[len*len];
    for (int i = 0; i<len; i++)
        for (int j = 0; j<len; j++)
            *(q + i*len + j) = *(p + i*len + j); //先复制一遍,方便判断数组是否发生改变
    if (trans) transform(p, len); // 转置
    // out(p, len);
    for (int i = 0; i < len; i++) // 遍历每一行
    {
        int *q = p + i * len;     // 构造一行数据对应的指针
        // for(int i=0;i<len;i++) cout << *(q+i) << " ";cout << endl;
        delZeros(q, len, rev);    // 先把这一行中的零元素往一个方向堆叠
        // for(int i=0;i<len;i++) cout << *(q+i) << " ";cout << endl;
        *score += combine(q, len, rev); //合并相同元素,并获得得分
        // for(int i=0;i<len;i++) cout << *(q+i) << " ";cout << endl;
    }
    // out(p, len);
    if (trans) transform(p, len); // 操作完了,再转置回来
    return ifchange(p, q, len);   // 返回数组是否发生变化的标志
}

/*添加随机数*/
void AddNum(int *p, int len)
{
    int x, y;
    do
    {
        x = rand() % 4;
        y = rand() % 4;
    } while (*(p + x * len + y) != 0); // 找到数字为零的位置
    if (rand() % 9 >= 5)  // 4出现的概率为4/9
        *(p + x * len + y) = 4;
    else
        *(p + x * len + y) = 2;
}

/*运行2048*/
void run(int *p, int len, int *score)
{
    char key = getch();
    switch (key)
    {
    case 72: //"up"
    case 'w':
    case 'W':
        if (pileRows(p, len, false, true, score)) AddNum(p, len); //只有数组发生改变才增加一个随机数
        //out(p, len);
        break;
    case 80: //"down"
    case 's':
    case 'S':
        if (pileRows(p, len, true, true, score)) AddNum(p, len);
        //out(p, len);
        break;
    case 75: //"left"
    case 'a':
    case 'A':
        if (pileRows(p, len, false, false, score)) AddNum(p, len);
        //out(p, len);
        break;
    case 77: //"right"
    case 'd':
    case 'D':
        if (pileRows(p, len, true, false, score)) AddNum(p, len);
        // out(p, len);
        break;
    default:
        break;
    }
}

/*主程序,测试用*/
//int main()
//{
//    int b[4][4] = { 4, 0, 0, 0,
//        2, 0, 0, 0,
//        8, 0, 0, 0,
//        2, 0, 0, 0 };
//    int *score = new int;
//    *score = 0;
//    int *x = (int *)b;
//    while (1)
//    {
//        run(x, 4, score);
//        out(x, 4);
//    }
//
//    // int a[] = {2,2,1,2};
//    // cout << combine(a,4,true);
//    // for(int i=0; i<4; i++) cout << a[i] << " ";
//    return 0;
//}

  以上代码可以概括为几个要点:①先堆叠零,往哪个方向移动就往另一边堆叠零;②合并相同的数,并计算得分;③以上两个操作都是按行操作,即左右移动时。如果是上下移动,需要先对数组进行转置,再进行以上操作,操作完了再转置回来。④最后是判断数组是否发生变化,再选择是否需要增加随机数。
  需要注意的就是写代码的时候逻辑要清晰,而且建议以指针作为参数传入,只修改指针指向的内容,不修改指针本身,这样可以尽量减少函数返回值

2 EasyX库

  实现完了核心部分,接下来就是制作界面了。这里使用的是C++的一个第三方库——EasyX,这是一个可以用来绘制界面的库,而且使用起来相对方便。具体安装方法和使用方法可以参考官方文档,内容非常详细。

2.1 配色

  由于本人实在没有艺术细胞,关于这个游戏的配色,是完全参考自一个2048的在线游戏,链接在这里。如下图所示。
在这里插入图片描述

2.2 文字

  在显示文字方面,这里采用的是outtextxy函数,可以在指定位置输出设定的文本,不过它默认是有背景色作为填充的,可以在调用该函数先设置一下:
在这里插入图片描述

  另外,这个第三方库和MFC不一样,可以指定某段文本的属性,它是设置完属性后,如字体的颜色,大小等,之后所有写入的文本都会按照这个属性来,所以在调用该函数前,记得先设置好属性。

2.3 填充

  2048如果只是数字的移动看起来不太方便,最好是要有不同颜色的方块。好在EasyX库也支持填充函数fillrectangle。和上面一样,每次使用前都需要设置好属性。

3 总结

  本博客主要记录了一下自己使用C++实践2048小游戏时的一些心得体会,同时提供了核心代码。颜色渲染部分建议还是去认真看一下官方文档,写得挺明白的。总的来说,这个项目不是很难。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/158405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

研究发现,大多数长期 COVID 影响在感染后一年内消退

英国医学杂志今天发表的一项来自以色列的大型研究发现&#xff0c;轻度 COVID-19 感染后出现的大多数症状或病症会持续数月&#xff0c;但在一年内恢复正常。 特别是接种过疫苗的人&#xff0c;呼吸困难的风险较低。这通常也是轻度感染后最常见的影响。相比之下&#xff0c;比未…

【Day2】977有序数组的平方、209长度最小的子数组、59螺旋矩阵Ⅱ

【Day2】977有序数组的平方、209长度最小的子数组、59螺旋矩阵Ⅱ977有序数组的平方暴力排序双指针法209长度最小的子数组暴力解法滑动窗口法59螺旋矩阵Ⅱ977有序数组的平方 题目链接&#xff1a;977 题目&#xff1a;给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返…

Linux常用命令——xargs命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) xargs 给其他命令传递参数的一个过滤器 补充说明 xargs 命令是给其他命令传递参数的一个过滤器&#xff0c;也是组合多个命令的一个工具。它擅长将标准输入数据转换成命令行参数&#xff0c;xargs 能够处理管道…

python--城堡保卫战

实现功能&#xff1a; 1&#xff1a;敌人的绵绵不断的前进&#xff0c;拿着各种各样的武器&#xff08;叉子&#xff0c;斧头&#xff0c;宝剑&#xff09;&#xff0c;挥动武器攻击我方城堡&#xff0c;对我方城堡造成伤害&#xff01; 2&#xff1a;我方城堡发现敌人可手动…

Linux-文件系统

Windows文件系统 在Windows下&#xff0c;打开“计算机”&#xff0c;我们看到的是一个个驱动盘符。 注意&#xff1a;盘符与硬件不是对应的&#xff0c;比如说电脑有有一块硬盘&#xff0c;到Windows下可以将其切成C、D、E盘&#xff0c;也就是一个硬盘可以放多个盘符。 Lin…

maple-example简单操作示例

好久都没写博客了&#xff0c;今天学习到一点新知识&#xff0c;在这里小编和大家分享&#xff0c;欢迎大家指点&#xff0c;这篇文章是关于 maple-example的简单操作示例&#xff0c;具体软件下载不做讲解&#xff0c;谢谢&#xff01;

浅谈分辨率带宽RBW

频谱仪是射频工程师最常用的设备之一&#xff0c;信号的频率、功率、谐波、相位噪声等诸多射频参数都需要使用频谱仪测试。使用频谱仪时&#xff0c;有一个参数需要经常设置&#xff0c;就是分辨率带宽(Resolution BW&#xff0c;简称RBW)。RBW是指中频链路上最小的中频滤波器带…

Enhance the Visual Representation via Discrete Adversarial Training

在自然语言处理NLP中&#xff0c;AT可以从泛化中受益&#xff0c;我们注意到AT在NLP任务中的有优点可能来自于离散和符号输入空间。为了借鉴NLP风格AT的优势&#xff0c;我们提出了离散对抗训练&#xff08;DAT&#xff09;。DAT利用VQGAN将图像数据改为离散的类似文本的输入&a…

Vuex的学习内容

本教程使用的是vue3 1.核心概念 官网地址:https://vuex.vuejs.org/安装(固定)配置项(固定) 2. 图示关系 单一定义store对象,里面5个配置项,在任意组件可以使用. 3.案例准备 准备两个组件AddItem.vue、SubItem.vue、Main.vue 展示效果如下: AddItem代码 <template&…

STL - String容器

1. string基本概念 本质&#xff1a; string是C风格的字符串&#xff0c;而string本质上是一个类 string和char *的区别&#xff1a; char *是一个指针 string是一个类&#xff0c;类内部封装了char *,管理这个字符串&#xff0c;是一个char *型的容…

本地小说阅读网站打造

目录 一、本地小说网站总体组织框架 1、所需的VUE库和elementLib以及JQ库 2、本地目录设计 3、整体代码样式 二、正文核心代码 1、引入element 样式&#xff0c;和自定义的样式 2、引入JS 3、自定义Header组件 1&#xff09;vue 定义MyHeader组件 2&#xff09;MyHead…

Mapstruct的具体介绍与使用

我是 ABin-阿斌&#xff1a;写一生代码&#xff0c;创一世佳话&#xff0c;筑一览芳华。 如果小伙伴们觉得我的文章不错&#xff0c;记得一键三连哦 文章目录一、mapstruct简介二、mapstruct与其他映射对比三、mapstruct底层原理解析1、Java动态编译四、具体使用1、依赖导入2、…

Linux开发工具的使用(三)

文章目录Linux开发工具的使用&#xff08;三&#xff09;1. 缓冲区1.1 理解\r和\n1.2 缓冲区的初步理解1.3 倒计时小程序实现1.4 进度条小程序实现2. 分布式版本控制系统-git使用2.1 git历史2.2 git版本控制理解2.3 git使用2.3.1 gitee搭建远程仓库2.3.2 开始配置3. Linux调试器…

Revit教程:创建“幕墙竖梃族”的方法步骤

幕墙竖梃族分为两个组成部分&#xff1a;“幕墙竖梃”和“公制轮廓-竖梃”&#xff0c;前者是基于后者轮廓的一个实体拉伸&#xff0c;两者的关系类似于实体与草图。轮廓族及门窗族 (公制门-幕墙&#xff0c;公制窗-幕墙而非公制门与公制窗)可以嵌套入CAD详图或Revit详图&#…

93、【树与二叉树】leetcode ——222. 完全二叉树的节点个数:普通二叉树求法+完全二叉树性质求法(C++版本)

题目描述 原题链接&#xff1a;222. 完全二叉树的节点个数 解题思路 1、普通二叉树节点个数求法 &#xff08;1&#xff09;迭代&#xff1a;层序遍历BFS 遍历一层获取一层结点 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode …

【九】Netty HTTP+XML协议栈开发

HTTP协议介绍业务场景流程图技术栈设计流程图的分析:Step 1Step2Step3Step4Step5分析结果开发开发流程图代码jar 依赖代码结构如图pojo 包request包response 包client 包server包编码解码基类代码说明测试服务端打印结果客户端打印结果总结介绍 由于HTTP协议的通用性&#xff…

使用js实现一个可以【放烟花】的小游戏

放烟花游戏需求&#x1f447;核心玩法&#x1f447;&#x1f447;界面原型&#x1f447;&#x1f447;成品演示&#x1f447;游戏开发1.游戏素材准备2.代码实现1.创建index.html页面2.首页-开始3.加载烟花音效4.重玩儿放烟花的小游戏。点击页面放烟花。兼容移动端。 游戏需求 …

作为普通网民,这些“实用电脑神器”,值得你知道

国内软件夹缝里求生存&#xff0c;由于某些不良软件&#xff0c;许多人对于国产软件认识多为“流氓、捆绑、多广告”&#xff0c;其实并非如此&#xff0c;下面几款让你刮目相看&#xff0c;扭转观念。 1、图片视频画质增强器 这是一款功能极其强大的图片与视频画质增强器&…

阿里云数据湖3.0解决方案两度登上InfoQ 2022年度榜单

经过一个多月的层层竞选&#xff0c;【阿里云数据湖 3.0 解决方案】从 130 多个方案中脱颖而出&#xff0c;荣获 InfoQ 2022 年度中国技术力量年度榜单《十大云原生创新技术方案》&《云原生十大场景化落地方案》双料大奖&#xff0c;这是头部技术媒体对阿里云存储的再一次认…

低代码是什么?有什么优势?一文看懂LowCode

低代码到底是什么&#xff1f;用最简单的方式告诉我&#xff1f;低代码是近两年来一个很热门的概念&#xff0c;尤其是疫情的影响&#xff0c;市场对低代码的需求不断增加&#xff0c;但到底什么是低代码&#xff1f;它到底有什么好处&#xff1f;这篇就为大家解答这个问题&…