C语言2048项目(全解注释-手把手教会)

00简介:

0.1:演示:

0.2:游戏说明:

玩家通过滑动屏幕来将相同数字合并并生成新的方块,并努力生成2048方块。

1.项目说明:


1.1项目主题:


本项目的主题是创建一个基于C语言的2048游戏,运用二维数组来管理2048棋盘,实现棋盘的灵活移动。同时,通过相同方块合并机制,让各个方块进行滑动合并生成新的方块,实现游戏的核心逻辑。

1.2技术实现:


项目采用C语言作为开发语言,整个游戏的设计主要包含以下几个方面的知识和技术实现:

二维数组的运用:

使用二维数组来存储棋盘的每个格子,每个格子包含着产生的格子信息。这种结构能够方便地实现2048滑动合并等操作。


枚举类型的设计:

通过定义枚举类型touchEvent,touchType;,管理方块滑动的方向,允许程序在不同情况下执行不同的逻辑,使代码更加清晰和易于管理。


游戏逻辑的实现:

实现了方块的滑动逻辑、方块的生成与合并逻辑等。特别是通过方块滑动函数来判断是否有相同的方块可以合并。


用户交互:

采用触摸屏滑动方式,用户通过滑动屏幕来控制方块的滑动方向。结合动态刷新界面和动画效果,增强了用户的游戏沉浸感。
 

1.3项目框架:


项目的整体框架分为几个模块,包括:

棋盘和方块模块:负责定义整个二维数组棋盘和每个方块的值,以及相关的方块合并生成函数。
游戏逻辑模块:处理棋盘状态的更新,包括方块的滑动、合并逻辑、方块生成、以及游戏得分的计算。
用户交互模块:管理用户的滑动,响应触摸事件,并实时更新棋盘。
初始化与资源管理模块:负责初始化游戏设置,例如棋盘的初始状态和速度,并管理游戏过程中的资源


1.4项目开发工具:


本项目在Ubuntu Linux环境下进行开发,主要使用以下工具和技术:

开发环境:

代码编辑器:使用 Visual Studio Code (VSCode) 作为主要的代码编辑器。VSCode 提供了丰富的插件和调试支持,极大提高了开发效率。
编译工具链:使用 arm-linux-gcc 编译器针对 ARM 架构进行编译。此编译器适用于嵌入式系统,可以将 C 代码编译为适合 ARM 处理器的可执行文件。
文件管理:

项目文件通过 NFS (网络文件系统) 共享到目标开发板。这一方式允许开发者在本地机器上进行开发与测试,同时能够方便地将代码同步到开发板进行实际运行。
在 NFS 的配置中,确保设置合适的权限,以便于无障碍地访问和修改共享的项目文件。

2.项目实现:


2.1项目整体架构:

void _2048Play(void)
{
    // 显示2048棋盘图片
    showRandBmp();
    // 初始化2048 把4*4的数组全部赋值为0
    memset(_2048ChessBoard, 0, sizeof(_2048ChessBoard));
    // 初始化_2048GameOverFlag为false
    _2048GameOverFlag = false;
    // 重置棋盘 重置分数 重置change dir _2048GameScore _2048AddScore 重新播放音乐
    _2048Restart(_2048ChessBoard);
    //判断用户是否触摸了棋盘
    bool isTouchFlag = 0;
    while (1)
    {
        // 规定触摸范围在2048以内
        if ()
        {
            isTouchFlag = true;
        }
        //当产生触摸事件时,dir赋值
        if (isTouchFlag)
        {
            isTouchFlag = false;
            dir = touchResult.touchEventResult;
        }

        // 判断上下左右
        switch (dir)
        {
        case up_to_down:
            memset(&touchResult, 0, sizeof(touchType));

            dir = no_event; // 置零
            // 从上往下滑
            _2048_Up_To_Down(_2048ChessBoard);

            break;
        case 2:
            memset(&touchResult, 0, sizeof(touchType));

            dir = 0; // 置零
            // 从下往上滑
            _2048_Down_To_Up(_2048ChessBoard);

            break;
        case 3:
            memset(&touchResult, 0, sizeof(touchType));

            dir = 0; // 置零
            // 从左往右滑
            _2048_Left_To_Right(_2048ChessBoard);

            break;
        case 4:
            memset(&touchResult, 0, sizeof(touchType));

            dir = 0; // 置零
            // 从右往左滑
            _2048_Right_To_Left(_2048ChessBoard);

            break;

        default:

            break;
        }
        // 打印棋盘
        _2048PrintfChess(_2048ChessBoard);

        // 当游戏结束时赋值为1 并且图片显示GameOver 用户再次点击重置时再刷新
        _2048GameOver(_2048ChessBoard);

        // 判断是否点了重置
        if ()
        {
            // 置零触摸事件
            memset(&touchResult, 0, sizeof(touchType));
            // 2048重置函数
            _2048Restart(_2048ChessBoard);
        }

        // 返回检测 时间变量掐掉  音乐变量掐掉 界面标识符设置为3
        if ()
        {
            // 触摸事件置零
            memset(&touchResult, 0, sizeof(touchType))
            // 2048重置以便下次进入游戏是刷新游戏的状态
            _2048Restart(_2048ChessBoard);
            break;
        }
    }
}

2.2 主要功能模块及API


 2.2.1棋盘与数据结构:

// 触摸滑屏事件enum
typedef enum touchEvent
{
    no_event = 0,
    up_to_down = 1,    // 从上往下滑
    down_to_up = 2,    // 从下往上滑
    left_to_right = 3, // 从左往右滑
    right_to_left = 4, // 从右往左滑
} touchEvent;

// 触摸事件
typedef struct touchType
{
    int touchX;                  // 触摸事件X
    int touchY;                  // 触摸事件Y
    touchEvent touchEventResult; // 滑屏事件
} touchType;


// 初始化2048 把4*4的数组全部赋值为0
int _2048ChessBoard[4][4] = {0};

2.2.2游戏初始化


全局变量设置:

// _2048ChessBoardChangeFlag记录数组变化,变化了就打印数组
// _2048GameOverFlag 游戏结束标志,当游戏结束时赋值为1 并且图片显示GameOver 用户再次点击重置时再刷新
bool _2048ChessBoardChangeFlag = false, _2048GameOverFlag = false;
// dir 记录滑屏事件 switch判断dir来调用上下左右函数
int dir = no_event;
// _2048GameScore记录总分  在每次两个for循环跳出来后加上_2048AddScore  有变化时,刷新字库 退出或者新游戏重置为0
//  _2048AddScore 记录每次的分数 在每次棋子变化加上新棋子
int _2048GameScore = 0, _2048AddScore = 0;


游戏初始化:

  

    // 显示2048游戏界面
    showRandBmp(display(interface_List_head, 5), 0, 0);
    // 显示用户名
    writeFontProMax(currentUser.name, 575, 15, 100, 40, 0, 0);
    // 初始化2048 把4*4的数组全部赋值为0
    memset(_2048ChessBoard, 0, sizeof(_2048ChessBoard));
    // 初始化_2048GameOverFlag为false
    _2048GameOverFlag = false;
    // 重置棋盘 重置分数 重置change dir _2048GameScore _2048AddScore 重新播放音乐
    _2048Restart(_2048ChessBoard);
    //判断用户是否触摸了棋盘
    bool isTouchFlag = 0;

重置棋盘_2048Restart()函数API:

/// @brief 重置棋盘
/// @param _2048ChessBoard 棋盘
void _2048Restart(int _2048ChessBoard[][4])
{

    // 重置棋盘 重置分数 重置change dir _2048GameScore  _2048AddScore 重新播放音乐

    // 重置棋盘, 初始化2048 把4*4的数组全部赋值为0
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            _2048ChessBoard[i][j] = 0;
        }
    }

    // 初始化2048 把4*4的数组全部赋值为0
    memset(_2048ChessBoard, 0, sizeof(&_2048ChessBoard));
    // 重新打印空棋盘
    showRandBmp(display(interface_List_head, 501), 0, 0);
    // 重置滑动方向
    dir = 0;
    // 重置累加分数
    _2048AddScore = 0;
    // 重置用户得分
    writeFontProMax("0", 615, 225, 80, 40, 0, 0);
    _2048GameScore = 0;
    _2048GameOverFlag = false;
    _2048ChessBoardChangeFlag = true;
    // 随机刷新一个棋子
    _2048RandChess(_2048ChessBoard);
    // 这里总共要刷新两个棋子,但是这里注释掉这句原因是_2048PrintfChess还有再调用一次随机刷新棋子
    //  _2048RandChess(_2048ChessBoard);
    // 打印重置后的棋盘
    _2048PrintfChess(_2048ChessBoard);
    // 棋盘刷新标志置为false
    _2048ChessBoardChangeFlag = false;
}

2.2.3 2048方块滑动合并逻辑

1.触摸线程函数不断返回触摸事件:

/// @brief 触摸线程,不断扫描屏幕触摸信息,并返回触摸事件
/// @param arg 线程号
/// @return 无
void *touchThread(void *arg)
{

    int endX = 0, endY = 0, startX = 0, startY = 0;
    struct input_event ts;

    memset(&ts, 0, sizeof(struct input_event));
    while (1)
    {
        // 读触摸屏
        read(touch_fd, &ts, sizeof(struct input_event));
        // 决断是否为相对坐标类型
        if (ts.type == EV_ABS && ts.code == ABS_X)
        {

            endX = ts.value;
            touchResult.touchX = ts.value * (800.0 / 1024.0);
        }
        // 决断是否为相对坐标类型
        if (ts.type == EV_ABS && ts.code == ABS_Y)
        {

            endY = ts.value;
            touchResult.touchY = (int)(ts.value * (480.0 / 600.0));
        }
        // 表示手指按下
        if (ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 1)
        {
            // 记录起点坐标
            startX = endX;
            startY = endY;
        }

        // 表示手指松开
        if (ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 0)
        {
            // 坐标换算  起点坐标
            startX = startX * (800.0 / 1024.0);
            startY = startY * (480.0 / 600.0);
            // 坐标换算  结束坐标
            endX = endX * (800.0 / 1024.0);
            endY = endY * (480.0 / 600.0);

            // 判断是左右滑还是上下滑
            if (abs(startX - endX) > abs(startY - endY))
            {
                if ((startX - endX) > 100)
                {

                    touchResult.touchEventResult = right_to_left;
                }
                if ((endX - startX) >= 100)
                {

                    touchResult.touchEventResult = left_to_right;
                }
            }
            else
            {
                if ((startY - endY) > 50)
                {

                    touchResult.touchEventResult = down_to_up;
                }
                if ((endY - startY) >= 50)
                {

                    touchResult.touchEventResult = up_to_down;
                }
            }
        }
    }
    return 0;
}


2.判断滑动方向:

  


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值