Arduino開発入門-動かなければ勝ちゲームを作ってみた

#はじめに
Arduino開発の入門として、簡単なゲームを作成してみました。

#概要
動かなければ勝ちゲームを作成します。
1分間、センサーに感知されないように動きを止めて監視をくぐり抜けるゲームです。

#仕様
・電源が入ったらゲームスタート。
・ゲームをスタートしてから1分間、人感センサーに動きを感知されなければゲームクリア。
・動きを感知されたらゲームオーバー。
・ゲームクリア、ゲームオーバー時にLEDを点灯。
・再度ゲームを始めるにはArduinoのリセットボタンを押し、リセットする。

#構成
・Arduino Uno R3
・LCDディスプレイ(I2Cモジュール付）
・人感センサー

#フロー
![フロー.png](https://qiita-image-store.s3.amazonaws.com/0/191429/a2637567-d4c5-e553-d805-a009eb00838a.png)

#詰まった所
・LCD液晶に文字が表示されなかった。	
　原因：I2C アドレスが間違っていた。
　解決：下記のURLを参考にアドレスを調べて設定しました。
  URL：http://ht-deko.com/arduino/lcd_i2c.html

　原因：ディスプレイの輝度が明る過ぎて文字が見えていなかった。
　解決：下記のURLを参考にI2CモジュールのLCD Constractの設定を変更したら表示できました。
  URL：http://ht-deko.com/arduino/lcd_i2c.html

#回路図
![Arduino_Uno_i2C_LCD_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/191429/07be129c-81dc-7c98-93ea-087714b4ef9a.png)

#完成イメージ
![IMG_2306.jpg](https://qiita-image-store.s3.amazonaws.com/0/191429/15baec07-e11e-b710-8efa-42590888b124.jpeg)

#ソースコード
```cpp
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 16, 2);

//----------------------------
// 人感センサー
#define SWITCH_SOCKET 2

//----------------------------
// LED制御
#define LED_SOCKET 10

//----------------------------
// Geme 制御
#define STATE_START 0 // ゲームスタート
#define STATE_RUN 1 // ゲーム実行中
#define STATE_GEME_OVER 9 // ゲームオーバー
#define STATE_GEME_CLEAR 8 // ゲームクリア

#define START_START_TIME 2000

int m_state = STATE_START;
 
void setup() {
  Serial.begin(9600);

  //-------------------------
  // PIN MODE 設定
  pinMode(LED_SOCKET,OUTPUT);
  pinMode(SWITCH_SOCKET, INPUT);

  //-------------------------
  // LED設定
  digitalWrite(LED_SOCKET,LOW);
  
  //-------------------------
  // LCD設定
  lcd.init();
  lcd.backlight();
}

void loop() {
  //--------------------------
  // 経過時間を取得
  unsigned long time_m = millis() - START_START_TIME;

  if(m_state == STATE_RUN)
  {
    //----------------------------
    // 人感センサー
    // 動きを感知したらゲームオーバー
    int val = digitalRead(SWITCH_SOCKET);
    if(val == 1){
      m_state = STATE_GEME_OVER;
      lcd.clear();
    }
  
    // 経過時間を監視
    // 1分過ぎたらゲームクリア
    int m = (time_m / 1000) / 60;
    m = m % 60;
    if(m >= 1){
      m_state = STATE_GEME_CLEAR;
      lcd.clear();
    }
  }
  
  // 状態に応じて表示を切り替え
  switch (m_state) {
  case STATE_START:
    lcd.setCursor(0, 0);
    lcd.print("Game Start !!");
    lcd.setCursor(0, 1);
    lcd.print("Don't move！");
      
    m_state = STATE_RUN;
    delay(START_START_TIME);
    lcd.clear();
    break;
    
  case STATE_RUN:
    // 現在時刻を表示
    DispCountTimer(time_m);
    break;
    
  case STATE_GEME_OVER:
    
    lcd.setCursor(0, 0);
    lcd.print("Game Over,,");

    analogWrite(LED_SOCKET, 124);
    digitalWrite(LED_SOCKET,HIGH);
        
    break;
    
  case STATE_GEME_CLEAR:
    lcd.setCursor(0, 0);
    lcd.print("Game Clear!!");

    analogWrite(LED_SOCKET, 124);
    digitalWrite(LED_SOCKET,HIGH);
    
    break;
  }
  
  delay(500);
  
}

/**
 * 現在時刻を表示
 */
void DispCountTimer(unsigned long time_m)
{
  int s = (time_m / 1000) % 60;
  int m = (time_m / 1000) / 60;
  m = m % 60;
  int h = (time_m / 1000) / 60 / 60;
  
  lcd.setCursor(0, 0);
  lcd.print(StringTwoZero(String(h)) + ":" + StringTwoZero(String(m))  + ":" + StringTwoZero(String(s)) );
 
}

/**
 * 2桁の前ゼロ変換
 */
String StringTwoZero(String val)
{
  val = "00" + val;
  return val.substring(val.length() - 2);
}
```

#参考にしたサイト
LCDディスプレイに文字を表示：
http://ht-deko.com/arduino/lcd_i2c.html

#最後に
LCDディスプレイの表示が思うようにされず時間がかかりましたが、ブログで技術展開してくれている皆様のおかげで、なんとか完成できました。ありがとうございました。

人感センサーの感度を高く設定していると呼吸をしただけでゲームオーバーとなるので、感度は下げるのがいいかと思います。

また、ゲームとしてだけでなく仕事の集中力が切れた時などにこのゲームを行うと、集中力を回復することが出来るので、ぜひご利用ください。