具有4x 8x8点矩阵的Arduino Nano的跌落块(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/falling-blocks-on-an-arduino-nano-with-4x-8x8-dot-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 35 分钟阅读 - 17470 个词 阅读量 0具有4x 8x8点矩阵的Arduino Nano的跌落块(译文)
原文地址:https://www.codeproject.com/Articles/5276729/Falling-Blocks-on-an-Arduino-Nano-with-4x-8x8-dot
原文作者:Christ Kennedy
译文由本站 robot-v1.0 翻译
前言
here’s how I made a game of Falling Blocks with my Arduino Nano, a clothes hanger and some duct tape
这是我使用Arduino Nano,衣架和一些胶带制作掉落游戏的方法
Falling Blocks is great! Used to play it at the pub back in the day. Yea, its old. I know. but what the heck? This project took me one week from start to finish - and I only worked on it a few hours each day. Things went fairly well. No major complications … just : code, debug, test, fix and repeat until I was done.
掉落块很棒!过去曾经在酒吧里玩.是的,它很旧.我知道.但是到底是什么?这个项目从头到尾花了我一个星期的时间,而且我每天只花几个小时.一切进展顺利.没有大的复杂性^只是:代码,调试,测试,修复和重复直到完成.
- 下载Falling Blocks_20200818_1552.zip-9.4 KB(Download Falling Blocks_20200818_1552.zip - 9.4 KB) 最终项目的源代码(source code of final project)
- 下载Falling Blocks_FSMs_20200818_1551.zip-10 KB(Download Falling Blocks_FSMs_20200818_1551.zip - 10 KB) 删除FSM之前的源代码(source code before FSMs were removed)
- 下载Scrolling_Text_20200818_807.zip-3.4 KB(Download Scrolling_Text_20200818_807.zip - 3.4 KB)
介绍(Introduction)
自从23年前的计算机工程专业第二年起,我就再也没有做过任何电子方面的事情了,直到去年秋天我订购了Arduino Starter-Kit并热切期盼它的到来.我什至不知道我订购了什么,没有意识到(I had never done anything ‘electronic’-cky since my second year of Computer Engineering over 23 years ago until I ordered an Arduino Starter-Kit late last fall and eagerly anticipated its arrival. I didn’t even know what I had ordered, not realizing)Arduino的(Arduino)是一个微控制器,我以为我会得到一堆晶体管,二极管和LED.但是,瞧,就在那儿,我在邮件中发现的那个破损的塑料盒中,与所有其他小部件相比,它们都显得苍白了.(was a MicroController, I thought I was going to get a bunch of transistors, diodes and LEDs. But lo and behold, there it was, right there in the broken plastic box I got in the mail along with all the other widgets that pale in comparison to the)Arduino Uno(Arduino Uno).(.) 我参加了在线初学者课程(I took an on-line beginner’s class with) 乌迪米(Udemy) 和火花飞扬…从字面上看.(and sparks flew … literally.) 我已经买了很多在线(I’ve bought a lot of on-line)Arduino的(Arduino)从此开始.来自中国的慢船花了几个月的痛苦才能最终到达这里.然后发生了加拿大太平洋铁路封锁,这进一步阻碍了我的小小的掘金队在我们都被电晕病毒袭击之前到达他们幸福的家.因此,我去了加拿大新不伦瑞克省蒙克顿的当地电子经销商处,但他收取的价格是我在线支付价格的5倍.我为此太便宜了.所以大多数情况下,我只是坐在那里等待下一次邮件传递(‘kindling’ since then. It took a few agonizing months for slow boats from China to eventually get here. And then there was a Canadian Pacific railway blockade that further impeded my tiny nuggets of joy from reaching their happy home before we all got hit with the Corona Virus. So, I went to my local electronics dealer here in Moncton, New Brunswick, Canada, but he charges 5x the price I pay on-line. and I am way too cheap for that. So mostly I just sit and wait for the next mail delivery and my)Arduino的(Arduino)最终确实会到达这里.在完成在线课程后,尽管遇到了一些令人沮丧的情况,但还是观看了一些YouTube指导性视频并阅读了一些(bits do eventually get here. Despite some frustrating instances after I had completed the on-line course, watched a few instructional YouTube videos and read several)Arduino的(Arduino)语言参考页面,我确定自己知道自己在做什么,但在蜂鸣器和陀螺仪LED仍应放置的地方仍然冒着火花……但我坚持不懈,最终建立了一些简单的项目.(Language Reference pages, and I was sure I knew what I was doing, I still got smoking sparks where buzzers and gyroscopic LEDs should have been… but I persisted and eventually built a few simple projects.) 现在情况好了.我终于有了一些必需品,例如稳压电源,可靠的万用表和像样的烙铁.所以我都准备好了.(Things are better now. I finally have a few essentials like a regulated power-supply, a reliable multi-meter and a decent soldering iron. So I’m all set.) 当您拥有一个(There are endless possibilities when you have an)Arduino的(Arduino),或两个或三个.我已经建立了一个机械臂,相比编写代码而言,制造机械零件要困难得多,但事实证明这根本没什么好玩的,因为那些SG-90 Micro-Servo电动机太弱了,无法执行任何操作,但是我出去买了更大,更好,更坏的MG995,这样很快就会动摇.有一个LCD1604"亚军"游戏,您在迷宫中四处奔跑,拍摄坏人,西蒙`西斯(Simon-Says)和其他内容,因为我一直在忙于C#项目,最近又忙于实际工作.(, or two or three. I’ve built a robotic arm which was a lot harder to build the moving parts for than it was to code but turned out to be no fun at all because those SG-90 Micro-Servo motors are way too weak to do anything with but I went out and bought the bigger, better, badder MG995s so that’ll rock soon enough. There was an LCD1604 ‘Runner’ game where you ran around in a maze shooting bad-guys, a Simon-Says and little else besides as I’ve been busy with C# projects and, most recently, and actual) 艺术项目(Art Project) 这占用了我太多的时间.所以,上周一个全新的(which was taking up way too much of my time. So, last week a brand new)最大7219(Max7219)4x菊花链点矩阵(8x8x4)到达邮件中,这是有足够理由每天晚上将我的艺术项目放下几个小时以便与我一起玩的理由(4x daisy-chained dot-matrix (8x8x4) arrived in the mail and it was reason enough to put down my art project for a few hours a day during the evening to play with my)Arduino的(Arduino).(.) 第一个晚上,我定义了((由于某俄罗斯著名的经典视频游戏的版权问题,我将拒绝使用本文中该项目的工作名称)(The first night, I defined the (because of copyright issues with a certain famous video game classic from Russia, I will decline from using this project’s working title for this article))下降块(Falling Blocks)可以旋转的碎片作为类,并可以计算出每个正方形在它们掉落时的位置,并且碎片在我的点矩阵游戏屏幕上开始掉落.第二天晚上,他们在旋转并用我的面包板左右移动(pieces as a class which could rotate and calculate where each of their squares were as they fell and pieces began dropping on my dot-matrix game screen. The next night they were spinning and moving left/right with my breadboard)74HC165(74HC165)加载注册的按钮.第三天晚上,地图数据诞生了,现在碎片遵循它们所在位置的物理定律.行被擦除,掉落时发生了时髦的事情,但是我解决了所有这些问题.即使有些事情我确实不得不重写,但整个过程只花了我一周的时间.那周的剩余时间都花在了抛光上.除了一个下午用烙铁,还有一些介绍词,滚动文本,滚动文本并没有吞噬我的全部记忆,最后滚动了按位逐字的方式向侧面滚动的文本.然后获得高分,发现一种神奇的东西叫做EEPROM,(load-register’ed push-buttons. On the third night, the map data was born and pieces now obeyed the laws of physics resting where they lay. Rows were being erased and funky things happened when they fell, but I fixed all that. Even though there were some things which I did have to rewrite, the whole thing only took me exactly one week. The rest of that week was spent on polish. Besides an afternoon with the soldering iron there were a few words of Intro, scrolling-text, scrolling-text that didn’t gobble up all my memory, and finally scrolling text that went sidewards in bitwise what-words way. Then high-scores and the discovery of a magical thing called the EEPROM,) “像微型硬盘一样”,Arduino参考.(“like a tiny hard drive”, Arduino Reference.) 它太酷了!我的编码背景有助于通过4x8byte的点矩阵屏幕阵列将奇形异形的瓦片掉落所涉及的所有按位操作,而我从大学那儿走过的一些电子基础知识足以完成任务.(Its pretty cool! My coding background helped with all the bitwise operations involved in dropping odd-shaped tiles through 4x8byte arrays of dot-matrix screens, and what little electronics basics I walked away from University with was enough to get’er done.) 现在,不幸的是,我需要一个支持小组来帮助我断奶玩(Now, unfortunately, I’ll need a support-group to help wean me off play the game of)下降块(Falling Blocks)…但是我听说他们有甜甜圈和咖啡.所以没关系.(… but I hear they have donuts and coffee. so that’s alright.)
背景(Background)
该项目是世界经典作品<俄罗斯方块>的廉价劣质复制品.(This project is a cheap inferior copy of a world classic called Tetris.)
按照(As per) 维基百科(Wikipedia) ,<俄罗斯方块>的原始游戏是由(, the original game of Tetris was designed by) 阿列克谢帕吉诺夫(Alexey Pajitnov)(*Alexey Pajitnov*)](https://en.wikipedia.org/wiki/Alexey_Pajitnov) 和(*and*) [瓦迪姆
杰拉西莫夫(Vadim Gerasimov)(Vadim Gerasimov) 他于1984年在俄罗斯首次发布了这款游戏.经过多年的创作权利争议,(who first released the game in Russia in 1984. After years of disputes over rights for their creation,) 阿列克谢`帕吉诺夫(Alexey Pajitnov)(Alexey Pajitnov) 于1996年从任天堂手中夺回了这些权利,并成立了(wrestled those rights from Nintendo in 1996 and founded)俄罗斯方块公司(The Tetris Company).该游戏已售出超过2.02亿份,其中包括约7,000万个物理单位和1.32亿次付费下载.游戏拥有(. Over 202 million copies of the game have been sold consisting of approximately 70 million physical units and 132 million paid downloads. The game holds the)吉尼斯世界纪录(Guinness World Record)适用于最多移植的标题,可在65个平台上使用,如果包括我的(for Most Ported Title and is available on 65 platforms, 66 if you include my)Arduino纳米(Arduino Nano)!(!)
所需资源(Resources needed)
- Arduino纳米(Arduino Nano)(或您拥有的任何控制器)带有匹配的USB连接器((or any controller you have) with matching USB connector)
- 4菊花链式(4 daisy chained)最大7219(Max7219)的(’s)
- 74HC165(74HC165)加载寄存器(可选)(load register (optional))
- 6个按钮(6 push buttons)
- 5V直流蜂鸣器(5V DC buzzer)
- 5k欧姆电位器(5k ohm potentiometer)
- 电线,焊锡和烙铁,镊子,钳子,剥线钳(wire, solder & soldering iron, tweezers, pliers, wire-strippers)
- 特百惠,汤罐盖和筷子是可选的(tupperware, soup-jar lid and chop-stick are optional) 观看显示最终结果的4分钟视频.(Watch a 4 minute video showing the end result.)
用户界面(User Interface)
游戏(The game of)下降块(Falling Blocks)通常使用操纵杆和两个按钮来玩,但是由于操纵杆是我随(is generally played with a joystick and two buttons but since the joystick I got in the mail with the)Arduino的(Arduino)相反,入门工具包仅用了一点点就损坏了,我选择了6个按钮(几个月前我刚好从旧的废旧电子设备中抢了下来).由于该项目中只有六个按钮,因此我设法节省了两个输出引脚,而只花了一个(Starter Kit has taken some damage after only a little use I opted for 6 push buttons (which I happened to have salvaged from old scrap electronics a few months ago) instead. Since there’s only six buttons in this project I managed to save 2 output pins at the cost of one)74HC165(74HC165)负载寄存器,6个180欧姆电阻器和少量焊料,但我坚持这个艰难的设计决定,因为它为我提供了使用烙铁的理由.还有谁不喜欢玩烙铁呢?(Load Register, 6x 180 ohm resistors and a bit of solder but I stand by this difficult design decision as it gave me a reason to play around with my soldering iron. And who doesn’t love to play around with their soldering iron?) 的(The)74HC165(74HC165)加载寄存器是一种微芯片,可以读取八个输入并将这些输入的状态仅使用四条线串行地传达给您的微控制器.您可以菊花链连接它们,并仅使用四个数字信号一次读取16\24\32或更多输入(Load Register is a micro-chip that can read eight inputs and communicate the states of those inputs to your microcontroller serially using only four lines. You can daisy-chain them and read 16, 24, 32 or more inputs at once still using only four digital)Arduino的(Arduino)别针(pins(the)奈米(Nano)只有13个,这意味着对于某些项目而言,加载寄存器是必不可少的).为这个项目使用一个是有点过分的杀手,但是无论如何我在架子上都有十几个,并且按钮被焊接到与(only has 13 which means for some projects a Load Register is essential). Using one for this project was a bit of an over kill but I have a dozen on my shelf anyway and the buttons are soldered onto the same removeable board as the)74HC165(74HC165)当我感到无聊时可以拔出插头再用于其他项目(and can be unplugged and reused for a different project whenever I get bored with)下降块(Falling Blocks)(或将其绑在一起的筷子最终会折断).下图显示了如何连接((or the chop-stick holding it together finally breaks). The a diagram below shows how to connect an)Arduino Uno(Arduino Uno)到8个DIP开关,使用(to 8 Dip Switches using a)74HC165(74HC165).(.)
在该项目中,我使用了6个按钮代替了拨码开关,并将(In this project, instead of dip switches I used 6 push-buttons and tied the)74HC165(74HC165)到(to the)Arduino的(Arduino)使用母接头.按钮和下拉电阻必须与焊接在一起.(using female connectors. The push-buttons and pull-down resistors had to be soldered together with the)74HC165(74HC165).除蜂鸣器和电位计外,这是该项目唯一需要的焊接.关于该项目中的加载寄存器,唯一需要注意的是引脚5和6(分别为D6和D7)都接地,因为只有6个(可能的8个)按钮连接到了这两个线上,浪费了,最好不要漂浮.另外,由于(. This was the only soldering that was required for this project aside from the buzzer and potentiometer. The only thing of note with regards to the Load Register in this project is that pins 5 & 6 (D6 & D7 respectively) are both tied to ground since there are only 6(of a possible 8) buttons connected to it those two lines are wasted and better left not floating. Also, since the)Arduino纳米(Arduino Nano)只有两个接地引脚,并且需要将三根电线接地((has only two ground pins and there are three wires needing to be grounded ()74HC165(74HC165)加载寄存器,(Load Register,)最大7219(Max7219)点矩阵和蜂鸣器)我必须创建一个具有旧跳线端的1:3分线器,以便我仍然可以使用跳线将这些外围设备连接在一起而无需焊接,并为它们提供共同的接地.(Dot Matrix and the buzzer) I had to create a 1:3 wire splitter with old jumper-wire ends so that I could still use jumper wires to connect these peripherals together without solder and provide them all with a common ground.) 下图显示了下落块组件如何连接到(The schematic below shows how the Falling Blocks components are connected to the)Arduino纳米(Arduino Nano).(.)
UI代码(UI Code)
在游戏过程中,用户界面非常简单直观.左侧的四个按钮是方向按钮,右侧的两个按钮控制下落片的旋转.(During game-play, the user-interface is quite simple and intuitive. The four buttons on the left are directional buttons and the two on the right control the falling piece’s rotation.)
但是,由于在游戏中没有使用向上按钮,因此可以将其用作两个按钮组合的控制按钮.(However, since the Up button has no use in the game it is available as a control button for two-button combinations.)
-
向上+向右旋转=暂停(Up + Rotate Right = Pause)
-
向上+向左旋转=预览下一块(Up + Rotate Left = preview next piece)
-
上+右=切换音乐(Up + Right = toggle Music) 首先,我实现了这些按钮的组合,并让各个按钮仍然控制着下落的游戏片段,如果您旋转该片段以尝试查看接下来会掉下来的片段或滑动片段以尝试切换音乐,则这会使玩游戏变得困难.因此,我回想起有关有限状态机的远距离演讲,并把所有FSM都投入了该项目.当我真正需要做的是在"向上"按钮按下时禁用所有控件时,我最终为这三种组合制作了FSM,但是当时我还没有完全确定向上按钮是控制按钮,仍在使用以下两个按钮组合:(I at first implemented these button combinations and let the individual buttons still control the falling game piece which made playing the game difficult if you rotated the piece trying to see what would fall next or slid a piece over trying to toggle the music. So I recalled some distant lecture about Finite State Machines and went all FSM on this project. I ended up making FSMs for all three of these combinations when all I really needed to do was disable all controls while the ‘up’ button is down but at the time I hadn’t settled on the up button being a control button at all but was still using the following two-button combinations :)
-
左+右=暂停(Left + RIght = pause)
-
向上+向下=切换音乐(Up + Down = toggle music)
-
向左旋转+向右旋转=参见下一部分(Rotate left + Rotate right = see next piece) 因此,我将向您介绍我的有限状态机,因为即使它们是完全不必要的,它们也可以正常工作,并且在避免游戏时间控制问题方面非常复杂.您可以通过下载zip文件查看这三个FSM(暂停,音乐和ShowNextPiece)的原始代码(So I’ll tell you about my Finite State Machines as they work adequately even though they are completely unnecessary and by far over complicated in avoiding game-time control issues. You can look at the original code with these three FSMs (Pause, Music & ShowNextPiece) by downloading the zip file) 下降块_FSMs_20200818_1551.zip(Falling Blocks_FSMs_20200818_1551.zip) .但是对于最后的项目,在按下"向上"按钮的同时,我摆脱了所有这三个因素,并分拆了游戏控件. bada-bing,bada-boom …要容易得多.(. But for the final project I got rid of all three of these and shunted game-controls while the ‘up’ button is pressed. bada-bing, bada-boom… much easier.)
UI有限状态机(UI Finite State Machines)
有限状态机是一种定义给定自动化系统所处的不同状态的方法.一旦知道了程序可能处于的所有可能条件,便可以创建从一个状态到下一个状态的路径,将它们全部连接在一起,以便给定数据,传感器或用户输入的条件,它们将从一种状态转换到另一种状态.这是一个简单的例子:(A finite state machine is a way to define different states in which a given automated system is in. Once you know all the possible conditions your program can be in you can then create a path from one state to the next connecting them all together so that they will transition from one state to the next given the conditions of your data, sensors or user inputs. Here’s a simple example:)
enum enuFSMMusic
{
FSMMusicOn = 0, // 0
FSMMusicStartUpRight, // 1
FSMMusicStartUp, // 2
FSMMusicStartRight, // 3
FSMMusicOff, // 4
FSMMusicEndUpRight, // 5
FSMMusicEndUp, // 6
FSMMusicEndRight // 7
};
用于切换音乐的有限状态机定义了上面显示的8个唯一状态.当电源打开时(The Finite State Machine for toggle the music defines the 8 unique states shown above. When the power is turned on the variable) eFSMMusic
被实例化并初始化为零(FSMMusicOn).功能(is instantiated and initialized to zero (FSMMusicOn). The function) PlaySong()
来电(calls) Music_UI()
在播放音符之前(before it plays a note and the) Music_UI()
使用开关盒(uses a switch-case for the) eFSMMusic
变量并决定要做什么.虽然它仍然在(variable and decides what to do. While its still in the) FSMMusicOn
说明它测试按钮的状态(state it tests the condition of buttons)向上(up)和(and)对(Right).如果同时按下这两个按钮,则其状态将变为(. If both these buttons are pressed then its changes its state to) FSMMusicStartUpRight
直到它再次循环并切换到该状态的情况并再次测试这些相同的按钮,最终落入(until it cycles through again and switches to that state’s case and tests those same buttons again eventually falling into the) FSMMusicOFF
播放器释放这两个按钮时的状态.一直以来(state when both those buttons are released by the player. All the while, the) PlaySong()
仅当变量(will only play music if the variable) eFSMMusic
处于状态(is in the state) FSMMusicOn
.(.)
有限状态机是功能非常强大的工具,可以使用它们并可以大大简化其他困难的程序流程问题,但是在这里完全没有必要.决定使用一个``向上'‘按钮作为控件,并在按下一个按钮时分流所有其他与游戏相关的按钮控件,只需要三个布尔变量来定义所有三个选项的条件(暂停,音乐和下一个片段) ).(Finite state machines are very powerful tools that have their uses and can greatly simplify otherwise difficult program flow issues but they were wholly unnecessary here. Deciding to use the one ‘Up’ button as a control and shunting all other game-related button controls whenever that one button is depressed only required three boolean variables to define the conditions of all three options (pause, music & see-next-piece).)
一位智者说:“当一切都平等时,简单会更好."(“Simpler, when all things are equal, is better,” a wise man said.)
(或者可能是提利昂`兰尼斯特^我不记得了)((or it might have been Tyron Lannister… I don’t remember))
碎片(The Pieces)
游戏中有七种不同的棋子(There are seven different kinds of pieces in the game of)下降块(Falling Blocks).在这个项目中,我使用名为(. In this project I coded them using a class called) classFalling BlocksPiece
跟踪作品落下时在屏幕上的位置.每次下降(that keeps track of where the piece is on the screen as it falls. Each falling)下降块(Falling Blocks)一块是由四个实例组成的数组(piece is made up of an array of four instances of the) classFalling BlocksPiece_Square
.(.)
class classFalling BlocksPiece
{
public:
byte bytPieceType = 0; // not necessary - only used for early debugging
classPoint pt; // its location on the game map
classFalling BlocksPiece_Square squares[4];
classFalling BlocksPiece();
void setType(byte bytTypeNew); // initializes each square
void InitRandom();
void RotateRight();
void RotateLeft();
int PieceInBounds_Horizontal();
};
棋子可以绕自己旋转,而0(The Pieces can rotate about themselves and the 0)日(th)索引正方形是每个零件围绕其旋转的枢轴正方形.在下面的图像中,您可以看到每个块如何由这四个正方形组成,以及如何配置这些正方形来定义块的形状.(indexed square is the pivot-square about which each piece rotates. In the image below you can see how each of the pieces is composed of those four squares and how those squares are configured to define the piece’s shape.)
的(The) classFalling BlocksPiece_Square
跟踪两个笛卡尔点.第一个跟踪它相对于枢轴正方形的位置,第二个跟踪它在游戏地图上的位置.零件本身不需要知道它们是什么形状,而只需知道它们的正方形相对于枢轴正方形的位置即可,因此当需要旋转时,每个正方形都会改变其相对于枢轴正方形的位置,从而实质上改变了形状但有效地愚弄了玩家认为棋子已经旋转.马铃薯…番茄无论您叫什么,它看起来都在旋转.(keeps track of two cartesian points. The first tracks where it is located relative to the pivot-square and the second positions it on the game-map. The pieces themselves don’t need to know what shape they are but only where their squares are located relative to the pivot-square so when they need to be rotated each square changes its position relative to the pivot square essentially changing their shape but effectively fooling the player into believing that the piece has been rotated. Potato … Tomato. Whatever you call it, it looks like its rotating.)
void classFalling BlocksPiece_Square::RotateRight()
{
int intY_Temp = pt.X;
pt.X = - pt.Y;
pt.Y = intY_Temp;
}
void classFalling BlocksPiece_Square::RotateLeft()
{
int intY_Temp = -pt.X;
pt.X = pt.Y;
pt.Y = intY_Temp;
}
作品的位置本身记录在(The piece’s location itself is recorded in the) classFalling BlocksPiece
并确定枢轴正方形的位置,该位置设置相对于它定位的其他三个正方形的所有位置.(and determines the pivot-square’s location which sets all the locations of the three other squares that are positioned relative to it.)
尽管游戏可以进行一段时间,并且游戏结束时标题滚动之前可能会掉落数百块或更多块,但实际上游戏中只有三块.所有这三个部分都在一个阵列中.(Although the game can go on for some time and a hundred pieces or more may fall before the titles roll when the game ends there are really only three pieces in the game. All three pieces are in a single array.)
- 的(the)下降片(Falling piece)
- 的(the)下一块(Next piece)
- 的(the)试片(Test piece) 的(The)下降片(Falling Piece)是您在屏幕上看到的由播放器控制的部分.的(is the piece you see on the screen which the player controls coming down. The)下一块(Next Piece)是屏幕顶部闪烁的等待下降的那个.这两部分有两个指针,每次每次指针在两个指针之间交替(is the one flashing at the top of the screen waiting to come down. There are two pointers to these two pieces and the pointers alternate between the two every time the)下降片(Falling Piece)停止移动.的(stops moving. The)试件(Test Piece)是的克隆(is a clone of the)坠落(Falling)用于碰撞检测以确定是否(piece used in collision detection to determine if the)下降片(Falling Piece)可以执行玩家想要的动作.(can perform an action the player intended.)
碰撞检测(Collision detection)
当然,您需要测试一块是否会掉落,侧向移动甚至旋转.为此,(Of course, you need to test whether or not a piece can fall, shift sideways or even rotate. To do this, the)下降片(Falling Piece)的变量复制到(’s variables are copied onto the)试件(Test Piece).的(. The)试件(Test Piece)然后根据玩家的意图进行操作,如果最终的旋转和位置(is then manipulated according to the player’s intentions and if the resultant rotation and location of the)试件(Test Piece)不会与游戏地图的当前状态冲突(稍后会详细介绍),那么该移动是允许的,并且(does not conflict with the current state of the game map (more on that later) then that move is allowed and the)试件(Test Piece)的更改值分配给了(’s altered values are assigned to the)下降片(Falling Piece)然后游戏继续进行.有时旋转会导致碰撞,在这种情况下(and the game goes on. Sometimes a rotation will lead to a collision in which case the)试件(Test Piece)向左或向右移动,然后进行另一个碰撞测试.如果(is moved Left or Right and another collision test is made. If the)试件(Test Piece)此处的最终状态是允许的,然后(’s final state here is permissible then the)下降片(Falling Piece)不仅旋转(根据玩家的意图),而且还移了一个正方形以允许旋转继续进行而不会与游戏地图发生碰撞.在撰写本文时,旋转碰撞仅改变了一个左移或右移,而没有改变第二个或第三个移位,在某些情况下,这意味着棋子不会旋转,如果这样做将要求将它们移位一次以上为了避免碰撞.这可以纠正,我只是没有做过.(is not only rotated (as per the Player’s intention) but is also shifted-over by one square to allow the rotation to proceed without causing a collision with the game’s map. At the time of writing, the rotation collision is only altered by a single left or right shift and not a second or third which, in some cases, means that pieces won’t rotate if doing so would require that they be shifted more than once in order to avoid a collision. This could be corrected, I just haven’t done it.)
动作和旋转以及必要的碰撞测试在外部进行(The moves and rotations, along with their requisite collision tests are done outside the) classFalling BlocksPiece
因为这些操作需要访问(as those operations require access to the)地图数据(Map Data).(.)
地图数据(Map Data)
当…的时候(When the)下降片(Falling Piece)不能再动了,它变得静止了.在这种情况下,不再需要将其作为一个整体来跟踪(can no long move it becomes stationary. In that case it is no longer necessary to keep track of it as an integral)下降块(Falling Blocks)由四个正方形组成.除了记住掉落的方块属于哪一块并创建新的碎片,这些新碎片只会随着玩家逐行清除而消失而消失,(piece made up of four squares. Instead of remembering what fallen squares belong to which piece and creating new pieces that will only be broken apart and disappear as the Player clears row after row, the)下降片(Falling Piece)的位置用于设置游戏的值(’s location is used to set the values in the game’s)地图数据(Map Data).由于游戏屏幕由4个8x8点矩阵阵列组成,因此屏幕上有8x32正方形.每个正方形都可以被一个(. Since the game screen is made up of 4 8x8 dot matrix arrays there are 8x32 squares on the screen. Each square can either be occupied by a)下降块(Falling Blocks)-片方或不.的(-Piece-Square or not. The)最大7219(Max7219)菊花链旨在从侧面观察.在这个(daisy chain is intended to be viewed sideways. In this)下降块(Falling Blocks)项目,但是将其配置为0(project, however, it is configured such that the 0)日(th)矩阵位于游戏屏幕的顶部,而3(Matrix is at the top of the game screen while the 3)rd(rd)矩阵位于底部.每个矩阵由8个字节组成(通常彼此叠加),其中0(Matrix is at the bottom. Each Matrix consists of 8 bytes (normally on top of each other) with the 0)日(th)顶部的字节和7(byte at the top and the 7)日(th)在底部(如下图所示).要在屏幕上绘制任何内容,您必须处理矩阵和行(at the bottom(when viewed sideways as in the diagram below). To draw anything on the screen you have to address the Matrix and row of your)最大7219(Max7219)菊花链(通常也是侧向的).下图显示了如何设置这些矩阵.(daisy chain (which, again, is normally sideways). The diagram below shows how these Matrices are set-up.)
游戏(The game’s)地图数据(Map Data)由组成游戏各栏的8个无符号长整数组成.当如上图所示水平显示时,您会注意到这些无符号长整数的位索引从游戏屏幕的顶部(图像的右侧)开始,到游戏屏幕的底部(图像的左侧)结束图片),其无符号长整数本身的索引顺序与(consists of 8 unsigned long integers that make up the columns of the game. When shown horizontally as they appear in the diagram above, you will notice that the bit indices of these unsigned long integers start at the top of the game-screen (right of the image) and end at the bottom of the game screen(left of the image) with the unsigned long integers themselves indexed in the same order that the)最大7219(Max7219)自己的字节在屏幕左侧(图像顶部)为0,在右侧(图像底部)为7.当一块落下时,数据被更改,并且在(’s own bytes are with 0 at the left of the screen(top of image) and 7 at the right(bottom in image). When a piece falls the data is altered and the bits are set where the)下降片(Falling Piece)的方块在下一块开始从顶部掉落之前.当需要绘制屏幕时,(’s squares are before the next piece starts to fall from the top. When it comes time to draw the screen, the)地图数据(Map Data)复制到由8个无符号长整数组成的临时数组中,并且(is copied onto a temporary array of 8 unsigned long integers and the)下降片(Falling Piece)被添加到他们.然后将每个临时无符号长整数向右移8位,并在其中使用其最低有效字节(is added to them. Then each temp unsigned long integer is shifted 8 bits to the right and has its Least Significant Byte used in the)
lc.setRows(intDisplayCounter, intColumnCounter, bytDisplay);
称为(call as the) bytDisplay
如果自上次绘制屏幕以来这8位中的任何一个已更改,则在屏幕上绘制.两个变量用于跟踪4个字节中的8个字节中的哪个字节(to draw on the screen if any of those 8 bits have changed since the last time the screen was drawn. Two variables are used to keep track of which of the 8 bytes of each of the 4)最大7219(Max7219)矩阵需要更新.(Matrices need to be updated.)
unsigned long ulngScreen_RowsNeedRefresh = -1;
byte bytScreen_ColumnsNeedRefresh = B11111111;
无符号长(The unsigned long) ulngScreen_RowsNeedRefresh
跟踪哪些行已更改,而(keeps track of which rows have been altered while the) bytScreen_ColumnsNeedRefresh
跟踪更改了哪些列.刷新屏幕时,这两个变量将重置为默认值(所有位均设置为高),并保持这种状态,直到(keeps track of which columns were altered. When the screen is refreshed these two variables are reset to the default values (all bits set high) and they remain that way until the)坠落(Falling)一块移动或旋转时,所有行和列(piece is moved or rotated at which time all the rows and columns the)下降片(Falling Piece)在此更改之前和之后占用的空间将在上面的"刷新"变量中设置,以便下次进行采样时(occupied before and after this change are set in the ‘Refresh’ variables above to be sampled the next time the) drawScreen()
函数被调用.(function is called.)
折叠行(Collapsing rows)
随着游戏的继续,被填充的行将被擦除,然后被擦除的行上方的行将被替换.为此,(As game play continues the rows that are filled flash then are erased, and the rows above those that were erased fall to replace them. For this to happen the)下降片(Falling Piece)下降直到无法再下降为止在这里,算法需要测试哪些行已完成.它可以测试所有32行,但是如果知道(falls until it can fall no further. Here the algorithm needs to test which rows are completed. It could test all 32 rows but why do that when it knows that the)下降片(Falling Piece)是唯一可以填满一行的片段.因此,它仅使用(is the only piece that could fill a row. So its tests only those rows where the falling piece ended using the) ulngScreen_RowsNeedRefresh
上面提到的变量.它创建另一个无符号的长整数,并设置与玩家在游戏中填充的行相对应的位.然后,此无符号长整数将用作按位操作中的掩码,这些操作会设置或重置(variable mentioned above. It creates another unsigned long integer and sets the bits that correspond to the rows that the player filled in the game. This unsigned long integer is then used as a mask in bitwise operations which set or reset the bits in the the)地图数据(Map Data)在将其绘制到屏幕上以创建闪烁的消失行效果之前.之后,通过从最远的那一行开始的所有消失的行,将所有列的左上方的所有位向左移动(此处左为按位左移,对应于屏幕上的"向下”),一次擦除一行.在游戏屏幕的底部.只有以这种方式擦除了所有消失的行之后,才会再次绘制屏幕.(before it is drawn to the screen to create the flashing vanishing rows effect. After which they are erased one row at a time by shifting all the bits above that row to the left(left here being a bitwise left which corresponds to ‘down’ on the screen) for all columns for all vanishing rows starting from the one furthest down the bottom of the game screen. The screen is drawn again only once all the vanishing rows have been erased in this fashion.)
滚动文字(Scrolling Text)
的(The)最大7219(Max7219)有充分的文档记录,并且在线提供了大量教程,可为您提供使文本在点矩阵上滚动所需的所有功能.(is well documented and there are plenty of tutorials available on-line to provide you with all the functions you need to make text scroll on your dot-matrix.) 所以我写了我自己的.(So I wrote my own.) 我想这只是愚蠢或固执,但我喜欢编码,只花了几个小时就实现了一个简单的横向滚动文本功能,并带有全部大写/小写以及其他几个字符.(Just stupid or stubborn, I guess, but I like to code and it only took me a couple of hours to implement a simple sideways scrolling text function with all upper/lower case and several other characters besides.) 观看我发布在FaceBook上的视频(watch this video I posted on FaceBook) 如果您希望您的项目唯一要做的事情是横向滚动文本,但该文本滚动项目使用8个字节的内存定义了每个字符的位图,那么这总和超过82x8字节,总共656字节仅用于定义那82个字符.听起来可能不多,但请记住(That works fine if the only thing your want your project to do is scroll text sideways but that Text-scrolling project defined each character’s bit-map using 8 bytes of memory which added up to over 82x8 bytes for a total of 656 bytes just to define those 82 characters. That may not sound like much but remember that the)Arduino纳米(Arduino Nano)内存很少,没有多余的余地.在任何其他项目中,您都可能会遇到内存问题,因为大多数微控制器中的内存非常宝贵,您必须优化内存使用率或选择要执行的操作并删除那些需要过多内存的东西.(has very little memory and no more to spare. With any other project you may run into Memory issues as memory in most micro-controllers is at a premium you have to optimize memory usage or pick and choose what you want to do and drop those things that require too much memory.) 这是"滚动文本"项目的内存使用情况(仅滚动一个文本句子不执行任何操作)(Here’s the memory usage for the Scrolling Text project (that does nothing but scroll one sentence of text))
与此相比(compared to the memory usage of this)下降块(Falling Blocks)专案((project (that’s a game of)下降块(Falling Blocks)加上滚动文字)(with scrolling text besides))
它不仅限于26个大写字母,空格和数字0-9,而且还简化了定义这些字符的方式.的(Which is not only limited to the 26 upper case letters, space and digits 0-9 but condenses the way these characters are defined. The)下降块(Falling Blocks)项目在一个一维字节数组中横向定义了每个滚动字符的位图.(project defines each scrolling character’s bit-map sideways in a one dimensional array of bytes.)
String strCharList = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789";
String strChrWidth = "4444444435445544544545555545344544444";
byte bytFont[]
{
B11111110, // A 4
B00010001,
B00010001,
B11111110,
B11111111, // B 4
B10001001,
B10001001,
B01110110,
B01111110, // C 4
B10000001,
B10000001,
B01000010,
B11111111, // D 4
B10000001,
B10000001,
B01111110,
B11111111, // E 4
B10010001,
B10010001,
B10000001,
B11111111, // F 4
B00001001,
B00001001,
B00000001,
B01111110, // G 4
B10000001,
B10010001,
B11110010
看看下面的图片,该图片显示了相同的数据横向旋转,您可以更好地看到字符位图.(have a look at the image below which shows the same data rotated sideways and you can better see the character bit-maps.)
位图定义中的字母之间没有空格,大写字母的前四个字母中的每个字母仅使用4个字节,而不是第一个实现所需的8个字节.(There are no spaces between the letters in their bitmap definitions and each of the first four letters of the capitalized alphabet seen above use only 4 bytes as opposed to the 8 bytes the first implementation required.)
每当需要字符位图时,都会在(Whenever a character bit-map is needed that character is searched in the) strCharList
字符串及其在该字符串中的索引用于求和(string and its index in that string is used to sum all the integer values in the) strCharWidth
匹配的字符串(string that matches) strCharList
每个字符的位图宽度的长度和轨迹.这样,将要绘制的字符之前的所有字符的宽度的所有整数值相加,就可以得出字符中字节的起始索引.(in length and tracks of each of the characters’s bitmap widths. This way, summing up all the integer values of the widths of all the characters that precede the one you want to draw gives you the starting index of the character’s byte in the) bytFont
数组,然后将相同字符的宽度值添加到其开始索引,以确定其结束索引.使用这两个索引,可以从(array and that same character’s width value is then added to its start index to determine its end index. With these two indices the bitmap is read from the) bytFont
数组和一个以字符为中心的8字节数组将被创建并返回到调用函数,所有字符都使用一种类似于上述滚动文本项目所实现的算法的算法绘制.(array and an 8 byte array which centers the character is created and returned to the calling function and all characters are drawn using an algorithm similar to the one that was implemented for the Scrolling text project mentioned above.)
有限状态机确实有目的(Finite State Machines do have a purpose)
滚动文本项目仅做一件事:无限滚动一串文本.但是游戏(The scrolling text project does only one thing : infinitely scroll one string of text. But the game of)下降块(Falling Blocks)根据游戏中的位置,有几句话要说.在程序开始时,它将无限循环向上滚动字符串``Falling Blocks 2020 HIGH SCORE <高分> <名称高分>'',直到玩家按下RotateRight按钮以启动游戏为止.在这一点上,滚动停止并且游戏继续进行,直到玩家按下"暂停"按钮组合或游戏结束.暂停模式会像介绍文字一样垂直滚动其他字符串,但在游戏结束时,情况会变得有些复杂.最初,“游戏结束"文本也是垂直滚动的,但我发现它太慢了,并且花了太长时间才让玩家知道他的最终得分.所以我实施了(has several different things to say depending on where it is in the game. At the start of the program it scrolls the string “Falling Blocks 2020 HIGH SCORE ” upwards in an infinite loop until the player presses the RotateRight button which launches the game. At which point the scrolling stops and the game proceeds until the player either presses the Pause button-combination, or the game ends. Pause mode scrolls a different string vertically just as the intro text did but at game end things get a little more complicated. Originally, the Game Over text was also scrolling vertically but I found that too slow and it took too long to let the player know what his final score was. So I implemented a)**横向滚动(scroll-sideways)**功能,然后从右滚动两个四个字母的单词GAME&OVER.字母仍然像以前一样都是垂直的,但是第一个单词GAME从右边一次进入屏幕一个位图列,直到单词水平居中,在此点它短暂等待,然后再次对第二个单词OVER重复此操作并等待再次以类似的方式告诉玩家自己的得分之前.在这里,它必须决定玩家是否击败了高分.如果有新的高分,则单词” HIGH&SCRE"(滚动)和" SCRE"(滚动)会滚动显示,并且UI允许用户输入其名称.用户界面完成并输入了高分者的名称后,它将存储在EEPROM中(下文中有更多信息),并且显示继续在GAME + OVER + <得分> + HIGH + SCORE + <高分> + <高分名称>通常在玩家未击败高分时执行.(function and let the two four-letter words GAME & OVER scroll in from the right. The letters are all still vertical as before but the first word GAME enters the screen one bitmap column at a time from the right until the word is centered horizontally at which point it waits briefly before it repeats this operation again for the second word OVER and waits again before telling the player his score in similar fashion. Here it must decide whether the player has beaten the high score or not. If there is a new high score then the words HIGH & SCRE scroll in and the UI lets the user enter his name. Once the UI is complete and the high scorer’s name has been entered it is stored on the EEPROM (more on this below) and the display continues to cycle through GAME + OVER + + HIGH + SCORE + + it normally does when the player does not beat the high score.) 你可以看到(You can see that)如果(if),(,)**其他(else)**并嵌入(and embedded)**还有什么(what else)**会像这样的意大利面条弄得一团糟,因此使用FSM来实现这一切.(’s would make a spaghetti like mess of this so an FSM was used to make it all happen.) 以下是该FSM可能状态的列表:(Here is a list of that FSM’s possible states:)
enum enuFSMScrollingText
{
FSMScrollingText_IntroInit, // 1
FSMScrollingText_Intro, // 2
FSMScrollingText_PauseInit, // 3
FSMScrollingText_Pause, // 4
FSMScrollingText_ScoreValue_Init, // 5
FSMScrollingText_ScoreValue, // 6
FSMScrollingText_ScoreValue_Delay, // 7
FSMScrollingText_GameInit, // 8
FSMScrollingText_Game, // 9
FSMScrollingText_OverInit, // 10
FSMScrollingText_Over, // 11
FSMScrollingText_GameOver_Delay, // 12
FSMScrollingText_HighScore_High_Init, // 13
FSMScrollingText_HighScore_High, // 14
FSMScrollingText_HighScore_SCRE_Init, // 15
FSMScrollingText_HighScore_SCRE, // 16
FSMScrollingText_HighScore_Delay, // 17
FSMScrollingText_HighScoreValue_Init, // 18
FSMScrollingText_HighScoreValue, // 19
FSMScrollingText_HighScoreValue_Delay, // 20
FSMScrollingText_HighScore_PlayerName_UI, // 21
FSMScrollingText_HighScore_PlayerName_UI_Close, // 22
FSMScrollingText_HighScore_PlayerName_Init, // 23
FSMScrollingText_HighScore_PlayerName, // 24
FSMScrollingText_HighScore_PlayerName_Delay // 25
};
由于本文前面已经解释了FSM,因此似乎不太难理解这个特定的FSM.名称末尾带有" Init"字样的州是定义了要跟随的文本并准备好滚动到屏幕上的状态.每个’Init’状态之后的下一个状态是垂直滚动一长串文本或从右侧水平滚动任何给定的4个字符的字符串的状态. “延迟"表示屏幕在进入下一FSM状态之前会保持静止一秒钟.而且这两个’_UI’的所有情况都例外,表示进行任何侧向滚动以让高得分者输入其名字,然后等到旋转右按钮(玩家用来完成操作)后才能松开,以免误以为玩家打算开始新游戏.(Since FSMs were explained earlier in this article this particular FSM should not seem overly difficult to understand. Those states with the word ‘Init’ at the end of their names are states where the text to follow is defined and made ready to scroll onto the screen. The next state after each ‘Init’ state is the state that scrolls in a long string of text vertically or any given 4-character string horizontally from the right. ‘Delay’ means the screen stays static for a second before moving on to the next FSM state. And the exception to all that are the two ‘_UI’ states that side step any scrolling to let the high-scorer enter his name then wait until the Rotate-Right button(used by the player to complete the operation) is release lest it be mistaken for the player’s intention to start a new game.)
UI:输入高分名称(UI : Entering the High Score Name)
当滚动文本FSM落入(When the Scrolling Text FSM falls into)FSMScrollingText_HighScore_PlayerName_UI(FSMScrollingText_HighScore_PlayerName_UI)由于玩家记录了高分,因此程序进入与用户交互的功能,直到他按下"向右旋转"按钮,这表示他已经完成输入自己的名字.此功能清除屏幕并重设(state because the player has recorded a high score, the program flows into a function that interacts with the user until he has pressed the Rotate-Right button which signifies he has finished entering his name. This function clears the screen and resets the) strHighScorePlayerName
字符串转换为” AAAA",并创建一个由四个字符组成的数组,以跟踪播放器名称中的每个字母.使用整数变量来记住正在编辑的字符(对应于哪个矩阵阵列正在闪烁),它会测试方向按钮的状态,并在按下向左或向右按钮时滚动浏览字母,或者在每个四个点矩阵显示,允许玩家更改其他字母.播放器完成后,他可以按向右旋转按钮并保存信息.(string to “AAAA” and creates an array of four characters to keep track of each letter in the player’s name. Using an integer variable to remember which character is being edited (corresponds to which Matrix Array is flashing) it tests the directional buttons states and either scrolls through the letters when either the Left or Right buttons are pressed or cycles up and down through each of the four Dot-Matrix displays to allow the player to change a different letter. When the player is done, he can press the Rotate-Right button and the information is saved.)
跟踪高分(Keeping Track of High Scores)
Arduino微控制器都具有一些EEPROM存储器.即使切断电源,该内存也会被保存,并且只要您重新上电就可以用来初始化或重新启动您的项目.在这种情况下(The Arduino microcontrollers all have some EEPROM memory. This memory is saved even when the power is cut off and can be used to initialize or reboot your project whenever you power it back to life. In the case of the)下降块(Falling Blocks)在项目中,我发现EEPROM对于存储高分值非常有用.我可以用它来存储字符位图的那些160个奇数字节,但是我没有打扰.因为EEPROM存储器的预期寿命为100000(project, I found the EEPROM useful for storing the High score values. I could use it to store those 160 odd bytes of Character bitmaps but I haven’t bothered. Because EEPROM memory has a life expectancy of 100 000)写(writes)(读取不会使EEPROM变坏)最好不要将EEPROM存储器用于游戏变量或每天更改几次或多次的任何其他类型的变量,以防止EEPROM恶化并变得毫无用处.他们建议,当您确实写入EEPROM时,首先要测试您要覆盖的字节的值,并查看其是否与您要覆盖的字节的值相同,因为如果您可以通过不必不必要地覆盖一个字节的内存来延长EEPROM的寿命.最好的方法是避免使用((read does not deteriorate your EEPROM) its best not to use the EEPROM memory for game play variables or any other type of variable that is altered several times a day or more to keep your EEPROM from deteriorating and becoming useless. They suggest, when you do write to an EEPROM, to first test the value of the byte you’re about to write over and see if its the same as the value you’re about to over-write it with, because if it is you can extend your EEPROM’s life by not over-writing a byte of memory unnecessarily. The best way to do that is to avoid using the) write()
一起使用(function altogether and use the) update()
而是使用函数,因为如果旧值与您打算用其替换的新值不同,它只会写入预期的地址.因此,使用EEPROM存储器来存储位图(例如,用于滚动字符)将是EEPROM的一种有效使用方式,如果有需要,我会尝试这样做,但是随着项目的进行,剩余的动态内存为49%它永远不会有任何内存不足的机会.(function instead since it will only write to the intended address if the old value is not the same as the new value you’re intending to replace it with. So using the EEPROM memory to store, say, bit-maps for scrolling characters would be an efficient use of the EEPROM and I would have come around to doing that if there were a need but as the project compiles with 49% of dynamic memory remaining there is no chance of it ever having any shortage of memory.)
EEPROM的(The EEPROM’s) read()
,(,) <font color="#111111" face="Segoe UI, Arial, sans-serif"><span style="font-size: 14px;"> </span></font>
write()
和(and) update()
函数很简单,但是我在保存高分的无符号整数值时遇到了一些麻烦,因为我没有暗示您一次只能保存一个字节的事实,在无符号整数的情况下,它要进行两次运算我想象中的那一个(functions are straight forward but I had some trouble saving the unsigned integer value of the high score because I hadn’t clued into the fact that you can only save one byte at a time, which in the case of the unsigned integer took two operations instead of the one I had imagined.)
建造(The Build)
如您所见(As you can see in the) 我在YouTube上发布的视频(video I posted on YouTube) 该项目的建造需要在回收箱中进行一些抽膛.首先,我切割并拉直了一个旧的晾衣架,然后将其弯曲成一定形状并用电工胶带覆盖.我用镀锌钢丝将按钮控制器绑在弯曲的衣架的底部,并向自己保证,没有暴露的钢丝与按钮布线有任何接触.然后,我使用了两个塑料拉链,将其两端剪短以使其平整,然后用胶带将其扎到盖子的顶部,确定它们的弯曲衣架形状均匀,可以在以后固定.在这里,我测量了纽扣控制器应该去的弯曲衣架旁边的盖子,并用丁烷打火机加热了一把锋利的手术刀,并整齐地剪了塑料特百惠盖子.在这一点上,我在两个胶带式扎带两侧的盖子上切了八个孔,这样我就可以将未损坏的拉链穿过这些孔,并将衣架固定在盖子的下侧,紧贴边缘我为此掏腰包.导管顶部盖有切开的扎带,以确保穿过孔和衣架周围的扎带不会撕裂塑料特百惠餐具.之后有两个拉链,(the build for this project required a bit of rifling through the recycling bin. First I cut and straightened an old clothes-hanger then bent it to shape and covered it with electrical tape. I used galvanized steel wire to tie the button controller to the bottom of the bent clothes hanger and assured myself that none of the exposed steel made any contact with the button wiring. Then I used two plastic zip-ties, cut the ends off to make them flat and duct-taped them to the top of the lid, being certain they were even with the shape of the bent clothes hanger that they would help secure later. Here I measured the lid next to the bent clothes hanger where the button controller should go and used a butane lighter to heat up a sharp scalpel and neatly cut the plastic tupperware lid. At this point I cut eight holes in the lid on either side of both taped zip-ties so that I could run undamaged zip-ties through the holes and secure the clothes hanger to the under side of the lid, snugly fitting it along the edge that I cut out for it. The cut zip-ties duct-taped to the top of the lid are there to make sure that the zip-ties going through the holes and around the clothes-hanger don’t tear the plastic tupperware. Two zip-ties later and the)Arduino纳米(Arduino Nano)被牢牢固定在衣架上.我在电位器上切了一个孔,将其滑入并拧紧,然后用热手术刀的尖端在顶部盖住一系列小孔,将蜂鸣器粘在底面上.我还必须切割特百惠的下半部分以将其安装到盖子上,然后测量USB线从微控制器伸出的位置,并在特百惠的底部切一个孔.(was held fast to the clothes hanger. I cut a hole for the potentiometer, slipped it through and screwed it tight then used the point of the hot scalpel to sear a series of small holes overtop where the buzzer is glued to the underside. I had to also cut the bottom half of the tupperware to fit it onto the lid then measured where the USB wire sticks out of the micro-controller and cut a hole for it through the bottom of the tupperware there.)
当我尝试使用这种游戏时,在玩耍时几乎没有什么可握住的,因此我在Ragu意大利面条酱盖的盖子上打了个洞,并将其绑在衣架上,从而伸出按钮控制器下方.但这仍然没有真正的帮助,所以我在Ragu锅盖的后部又打了两个孔,并用一根筷子扎住了它,所以我的手掌底部向下压,而我的手指按住了我控制的控制器用我的拇指.不漂亮,但是可以.(When I tried using the game like this there was little to hold on to while playing so I punched holes in the lid of a Ragu spaghetti sauce lid and tied it to the clothes hanger so it sticks out beneath the button controller. That still didn’t really help, so I punched two more holes at the very back of the Ragu lid and tied a chop-stick across it so the base of my palms press down on it while my fingers hold up the controller which I control using my thumbs. Not pretty, but it works.)
那是我的项目.我有一些充电电池,并且需要一些零碎的东西将它们绑到我的身上(And that’s my project. I have some rechargeable batteries and the bits needed to tie them to my)Arduino纳米(Arduino Nano)所以我可以打San-USBilical线.但这一切仍然在某处的慢船上…所以也许在一个月或两三个月后,我会向您更新.也许,在完成之前,我会先让片段移动两位或更多.(so I can plays sans-USBilical cord. but that’s all still on a slow-boat from somewhere … so maybe in a month, or two or three I’ll update you on that. And maybe, I’ll get around to letting the pieces shift two bits or more before I’m done.) 在那之前,快乐的Quaranduino-ing!(Until then, happy Quaranduino-ing!)
历史(History)
- 最初于8月18日发布(originally published August 18)日(th),2020(, 2020)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C++ Arduino DevOps 新闻 翻译