- 抖动是录像软件的锅,并非渲染问题
- 项目的重点是库,不是渲染
A modern Tetris (pure) C language library, including
- Super Rotation System(SRS)
- Ghost piece
- API support for "Hold piece"
- API support for customized tetromino generator
- Random Generator("random bag" or "7 system")
- API support for garbage lines
- Block colors are supported
- Does NOT rely on any library
An example in windows terminal.
一个现代俄罗斯方块的纯c语言实现,具有以下游戏特性
- SRS旋转系统
- 影子显示(ghost piece)
- 支持Hold
- 支持自定义的发牌系统
- 内置7bag发牌系统
- 填充垃圾行
- 场景中可以有多种颜色
并且有下面的程序特性:
- 数据驱动,可以直接将
FTE_GAME
和FTE_7BAG
按照二进制传输或存储,游戏状态能够正常任意回退或前进 - 不依赖任何库、不存在动态内存申请和函数指针的行为,移植方便
提供一个样例程序main.c
,请在windows下使用cygwin
进行make
编译,运行时请使用powershell或cmd,也可以编译为控制台程序后直接双击运行。如果遇到乱码问题,请切换为支持Code Page 437
显示的字体。
libftetris.c
和libftetris.h
是实现srs系统的核心,受GPL许可证保护。
main.c
及makefile
是Windows下的控制台实现,其中除main函数外,都不依赖windows的接口。
这里是太长不看系列
游戏对象的初始化函数,参数是结构体指针,这个结构体用于存放游戏所需的全部数据
void fteGameInit(FTE_GAME * game);
你可以维护多个game对象,这在多人对战的时候会很有用。
比较理想的使用场景是,对象序列化后可以通过网络传输。
7 bag系统的初始化函数,也需要传一个结构体进去,还需要一个随机数种子,相同的随机数种子会产生相同的序列
void fte7BagInit(FTE_7BAG * bag,unsigned int seed);
下面的每个函数都会修改game对象的状态,你需要不断读取game中的一些数据并显示出来
fte_result_t fteRotLeft(FTE_GAME * game);
fte_result_t fteRotRight(FTE_GAME * game);
返回值有:
FTE_RESULT_MOVE_FAILED
旋转失败FTE_RESULT_MOVE_SUCCESS
旋转成功FTE_RESULT_MOVE_WALLKICK
踢墙旋转成功 请以此作为tspin奖励的判定依据
fte_result_t fteMoveLeft(FTE_GAME * game);
fte_result_t fteMoveRight(FTE_GAME * game);
fte_result_t fteMoveDown(FTE_GAME * game);
返回值有:
FTE_RESULT_MOVE_FAILED
移动失败FTE_RESULT_MOVE_SUCCESS
移动成功
建议将左右移动和下移交给用户去控制。你需要每隔一段时间调用一次fteMoveDown,以提供重力。如果调用返回FTE_RESULT_MOVE_FAILED
,说明到底了,此时请考虑根据情况生成下一个砖块。
反复调用fteMoveDown,直到返回FTE_RESULT_MOVE_FAILED
,可以作为HardDrop的实现。
fte_result_t fteSpawnNext(FTE_GAME * game,fte_tetromino_t next,int * clean_count /* OUTPUT parameter, line count of clean*/);
这个函数做三件事:
- (默认场上当前浮动的块是固定的)
- 清除场上已满的行
- 将缓存的垃圾行送上场
- 生成新的块
你需要指定下一个生成的方块next。它可以是:
#define FTE_TETROMINO_I 1
#define FTE_TETROMINO_O 2
#define FTE_TETROMINO_T 3
#define FTE_TETROMINO_S 4
#define FTE_TETROMINO_Z 5
#define FTE_TETROMINO_J 6
#define FTE_TETROMINO_L 7
建议通过7bag系统生成。
如果clean_count指针不是NULL,会将清除行的数量赋给这个地址。请以此作为消行的依据。
返回值为:
FTE_RESULT_MOVE_FAILED
新块正常产生FTE_RESULT_MOVE_SUCCESS
新块被挡住没法产生 请以此作为游戏结束的依据之一
fte_result_t fteReplaceCurrentTetromino(FTE_GAME * game,fte_tetromino_t new_tetromino);
替换场上当前的块为new_tetromino,可据此实现Hold功能。
void fteGameSetGhost(FTE_GAME * game,int isShow);
开关影子,影子的颜色是FTE_COLOR_GHOST
,直接被渲染在游戏场景中,请根据当前浮动的块来决定真正的颜色。
fte_tetromino_t fteGetCurrentTetromino(FTE_GAME * game);
void fteAddGarbage(FTE_GAME * game,fte_color_t garbage[FTE_WIDTH]);
增加一行垃圾行,garbage是一个由颜色组成的数组,需要至少有一个FTE_COLOR_NONE
,这个垃圾行会被缓冲起来,并不会立即上场。
fte_tetromino_t fte7BagGenItem(FTE_7BAG * bag);
不断调用这个函数,会产生不同的结果,它产生的值是下面之一:
#define FTE_TETROMINO_I 1
#define FTE_TETROMINO_O 2
#define FTE_TETROMINO_T 3
#define FTE_TETROMINO_S 4
#define FTE_TETROMINO_Z 5
#define FTE_TETROMINO_J 6
#define FTE_TETROMINO_L 7
且符合7bag系统的生成规律。你可以把这个值直接送给fteSpawnNext
函数,也可以放到一个队列里缓存起来,作为next显示的依据,然后再送给fteSpawnNext
。
游戏场景位于game对象的game.colors,是一个二维数组,默认长度为:[10][40]
,表示宽和高。建议通常需要绘制22行。
数组中每个元素为:
#define FTE_COLOR_NONE 0
#define FTE_COLOR_I 1
#define FTE_COLOR_O 2
#define FTE_COLOR_T 3
#define FTE_COLOR_S 4
#define FTE_COLOR_Z 5
#define FTE_COLOR_J 6
#define FTE_COLOR_L 7
#define FTE_COLOR_GARBAGE 8
#define FTE_COLOR_GHOST 9
其中FTE_COLOR_NONE
表示空白,其它的颜色都会进行碰撞检测(当FTE_COLOR_GHOST
不在正确的位置时,也会受到碰撞检测,所以请不要在开启影子的条件下自行修改color数组)。你可以根据不同的情况进行渲染,建议根据Tetris Guideline中的颜色进行绘制。颜色值可参考w3或其它类似标准。
本库并不是线程安全的,为了游戏少出BUG,并维持一个早睡早起的健康作息,请不要在多个线程上操作(修改)同一个game对象。
不同的线程可以同时操作不同的game对象,这会给联机同步提供极大的便利。