Simone Says





5.00/5 (1投票)
由 Arduino Micro Pro 带来的经典电子游戏。
引言
最初的 Simon 游戏于 1978 年推出,在没有 C++ 和 Arduino 的便利协助其创作者的情况下,制作它肯定需要付出更多的努力。我小时候这款游戏很受欢迎,虽然我从未拥有过,但我确实能和那些拥有它的表亲和邻居们一起玩,而且非常有趣。20 世纪 70 年代末电子游戏的吸引力让这款游戏比在本世纪推出时要流行得多,但它仍然可以是一种愉快的消遣,只是回味一下 Lennon 还在世、8 轨磁带播放着 BeeGees,而你的妹妹却霸占着固定电话与那个穿着 April Wine T 恤的怪男孩聊天时的美好旧时光。
背景
原版游戏只有四种颜色,并使用计时器来保持公平。这个版本有五种颜色,没有计时器。如果你愿意,可以自己添加计时器,我只是没 bother。我又不是说如果我按键太慢就会有人生气并把它从我这里拿走。代码相对简单,但我构建它的方式需要一些技巧才能连接起来,因为我有 5 个 LED、5 个按钮(采用分压器配置)和 74HC595 移位寄存器,所有这些都焊接在一个 6x4 厘米的板子上。我没有太多焊接和构建这些 Arduino 项目的经验,所以对我来说,它有点挤,但我第一次就成功了,所以我非常满意。如果你是 Arduino 和焊接新手,我建议使用一个更大的板子,或者将移位寄存器固定在一个单独的板子上,因为我认为我只是运气好,第一次就成功了。
你可能想少喝点咖啡因,换成绿茶来玩这个游戏。
代码
Arduino 代码的主要 loop()
函数相对简单。由于 Setup()
初始化了所有内容,然后进入一个无限循环,播放歌曲并为 LED 动画,直到玩家按下开始键,loop()
方法才会在那之后启动。方便的是,从通电到玩家按下“开始”按钮之间的延迟时间被用作 RandomSeed()
的值,否则你每次玩都会玩相同的谜题序列。
下面的代码展示了主要的 loop()
函数。你可以看到,它首先检查玩家是否按下了按钮。如果按下了,它会检查玩家的输入是否正确。当输入的正确序列完全完成后,将向谜题添加一个新的音调,并且在播放完序列供玩家听之后,代码将再次进入此循环。只要玩家的输入是正确的,就会重复此过程。当玩家未能完成谜题时,我们将退出此循环并进入 GameOver()
模式,在该模式下,玩家的分数将与最高分进行比较,并播放一首欢快的歌曲。
瞧,Simone 游戏!
//
void loop()
{
// loops waiting for player input
delay(10);
int intButtonPressed = ButtonPressed();
if (intButtonPressed != intButtonLast)
{
intButtonLast = intButtonPressed;
if (intButtonPressed != 0)
{
// when player presses a button LED/Tone reflect player input
LED_On(intButtonPressed);
// player input string has last input appended to it
strPlayerInput.concat((char)((int)'0' + intButtonPressed));
// if the player's input is correct
if (ComparePlayerInputWithPuzzle())
{
// if the player has entered the entire puzzle correctly
if (strPuzzle.length() == strPlayerInput.length())
{
// the puzzle has one more note added to it,
// it is played back for the player and player input is erased
Puzzle_AddTone();
Puzzle_Play();
strPlayerInput = "";
intButtonLast = -1;
}
}
else
{
PlayerInputIncorrect();
}
}
else
LED_On(0); // turns off all LEDs
}
}
//
接线
在上方的图表中,您可以看到所有部件的连接方式。LCD1602 可能有点吓人,我知道每当我制作包含它的项目时,我都会花额外的时间来正确设置它,但如果你看看下面的图表(我处理任何与 LCD 相关的东西的路线图),你应该能搞定。图片中的两个按钮是多余的,但接线是正确的。您可能需要选择不同的 Arduino 引脚进行连接,但您所要做的就是确保在声明 LiquidCrystal 时,按照下面代码中所示的方式标识正确的引脚。
关注点
输入按钮通过分压器配置区分。也就是说,每个按钮串联一个不同的电阻,然后该电阻与所有按钮共用的一个电阻相连。当按下任何按钮时,该按钮对应的电阻上的电压降由模拟引脚测量,代码将读取的电压值通过调用 analogRead()
来确定按下了哪个按钮。如果您想了解更多关于使用分压器控制一个模拟引脚上的多个按钮的知识,请阅读我的 Reps Counter 文章 或我专门关于使用分压器控制 按钮矩阵 的另一篇文章。这是一个简单的概念,但好处是您可以使用单个模拟引脚来控制大量按钮,而无需依赖 74HC165 移位寄存器。
最初(首次发布时)有一个去抖动问题。按钮的问题在于,在现实世界中,电压不会瞬间从零变为 VCC。在最好的情况下,有一个短暂的(纳秒级)垂直过渡,当用户按下按钮时,电压会从一个值增加/减少到另一个值。此外,按钮本身会接触 - 断开接触并弹跳几次,然后再稳定到其物理位置,即闭合或断开电路。当 Arduino 依赖于其模拟引脚上的精确电压测量来确定用户按下了哪个按钮时,这会引起问题。如果 Arduino 在电压转换期间轮询输入模拟引脚,它很可能会错误地读取电压。为了解决这个问题,ButtonPressed() 方法现在会轮询输入引脚两次,两次读取之间有很短(20 毫秒)的延迟。如果这两次读取都显示按下了同一个按钮(或者根本没有按按钮),那么它会返回正确的值;否则,它会忽略用户输入并返回零(没有按下按钮)。以前,当您玩游戏时,有时 Simone 会告诉您错了,而您确信自己是对的,这有点令人沮丧。现在她知道正确答案了……好多了。
我的设备有一个连接在蜂鸣器和微控制器之间的电位器(包括连接到 LCD 的电位器,共两个)。蜂鸣器的电位器为玩家提供了音量控制,这对于那些忍受您空闲时间的人来说可能会很感激。我还有一个用过的手机电池和一块锂离子充电器。连接起来相当容易,但电池充满电后只能产生不到 4V 的电压,所以 LCD 的亮度不会太高。效果还是挺好的。
历史
- 2021 年 3 月 9 日:初始版本
- 2022 年 1 月 4 日 - 修复了按钮的“去抖动”问题