ESP32 俄罗斯方块
userHead Zoologist 2020-09-30 11:38:07

1984年,在当时还叫做苏联的那个国家的首都莫斯科,俄罗斯科学院(当然那时它也还叫做苏联科学院)总部计算机中心的一位工程师阿列克谢·帕基特诺夫开始考虑在计算机上自行开发一些简单的游戏,经过一段时间的尝试后,他通过另一款拼图游戏得到灵感,考虑让不同形状的图形依次下落,在矩形底部堆叠起来使之排列成完整的一行后消除,在另外两位同伴的协助下,他最终完成了这款被他命名为“Tetris”(俄语:Тетрис)的游戏,而我们今天更习惯叫它为“俄罗斯方块”。1984年6月6日,是公认的俄罗斯方块诞生纪念日,游戏最初由苏联科学院计算中心的工程师阿列克谢·帕基特诺夫开发,他当时从另一款拼图游戏得到灵感。

projectImage

根据另一位当事人的回忆,“Tetris”这个单词是阿列克谢自己发明并坚持使用的,来自反映俄罗斯方块图案基本结构的“四”(希腊语:tetra)和阿列克谢自己最喜爱的运动“网球”(tennis)的组合。《俄罗斯方块》的原名“Tetris”(俄语:Тетрис)是发明者阿列克谢·帕基特诺夫自己生造出来的单词,来自反映俄罗斯方块图案基本结构的“四”(希腊语:tetra)和阿列克谢自己最喜爱的运动“网球”(tennis)的组合。 

projectImage

公认的第一款俄罗斯方块原始程序诞生于 1984 年 6 月 6 日,在当时苏联仿制的 Elektronika 60 计算机上运行,因为这款计算机不能显示色块图案,原始版本只能用字符串来表示图形,但即便这样它也体现出了游戏本身的魅力,阿列克谢和他身边的朋友们很快都开始为之沉迷。1985 年,开发同伴之一的瓦丁·格拉西莫夫在 MS-DOS 下移植了俄罗斯方块,让更多的个人电脑可以运行,游戏得以迅速的普及。   

阿列克谢起初希望能合法贩卖俄罗斯方块游戏,但在苏联当时的制度下这十分困难,几经尝试都失败后,阿列克谢表示可以考虑把游戏版权交给国家——当时的苏联科学院。而在诞生后的数年时间里,俄罗斯方块一直都以免费拷贝的形式传播,从苏联扩展到了整个欧洲,也引起了更多人的注意。

projectImage

第一个俄罗斯方块的程序在苏联仿制的 Elektronika 60 计算机上运行,因为无法显示色块只能用字符来表示图形,之后一年游戏移植了 MS-DOS 版,而这一版首次呈现出的图案画面也成为之后三十年来的游戏基础,甚至没有太多变化。  

1986 年匈牙利的程序员在 Apple II 和 Commodore 64 上移植了游戏,英国游戏公司 Andromeda 的一位经理人罗伯特·斯坦恩注意到了这个商机,他开始联系阿列克谢以及匈牙利的程序员试图购买俄罗斯方块的版权,并在确定到手之前就把它分别卖给了英国的游戏公司 Mirrorsoft 和美国的游戏公司 Spectrum Holobyte,从而导致了接下来整整十余年时间关于俄罗斯方块的版权之争,甚至可以说改变了游戏发展史的一连串事件。” 上述文字节选自《三十年成就经典传奇 发展史》【参考1】 

这次使用 ESP32 搭配 ILI9341(240*320)来实现一个掌上俄罗斯方块游戏机。

硬件清单
1x
DFRobot TinkerNode
1x
电路板
1x
PS2 方向键
1x
ILI9341 控制器
1x
TFT 屏幕
1x
排母若干
1x
螺丝若干

使用到的硬件  

DFRobot 的 TinkerNode ESP32 开发板,选择原因是它自带电源管理芯片,可以方便的使用 18650 充电电池,同时 ESP32 提供了强大的接口(SPI 轻松达到 40Mhz)和性能(核心可达 240Mhz);中景园的 ILI9431 TFT 显示屏;以及一个用于控制的 PS2 摇杆,模拟输出 XY 四个方向以及一个开关按钮。


使用到的软件

使用 Arduino IDE 进行编辑。项目参考了开源设计 。删除了项目中的串口控制和网络部分,修改为通过 PS2 摇杆控制,另外加入了分数显示和现实下一个的功能。


详细描述

1. ILI9341 的显示控制,最终选择使用 Adafruit_GFX 的显示库;特别注意这个库对 ESP32 有兼容性问题,通过修改 \Adafruit_BusIO\Adafruit_SPIDevice.cpp 这个文件解决: 

/*! * @brief Transfer (send/receive) one byte over hard/soft SPI * @param buffer The buffer to send and receive at the same time * @param len The number of bytes to transfer */ void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) { if (_spi) { // hardware SPI is easy //LABZDebug _spi->transfer(buffer, len); _spi->transferBytes(buffer,NULL,len); //LABZDebug return; } 

2. 修改 IL9341 的库兼容代码,增加了一个填充图像的函数 

void Adafruit_ILI9341::fillImage(void *image, int x, int y, int w, int h) { //drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w,int16_t h), Adafruit_SPITFT::drawRGBBitmap(x, y,(uint16_t *)image, w, h); } 

3. 增加了一个计分功能,每次消除行的时候,进行分数计算,具体在 DeleteLine() 函数中的 if (DeleteCount!=0) {score+=DeleteCount*DeleteCount;}2 

4. 增加了根据分数控制速度的机制,下降速度控制在 GetNextPosRot() 函数中:if ((millis()-TimeElsp)>Score2Level()) {pnext_pos->Y += 1;TimeElsp=millis();}Score2Level() 函数返回当前分数对应的延时,分数越高下落速度会越快;  

5. 显示“下一个” 的功能。设计在了 Draw() 函数中,出于对效率的考虑只有在下一个有变化的时候才会进行显示更新。同时,这里面还有一个特别的地方,比如,我们定义了一个 image[20][20] 的图像,但是我们想将它里面 10 x 20 的内容显示出来是不可以直接使用 tft.fillImage 的,因为这个函数会默认将显示Buffer 认为是 20x20 大小的,因此会出现混乱。 

ESP32 俄罗斯方块电路图 

projectImage

ESP32 俄罗斯方块 PCB 

projectImage

关于作者

Zoologist 来自 Arduino 中文社区,爱好使用 Arduino 制作各种有趣的东西。

联系我们
联系邮箱:makercarnival@hotmail.com
官方微信公众号:创客嘉年华
官方微博:上海创客嘉年华
© Copyright Zhiwei Robotics Corp. All Rights Reserved
code 上海创客嘉年华