Menu
CoddyTech

Simon:完整游戏

本课属于 Coddy Arduino 学习旅程的“项目”单元。第 16 课,共 24 课。

真正的 Simon 游戏从简单开始,逐渐增加难度。第 1 轮播放一种颜色。每次你正确重复一轮,棋盘都会保持原有颜色,并在末尾增加一种颜色,直到你出错为止。

数组需要为长时间的游戏留出空间,还需要一个变量 length 来记录其中有多少空间已被使用。添加一种颜色需要两行:

sequence[length] = random(4);
length++;

游戏开始时只设置一次随机数种子。现在,playSequence() 会播放 length 种颜色,而不是四种。当 step 达到 length 时,一轮就结束。

出错时,游戏会结束,并播放一个明显不是音符的声音,频率为 110 Hz,持续一秒,还会打印分数:已完成的轮数,即 length - 1,因为失败的那一轮不计入分数。

数组有 20 个位置,程序绝不能写到数组末尾之外,因此,玩家正确重复 20 种颜色就能获胜。

challenge icon

挑战

困难

把它变成完整的游戏:

  • const int MAX_STEPS = 20;、int sequence[MAX_STEPS]; 和 int length = 0;
  • 游戏从一个颜色开始;每轮正确重复后,增加一个颜色并播放全部颜色
  • 出错时:播放 110 Hz 的声音,持续 1000 ms,然后输出 Game over! Score: 和分数,并结束游戏
  • 正确重复 20 个颜色后:输出 You win! 并结束游戏

点击运行,看看你能进行到哪一轮,然后点击检查。

亲手试试

// 每种颜色对应一个条目:红、绿、蓝、黄
const int ledPins[4] = {9, 10, 11, 12};
const int buttonPins[4] = {2, 3, 4, 5};
const int notes[4] = {262, 330, 392, 523};  // C、E、G 和高音 C
const int buzzerPin = 8;

int lastState[4] = {HIGH, HIGH, HIGH, HIGH};  // 每个按钮上一次的读取值

int sequence[4];       // 电路板依次亮起的颜色
bool playing = false;  // 按下按钮开始游戏前,值为 false
int step = 0;          // 玩家已重复的颜色数量

// 点亮颜色 i,并播放对应的音符。
void lightOn(int i) {
  digitalWrite(ledPins[i], HIGH);
  tone(buzzerPin, notes[i]);
}

// 关闭颜色 i 的灯,并停止播放声音。
void lightOff(int i) {
  digitalWrite(ledPins[i], LOW);
  noTone(buzzerPin);
}

// 播放序列:每种颜色亮起 400 ms,然后静音 200 ms。
void playSequence() {
  delay(500);
  for (int i = 0; i < 4; i++) {
    lightOn(sequence[i]);
    delay(400);
    lightOff(sequence[i]);
    delay(200);
  }
}

// 随机生成一个新序列并播放。
void startGame() {
  randomSeed(micros());
  for (int i = 0; i < 4; i++) {
    sequence[i] = random(4);
  }
  playing = true;
  step = 0;
  playSequence();
}

// 玩家松开颜色 i 的按钮:它是序列中的下一个吗?
void checkPress(int i) {
  if (i != sequence[step]) {
    Serial.println("Wrong!");
    playing = false;
    return;
  }
  step++;
  if (step == 4) {
    Serial.println("Well done!");
    playing = false;
  }
}

void setup() {
  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  Serial.begin(9600);
}

void loop() {
  for (int i = 0; i < 4; i++) {
    int state = digitalRead(buttonPins[i]);
    if (state == LOW && lastState[i] == HIGH) {  // 按下
      lightOn(i);
    }
    if (state == HIGH && lastState[i] == LOW) {  // 松开
      lightOff(i);
      if (playing == false) {
        startGame();
      } else {
        checkPress(i);
      }
    }
    lastState[i] = state;
  }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

项目中的所有课

自己练习: Arduino 在线编辑器