Arduino 平台 - SIMON 游戏实现
使用Arduino平台实现Simon游戏。
引言
作为CodeProject的会员已经好几年了,但我一直没有发表过文章,这让我有点失望。我多次思考过我能写些什么样的文章。然后,在CodeProject上看到jeffb42的一些优秀文章后,我的问题解决了。
大约两个月前,我开始接触Arduino硬件平台,此前我一直在寻找合适的工具来实现我心中的一些家居项目。为了能够使用该设备,我首先必须了解它的功能。
本文将探讨如何克服使用Arduino平台运行Simon游戏克隆版的问题,因为它演示了处理此硬件平台上的主应用程序循环约束和代码重用的方法。
对于不熟悉Simon游戏的人来说,这是一款70年代早期的电子游戏,玩家基本上必须重复向控制台输入一个序列才能进入下一关。在我的游戏中,玩家可以选择循序渐进模式,游戏会将上一关的序列作为下一关的开头,然后在末尾添加一个随机步骤;或者可以选择随机模式,游戏的每一关都会生成一个新的随机序列,每个序列都比前一个长。
jeffb42的Arduino入门和LCD接口文章提供了更多关于Arduino平台细节的信息,在我的网站上,我还有一些关于一些基本IO的示例,因此这里不再赘述。
背景
在Arduino上构建这个游戏的挑战在于该平台的工作方式。在源代码中,有三个区域可以放置代码:初始化区域、setup方法和loop方法。这些方法按此顺序执行。
//initialisation section
// Library references and variable/constant declarations contained here
void setup()
{
//This method runs once
//Hardware allocation done here e.g. input/output pin directions
}
void loop()
{
//This method will run until power is removed or a new program is
//uploaded to the platform
}
挑战在于能够使代码以这样一种方式运行:游戏可以在两种模式下反复玩,而不会陷入无限循环。
Using the Code
硬件需求的原理图包含在下载文件中,源代码也包含在内。如果你拥有必要的组件,你可以构建游戏并将代码上传到Arduino使其工作。或者,如果你刚开始接触该平台或类似平台,这段代码可以为你提供一些如何在自己的项目中实现类似目标的想法。
游戏结构
我们需要能够使游戏代码在无限循环中运行,实现这一点的一种方法是使用标志。布尔变量(真或假)是实现此目的最简单的方法之一。查看游戏的工作方式,需要一些基本的标志。它们保存游戏的状态,即游戏是否已开始,游戏是否已玩过,以及游戏是否结束。还需要其他几个变量来跟踪生成的步骤序列以及用户当前处于哪个关卡。这些需求以及硬件引脚分配都在代码的初始化部分中进行了标识。
#include <LiquidCrystal.h>
//initialise the library with the numbers of the interface pins
LiquidCrystal lcd(13,12,11,10,9,8);
int userInput = 0; //Analog pin for user input from buttons
int led1 = 2; //LED 1
int led2 = 3; //LED 2
int led3 = 4; //LED 3
int led4 = 5; //LED 4
int speaker = 6; //Speaker
//Game Stats
boolean started = false; //Has the game started yet
boolean gameover = false; //Has the game ended
int level = 0; //What level is the user on (Score at end = level -1)
int gameMode = 0; //Which game mode is being used
// 1 = Progressive
// 2 = Random
boolean soundEnabled = true; //Is the sound enabled or not
int lastLevelSeq[50]; //The sequence for the steps used
//in progressive mode previous level
//Also used by game over to replay correct sequence back
//Nobody can get passed 50, surely!
代码的下一部分是`setup()`方法。在这里初始化硬件引脚。
void setup()
{
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(speaker, OUTPUT);
//Set up the LCD Col and Row count
lcd.begin(16,2);
delay(100);
lcd.clear();
lcd.print("Welcome to");
lcd.setCursor(0,1);
lcd.print("Arduino SIMON");
//...........rest of setup code snipped. see the download.
从这里开始,接下来执行的是`loop()`方法,该方法会无限期地运行,因此需要跟踪游戏状态。此外,为了使代码更短、更高效,使用了一些辅助方法来满足文章开头提到的代码重用要求。
//used to determine which button the user is pressing
getButtonPressed()
//Play a given sound
playTone(tone)
//This is the actual game level, it returns boolean true
//is user success or false if user failed
doLevel(level)
//Turn on a given led, or 0 to turn them all off
lightLed(led)
//This will play a sound and light the appropriate
//led using the other helper methods
playStep(step)
主要的loop()
结构如下所示(所有细节都被剥离以留下结构)
void loop()
{
while (started == false)
{
if (getButtonPressed() > 0)
{
//This part waits for the user to press a button to start the game
}
}
while (gameMode == 0)
{
switch (getButtonPressed())
{
case 1:
//The user pressed button 1 for Progressive Mode
break;
case 2:
//The user pressed button 2 for Random Mode
break;
case 4:
soundEnabled = (!soundEnabled);
//The user user is pressing Button 4 toggling the sound on and off
break;
}
}
while (gameover == false)
{
if (doLevel(level)==true)
{
//The user played a level and got it correct
}
else
{
//Level Wrong, set game over
}
}
if (gameover == true)
{
//The game is now over, playback the correct sequence
}
//Wait for user
while (gameover == true)
{
if (getButtonPressed() > 0)
{
//Wait for the user to press a button to go back to the start menu
}
}
}
想出一个结构最简单的方法是在脑海中玩游戏,并按块写下所需的每个步骤;由此,你可以构建流程图,然后构建代码结构。
关注点
鉴于可用的数字IO引脚数量有限,四个按钮实际上通过电阻网络连接到模拟输入引脚。按下每个按钮都会改变模拟输入的值;根据该值,可以使用`getButtonPressed()`方法确定按下哪个按钮。此外,模拟信号的波动可能会导致一些差异,必须使用合适的电阻尺寸来提供足够的输入值间距。
/*
Read the analog input and determine which button is pressed
*/
int getButtonPressed()
{
// What is the pushbutton resistor matrix value
int userValue = 0;
userValue = analogRead(userInput);
int buttonPressed = 0;
if (userValue > 850)
{
buttonPressed = 0;
//No Button Pressed
}
if (userValue < 850)
{
buttonPressed = 4;
// Maybe Button 4 still to check others
}
if (userValue < 800)
{
buttonPressed = 3;
// Maybe Button 3 still to check others
}
if (userValue < 700)
{
buttonPressed = 2;
// Maybe Button 2 still to check last one
}
if (userValue < 600)
{
buttonPressed = 1;
// Done Checking buttons
}
return buttonPressed;
}
总的来说,作为我自己的第一个Arduino项目,这让我很好地挑战了自己,想出了一个满足游戏需求的结构良好的代码。
历史
- 2009年10月25日 - 文章的第一个版本。