C语言俄罗斯方块时钟

C语言俄罗斯方块时钟

这个小程序是因为在某宝上看见一款点阵屏俄罗斯方块时钟,感觉很有意思就想在自己的stm32f469开发板上抄袭一下,看看效果,大家想玩一玩的可以参考一下,核心代码在下面。

先看一下效果图

在这里插入图片描述当时间改变,每个数字是由小的俄罗斯方块逐渐累加起来的,不是视频看不到效果。

下面是一些const数据用来定义俄罗斯方块基础形状及每个数字下落的方块序列


/* config  grid */
#define GRID_SIZE               14
#define GRID_ROW_NUM            (RK043FN48H_HEIGHT/GRID_SIZE-6)
#define GRID_COL_NUM            (RK043FN48H_WIDTH/GRID_SIZE-1)

/* config number and colon position */
#define NUMBER_COUNT            4
#define FIRST_NUMBER_OFFSET     1
#define SECOND_NUMBER_OFFSET    8
#define THIRD_NUMBER_OFFSET     18
#define FOURTH_NUMBER_OFFSET    25
#define COLON_OFFSET_X          15
#define COLON_OFFSET_Y          5

uint16_t u16GridMap[GRID_ROW_NUM * GRID_COL_NUM];
uint8_t u8ClockNumber[NUMBER_COUNT+1] = {0, 0, 0, 0, 0};
stTetrisClockHandle stTetrisNumHandle[NUMBER_COUNT];
struct tm *p_tm;

const uint32_t u32ColorRgb565Table[] =
{
    SCRLET           ,
    CAMEL            ,
    SUN_ORANGE       ,
    LAWN_GREEN       ,
    FOREST_GREEN     ,
    MARINE_BLUE      ,
    CHROME_YELLOW    ,
    DARK_SLATE_BLUE  ,
    CAYN_BLUE        ,
    RUBY             ,
    MIDIUM_TURQUOISE ,
    VERIDIAN         ,
    LIGHT_LIME       ,
    INDIAN_RED       ,
    MAROON           ,
    MISTY_ROSE       ,
    LIGHT_CORAL      ,
    HELIOTROPE       ,
};

const stNumSeqBase au8NumZeroTerisSeq[] =
{
    {18, 3}, {4,  1}, {9, 3}, {9, -1}, {5, 0}, {5, 4}, {5, 4}, {11, 0}, {0,  0}, {9,  0},
    {6,  2}, {19, 4}
};
const stNumSeqBase au8NumOneTerisSeq[] =
{
    {3, 4}, {17, 3}, {19, 4}, {17, 3}, {19, 4}
};
const stNumSeqBase au8NumTwoTerisSeq[] =
{
    {18, 3}, {14, 0}, {1, 1}, {2, 4}, {18, 3}, {14, 0}, {1, 1}, {2, 4}, {2,  2}, {0,  1}, {0, 0}
};
const stNumSeqBase au8NumThreeTerisSeq[] =
{
    {18, 3}, {14, 0}, {1, 1}, {0, 5}, {19, 3}, {14, 0}, {1, 1}, {2, 4}, {1,  1}, {12, 3}, {16, 0}
};
const stNumSeqBase au8NumFourTerisSeq[] =
{
    {2, 4}, {2, 4}, {2, 0}, {2, 0}, {18, 3}, {14, 0}, {1, 1}, {2, 4}, {2, 4}
};
const stNumSeqBase au8NumFiveTerisSeq[] =
{
    {2, 4, 8}, {2, 2, 8}, {0, 1}, {0, 0}, {1, 1}, {16, 0, 4}, {12, 3}, {2, 4}, {1, 1}, {12, 3},
    {16, 0}
};
const stNumSeqBase au8NumSixTerisSeq[] =
{
    {2, 4, 8}, {2, 2, 8}, {0, 1}, {0, 0}, {1, 1}, {16, 0}, {12, 3}, {2, 4}, {2, 0}, {1, 1},
    {12, 3},{16, 0}
};
const stNumSeqBase au8NumSevenTerisSeq[] =
{
    {18, 3}, {14, 0}, {1, 1}, {17, 3}, {0, 5}, {13, 3}, {2, 4}
};
const stNumSeqBase au8NumEightTerisSeq[] =
{
    {15, 4}, {1, 0}, {1, 1}, {7, 4}, {7, 0}, {16, 0}, {12, 1}, {9, 3}, {7, 0}, {12, 2}, {0, 5},
    {9, -1},{1, 1}
};
const stNumSeqBase au8NumNineTerisSeq[] =
{
    {10, 2}, {4, 0}, {5, 4}, {9, -1}, {12, 2}, {0, 5}, {5, 0}, {1, 1}, {2, 4}, {1, 2}, {1, 2}, {2, 0}
};

const stNumSeqBase *stNumSeqArrayTable[] =
{
    au8NumZeroTerisSeq  ,
    au8NumOneTerisSeq   ,
    au8NumTwoTerisSeq   ,
    au8NumThreeTerisSeq ,
    au8NumFourTerisSeq  ,
    au8NumFiveTerisSeq  ,
    au8NumSixTerisSeq   ,
    au8NumSevenTerisSeq ,
    au8NumEightTerisSeq ,
    au8NumNineTerisSeq  ,
};

const uint16_t u16NumSeqArraySize[] =
{
    sizeof(au8NumZeroTerisSeq )/sizeof(stNumSeqBase),
    sizeof(au8NumOneTerisSeq  )/sizeof(stNumSeqBase),
    sizeof(au8NumTwoTerisSeq  )/sizeof(stNumSeqBase),
    sizeof(au8NumThreeTerisSeq)/sizeof(stNumSeqBase),
    sizeof(au8NumFourTerisSeq )/sizeof(stNumSeqBase),
    sizeof(au8NumFiveTerisSeq )/sizeof(stNumSeqBase),
    sizeof(au8NumSixTerisSeq  )/sizeof(stNumSeqBase),
    sizeof(au8NumSevenTerisSeq)/sizeof(stNumSeqBase),
    sizeof(au8NumEightTerisSeq)/sizeof(stNumSeqBase),
    sizeof(au8NumNineTerisSeq )/sizeof(stNumSeqBase),
};

//这个是俄罗斯方块在一个9x9像素点中的坐标
//就是这样(x,x)(x,x)(x,x)(x,x),每个坐标2bit, 组成一个16bit数据
const uint16_t u16BasicModelTable[20] = {
    /*  #
     *  #
     *  #
     *  #
     */
    0xC840,/* 0 */
    /*  # # # #
     */
    0x3210,/* 1 */
    /*  # #
     *  # #
     */
    0x5410,/* 2 */
    /*  # #
     *  # #
     */
    0x5410,/* 3 */
    /*  # #
     *    # #
     */
    0x6510,/* 4 */
    /*    #
     *  # #
     *  #
     */
    0x8541,/* 5 */
    /*    # #
     *  # #
     */
    0x5421,/* 6 */
    /*  #
     *  # #
     *    #
     */
    0x9540,/* 7 */
    /*    #
     *  # # #
     */
    0x6541,/* 8 */
    /*  #
     *  # #
     *  #
     */
    0x9651,/* 9 */
    /*  # # #
     *    #
     */
    0x9654,/* 10 */
    /*    #
     *  # #
     *    #
     */
    0x9541,/* 11 */
    /*      #
     *  # # #
     */
    0x6542,/* 12 */
    /*  #
     *  #
     *  # #
     */
    0xA951,/* 13 */
    /*  # # #
     *  #
     */
    0x8654,/* 14 */
    /*  # #
     *    #
     *    #
     */
    0x9510,/* 15 */
    /*  #
     *  # # #
     */
    0x6540,/* 16 */
    /*  # #
     *  #
     *  #
     */
    0x9521,/* 17 */
    /*  # # #
     *      #
     */
    0xA654,/* 18 */
    /*    #
     *    #
     *  # #
     */
    0x9851, /* 19 */
};

下面是显示的main函数,10ms调用周期,可以自己改,把对应延时设置好就可以。

void tetris_main(void)
{
    static uint8_t u8LastSec = 0xff;
    static uint8_t u8LastDay = 0xff;
    static uint32_t u8AnimDelay = 0;
    stTetrisClockHandle *handle = NULL;
    uint32_t u32RandomColor = 0;
    int16_t xx, yy;
    uint8_t u8RandomNum = 0;

    uint8_t u8MinuteChange = TetrisClockUpdateTime(u8ClockNumber);
    if (u8MinuteChange) {
        /* clean screen and grid map */
        BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
        BSP_LCD_FillRect(0, 0, RK043FN48H_WIDTH, 200);
        rt_memset(u16GridMap, 0, sizeof(u16GridMap));

        /* init handle */
        for (uint16_t i = 0; i < NUMBER_COUNT; i++) {
            handle = &stTetrisNumHandle[i];
            u8RandomNum = HAL_RNG_GetRandomNumber(&hrng);

            /* set clock number offset */
            (i == 0) && (handle->u16TerisXOffset = FIRST_NUMBER_OFFSET);
            (i == 1) && (handle->u16TerisXOffset = SECOND_NUMBER_OFFSET);
            (i == 2) && (handle->u16TerisXOffset = THIRD_NUMBER_OFFSET);
            (i == 3) && (handle->u16TerisXOffset = FOURTH_NUMBER_OFFSET);

            /* init paramter */
            handle->pNumSeq = stNumSeqArrayTable[u8ClockNumber[i]];
            handle->u8SeqIdx = u16NumSeqArraySize[u8ClockNumber[i]] - 1;
            handle->u32TerisColor = u32ColorRgb565Table[u8RandomNum % (sizeof(u32ColorRgb565Table)/sizeof(uint32_t))];
            handle->u16TerisMode = u16BasicModelTable[handle->pNumSeq[handle->u8SeqIdx].u8ModeIdx];
            handle->u16TerisX = handle->pNumSeq[handle->u8SeqIdx].u8DefX + handle->u16TerisXOffset;
            handle->u16TerisY = 0;
            handle->u8EndFlag = 0;
        }
    }

    /* delay 80 ms */
    if (++u8AnimDelay % 8 == 0) {
        /* draw clock number loop */
        for (uint16_t i = 0; i < NUMBER_COUNT; i++) {
            handle = &stTetrisNumHandle[i];

            /* update next tetris mode */
            if (handle->u8EndFlag) {
                if (handle->u8SeqIdx == 0)
                    continue;

                u8RandomNum = HAL_RNG_GetRandomNumber(&hrng);
                handle->u8SeqIdx--;
                handle->u32TerisColor = u32ColorRgb565Table[u8RandomNum % (sizeof(u32ColorRgb565Table)/sizeof(uint32_t))];
                handle->u16TerisMode = u16BasicModelTable[handle->pNumSeq[handle->u8SeqIdx].u8ModeIdx];
                handle->u16TerisX = handle->pNumSeq[handle->u8SeqIdx].u8DefX + handle->u16TerisXOffset;
                handle->u16TerisY = 0;
                handle->u8EndFlag = 0;
            }

            /* clear last tetris base mode */
            for (uint16_t i = handle->u16TerisMode; xx = handle->u16TerisX + (i&0x3), yy = handle->u16TerisY + ((i>>2)&0x3), i; i >>= 4)
            {
                u16GridMap[yy * GRID_COL_NUM + xx] = 0;
                DrawTetrisRect(xx, yy, GRID_SIZE, GRID_SIZE, LCD_COLOR_BLACK, LCD_COLOR_BLACK);
            }

            /* down */
            down(handle);

            /* draw new tetris base mode */
            for (uint16_t i = handle->u16TerisMode; xx = handle->u16TerisX + (i&0x3), yy = handle->u16TerisY + ((i>>2)&0x3), i; i >>= 4)
            {
                u16GridMap[yy * GRID_COL_NUM + xx] = 1;
                DrawTetrisRect(xx, yy, GRID_SIZE, GRID_SIZE, handle->u32TerisColor, LCD_COLOR_BLACK);
            }
        }
    }

    /* flash colon */
    if (u8LastSec != u8ClockNumber[NUMBER_COUNT]) {
        /* get random color */
        u8RandomNum = HAL_RNG_GetRandomNumber(&hrng);
        u32RandomColor = u32ColorRgb565Table[u8RandomNum % (sizeof(u32ColorRgb565Table)/sizeof(uint32_t))];

        for (uint16_t i = u16BasicModelTable[2]; xx = COLON_OFFSET_X + (i&0x3), yy = COLON_OFFSET_Y + ((i>>2)&0x3), i; i >>= 4) {
            if (u8LastSec%2 == 0) {
                DrawTetrisRect(xx, yy, GRID_SIZE, GRID_SIZE, u32RandomColor, LCD_COLOR_BLACK);
                DrawTetrisRect(xx, yy+4, GRID_SIZE, GRID_SIZE, u32RandomColor, LCD_COLOR_BLACK);
            } else {
                DrawTetrisRect(xx, yy, GRID_SIZE, GRID_SIZE, LCD_COLOR_BLACK, LCD_COLOR_BLACK);
                DrawTetrisRect(xx, yy+4, GRID_SIZE, GRID_SIZE, LCD_COLOR_BLACK, LCD_COLOR_BLACK);
            }
        }

        u8LastSec = u8ClockNumber[NUMBER_COUNT];
    }

    /* update calendar */
    if (u8LastDay != p_tm->tm_mday) {
        /* show calendar */
        const char* str;
        str = solar_calendar(p_tm->tm_mon+1, p_tm->tm_mday, p_tm->tm_wday);
        show_str(170, 205, 200, 16, (uint8_t*)str, CH_FONT16);
        str = lunar_calendar(p_tm->tm_year+1900, p_tm->tm_mon+1, p_tm->tm_mday);
        show_str(170, 224, 440, 16, (uint8_t*)str, CH_FONT16);
        u8LastDay = p_tm->tm_mday;
    }
}

其他几个函数用来更新俄罗斯方块下落后的坐标,及获取时间还有画每个小方块的函数,
画图和获取时间的函数用到了其他接口,可以根据自己的工程修改。

static void DrawTetrisRect(uint16_t TetrisX, uint16_t TetrisY, uint16_t Width, uint16_t Height,
        uint32_t Fcolor, uint32_t Bcolor)
{
    BSP_LCD_SetTextColor(Fcolor);
    BSP_LCD_FillRect(TetrisX*(Width+1), TetrisY*(Height+1), Width, Height);
    if (Fcolor != Bcolor) {
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DrawRect(TetrisX*(Width+1), TetrisY*(Height+1), Width-1, Height-1);
    }
}

static uint8_t TetrisClockUpdateTime(uint8_t *data)
{
    static uint8_t u8LastMinute = 0xff;
    uint8_t u8MinuteChange = 0;
    rt_device_t rtc_dev = NULL;
    time_t time_stamp = 0;

    rtc_dev = rt_device_find("rtc");
    if (rtc_dev != NULL) {
        rt_device_control(rtc_dev, RT_DEVICE_CTRL_RTC_GET_TIME, &time_stamp);
    }

    p_tm = localtime(&time_stamp);
    //rt_kprintf("year %d day %d h:%d m:%d\n", p_tm->tm_year, p_tm->tm_mday, p_tm->tm_hour, p_tm->tm_min);

    data[0] = p_tm->tm_hour/10%10;
    data[1] = p_tm->tm_hour%10;
    data[2] = p_tm->tm_min/10%10;
    data[3] = p_tm->tm_min%10;
    data[4] = p_tm->tm_sec;

    if (u8LastMinute != p_tm->tm_min) {
        u8LastMinute = p_tm->tm_min;
        u8MinuteChange = 1;
    }

    return u8MinuteChange;
}
void down(stTetrisClockHandle *handle)
{
    int16_t xx, yy;

    handle->u16TerisY += 1;
    for (uint16_t i = handle->u16TerisMode; xx = handle->u16TerisX + (i&0x3), yy = handle->u16TerisY + ((i>>2)&0x3), i; i >>= 4)
    {
        if (yy >= GRID_ROW_NUM-handle->pNumSeq[handle->u8SeqIdx].u8DefY|| u16GridMap[yy * GRID_COL_NUM + xx]) {
            /* crash bottom */
            handle->u16TerisY -= 1;
            handle->u8EndFlag = 1;
        }
    }
}

头文件

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-08-06     Administrator       the first version
 */
#ifndef APPLICATIONS_TETRIS_TETRIS_CLOCK_H_
#define APPLICATIONS_TETRIS_TETRIS_CLOCK_H_

#include <stdint.h>
#include <stdlib.h>

#include <rtthread.h>
#include "main.h"


#define SCRLET              0xFF2400
#define CAMEL               0xA16B47
#define SUN_ORANGE          0xFF7300
#define LAWN_GREEN          0x7CFC00
#define FOREST_GREEN        0x228B22
#define MARINE_BLUE         0x00477D
#define CHROME_YELLOW       0xFFD700
#define DARK_SLATE_BLUE     0x483D8B
#define CAYN_BLUE           0x0DBF8C
#define RUBY                0xCC0080
#define MIDIUM_TURQUOISE    0x48D1CC
#define VERIDIAN            0x127436
#define LIGHT_LIME          0xCCFF00
#define INDIAN_RED          0xCD5C5C
#define MAROON              0x800000
#define MISTY_ROSE          0xFFE4E1
#define LIGHT_CORAL         0xF08080
#define HELIOTROPE          0x5000B8

typedef struct{
    uint8_t u8ModeIdx;
    int8_t u8DefX;
    int8_t u8DefY;
    int8_t u8BottomOffset;
}stNumSeqBase;

typedef struct{
    const stNumSeqBase *pNumSeq;
    uint16_t u16TerisMode;
    uint16_t u16TerisX;
    uint16_t u16TerisXOffset;
    uint16_t u16TerisY;
    uint32_t u32TerisColor;
    uint8_t u8SeqIdx;
    uint8_t u8EndFlag;
}stTetrisClockHandle;

extern RNG_HandleTypeDef hrng;

void tetris_main(void);

#endif /* APPLICATIONS_TETRIS_TETRIS_CLOCK_H_ */
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值