ハラハラドキドキ「うさぎさん危機一髪ゲーム」を作ろう!アイデア・ハック!! Arduinoで遊ぼう(4)(2/3 ページ)

» 2013年10月03日 10時00分 公開
[三月兎MONOist]

Arduinoでメロディーを奏でよう!

 それでは、Arduinoの統合開発環境「Arduino IDE」で、スケッチ(プログラム)を作成していきましょう(スケッチ1)。


#include "pitches.h"
 
//-----------------------
// 定数の定義
//-----------------------
const int BZ = 2;                //ブザー(TMP36)の出力ピン
 
const int nos = 5;               //スイッチの数
const int SW[nos] = {3,4,5,6,7}; //各スイッチの入力ピン番号
//const int BOM = 10;            //電磁石ピンの出力ピン(オプション)
 
//スイッチの回路は負論理なので、ONがLOWになる
const int SW_ON = LOW;
const int SW_OFF = HIGH;
 
//-----------------------
// グローバル変数の定義
//-----------------------
int G_old_val[nos] = {SW_OFF, SW_OFF, SW_OFF, SW_OFF, SW_OFF}; //前回のスイッチの値
int G_sw_val;
 
void setup() {
    pinMode(BZ, OUTPUT);        //ブザーを出力モードに設定
 
    //スイッチを全て入力モードに設定
    for(int i = 0; i < nos; i++){
      pinMode(SW[i], INPUT);
    }
//    pinMode(BOM, OUTPUT);       //電磁石ピンを出力モードに設定(オプション)
 
    randomSeed(analogRead(A0)); //乱数の初期設定に未接続ピンのノイズを利用
//  digitalWrite(BOM, HIGH);    //電磁石の電流を流す(オプション)
    bz_start();                 //ゲームスタート音楽
}
 
void loop() {
    int int_swNumber = -1;      //何も押してないときの番号を設定
    int int_rand = random(nos); //ランダムでハズレスイッチ番号を決定する
 
    //スイッチ1〜5の状態を取得
    for(int i = 0; i < nos; i++){
       G_sw_val = digitalRead(SW[i]);    //スイッチの状態を読み取る
       if(G_sw_val == SW_ON && G_old_val[i] == SW_OFF){
          int_swNumber = i;              //スイッチの番号を取得
       }
       G_old_val[i] = G_sw_val;          //スイッチの値を保存
    }
 
    //スイッチの入力があったとき
    if(int_swNumber != -1){
            //ハズレスイッチ番号が押されたら、ゲーム終了
            if(int_rand == int_swNumber){
                bz_ending();                //エンディング音楽
//        digitalWrite(BOM, LOW);           //電磁石の電流をカット
            } //クリア音を流す
            else{
                bz_levelup();
            }
    }
}
スケッチ1 「うさぎさん危機一髪ゲーム」。乱数でハズレスイッチ番号を決めて、ゲームの判定をしている

 1行目の#includeで、「pitches.h」を読み込んでいます。これは、音階を宣言したファイルで、Arduinoのサンプルスケッチ「toneMelody」に入っています。この音階を使用して、ゲーム用のメロディーを作りました。

 31行目のrandomSeed()は、乱数を発生するための初期処理です。使用していないアナログ入力ピン(A0)のノイズを引数にすることで、random()使用時に毎回違う値を取得できるようになります。

 36行目から始まるloop()の中で、ゲームの判定を行います。int_swNumber変数にスイッチが押されていないときの番号「−1」をセットした後(37行目)、ランダム関数でハズレスイッチ番号を選んでいます(38行目)。

 41〜47行目は、スイッチ1〜5までの入力値を見て、スイッチの状態をチェックしています。スイッチが押されていた場合は、int_swNumberにスイッチ番号を取得します(44行目)。

 スイッチが押されていたときは、50〜59行目が実行され、アタリ/ハズレの判定を行い、それぞれに該当するメロディーを呼び出します。

 今回、toneMelody()とゲームスタートを含む3曲分の楽譜を、ユーザー関数として作成しました。Arudino IDEには、音を鳴らすためのtone()が用意されています。tone()は引数に、出力するピン番号、周波数を指定して、メロディーを奏でることができます。

 toneMelody()と、ゲームスタートのbz_start()でメロディーの作り方を見てみましょう(スケッチ2)。

//-----------------------------------
// 指定した音階と長さでブザーを鳴らす
// note:音階  duration:長さ
//-----------------------------------
void toneMelody(int note, int duration){
  int noteDuration = 1000 / duration;    //音の長さを決める
  tone(BZ, note);                        //ブザーを指定周波数
  delay(noteDuration);                   //指定時間 鳴らす
 
  //音の切れ目を作る
  noteDuration = noteDuration * 0.1;    //長さを決めている
  noTone(BZ);                           //ブザーへの出力を止める
  delay(noteDuration);                  //指定時間保つ
}
 
//-----------------------
// スタート
//-----------------------
void bz_start(){
  int melody[] = {NOTE_G5, NOTE_G5, 0, NOTE_G5, NOTE_F5, NOTE_G5, NOTE_AS5};
  int noteDurations[] = {8,8,8,4,8,4,4};
  for (int i = 0; i < 7; i++) {
    toneMelody(melody[i], noteDurations[i]);
  }
スケッチ2 ゲーム開始時に流す曲。誰もが知っている懐かしいメロディーをマネてみた

 toneMelody()は、引数に音階と音の長さを指定して呼び出します。実際に鳴らす音の長さは計算で求めます。durationが「8」の場合は、1000÷8=125、つまり125ミリ秒間だけ音が鳴ります(5行目)。

 tone()の引数に、出力するピン、周波数を指定し、delay()で出力する時間を指定しています(7〜8行目)。音と音が連続すると曲が歯切れよく聞こえないので、noTone()で音を止めます(12〜13行目)。

 bz_start()には、音階と長さを記録してあります。要するに、これが楽譜です。20行目のmelody配列の要素は、「pitches.h」に宣言されている音階です。「pitches.h」には、B0〜DS8まで8オクターブの音(周波数)が定義されています。noteDurations配列には、melodyに入れた音の長さを要素として宣言します。

 for文で配列の要素をループして、toneMelody()を呼び出せばブザーが鳴ります。

 レベルアップとエンディングの音階は、ファイルに入っているのでダウンロードして確認してください。

>>スケッチ(mono04_game.zip)のダウンロードはこちら

Copyright © ITmedia, Inc. All Rights Reserved.