PR

キャラクターが音声で応援してくれる脳トレーニングアプリを作ってみよう

2014年1月9日(木)
薬師寺 国安

ロジックコードを記述する

※コードが長くなるため、今回のテーマと肝となる「数値をランダムに表示させる」並びに「音声認識」の部分をメインに解説しています。名前空間の読み込み、メンバー変数の宣言も省略しています。全てのコードを見る場合は、サンプルをダウンロードして見てください。

リスト2 (MainWindow.xaml.vb)

‘ RandomInfoというクラス内に、「乱数」という数値型のプロパティを定義しておきます。

Public Class RandomInfo
  Public Property 乱数 As Integer
End Class

ランダムな数値を表示する処理

新しいRandomのインスタンスRndオブジェクトを作成します。
数値型の変数myRndを宣言し0で初期化します。添え字が31の数値型配列変数myArray(31)を宣言します。
RandomInfoクラス型の新しいリストである、myRandomInfo変数を宣言します。
最初に、繰り返し変数iで1から31までを繰り返し、配列変数myArrayに格納しておきます。
同様に、繰り返し変数iで1から31までを繰り返し、以下の処理を行います。

myRnd = Rnd.Next(i, 31)

ここで、最少がiで最大が31までのランダムな数を生成し、変数myRndに格納します。

このままでは、重複した乱数が表示されるため、myRndで初期化された配列変数myArrayをtemp変数に格納します。myRndを配列に持つmyArrayにmyArray(i)の値を代入します。最後にmyArray(i)にtempの値を代入します。これで重複しない1から31までの数値が表示されます。しかし、数値は30までの表示でいいので、繰り返し変数iが31より小さかった時だけ、RandomInfoクラスの「乱数」プロパティにmyArray(i)の値を指定して、AddメソッドでmyRandomInfoに追加していきます。
最終的には30までの数字しか表示しないので、1から30までの繰り返しでいいのでは、と思われるかもしれませんが、それでは、必ず30の値が常に、最後に表示されてしまいます。1から29まではランダムに並びますが、30は常に最後に表示されます。そこで、31までの乱数を発生させて、その中から30までのランダムな数字を表示させています。
GridViewのItemsSourceプロパティにmyRandomInfoオブジェクトを指定します。これで、1から30までのランダムな数字が表示されます。

Private Sub DataShow()
  myCount = 0
  Rnd = New Random
  Dim myRnd As Integer = 0
  Dim temp As Integer = 0
  Dim myArray(31) As Integer
  Dim myRandomInfo As New List(Of RandomInfo)
  For i As Integer = 1 To 31
    myArray(i) = i
  Next
 
  For i As Integer = 1 To 31
    myRnd = Rnd.Next(i, 31)
    temp = myArray(myRnd)
    myArray(myRnd) = myArray(i)
    myArray(i) = temp
    If i < 31 Then
      myRandomInfo.Add(New RandomInfo With {.乱数 = myArray(i)})
    End If
  Next
  GridView1.ItemsSource = myRandomInfo
End Sub

ランダムに並んでいる数字を選択した時の処理

メンバー変数noの値を1ずつ増加させます。変数myNoに、GridView1から選択された項目を、RandamInfoクラスにキャストして、その「乱数」プロパティの値を取得して格納しておきます。
取得した乱数の値が1ずつ増加するメンバー変数noと同じなら、非表示になっているdummyTextBox内にその値を表示させます。そうでない場合は、エラー音を発生させて、1ずつ増加させていたメンバー変数noの値を1ずつ減少させます。
メンバー変数myCountの値が、ComboBoxから選択された値を格納しているメンバー変数mySecondと同じか小さく、且つ、「乱数」プロパティの値が「30」で、且つメンバー変数noの値が「30」なら、クリアしたことになるので、EndMessageメソッドを実行します。メンバー変数_secondの値を0で初期化します。_secondメンバー変数にはComboBoxから選択された秒数が格納されているメンバー変数です。

  Private Sub GridView1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles GridView1.SelectionChanged
    Try
      no += 1
      flagNo = no
      Dim myNo = DirectCast(GridView1.SelectedItem, RandomInfo).乱数
      If myNo = no Then
        dummyTextBox.Text = flagNo
      Else
        MediaElement1.Play()
        no -= 1
      End If

      If myCount <= mySecond AndAlso DirectCast(GridView1.SelectedItem, RandomInfo).乱数 = "30" AndAlso no = 30 Then
        EndMessage()
        _second = 0
      End If
    Catch
      Exit Sub
    End Try
  End Sub

[開始]ボタンがタップされた時の処理

メッセージを表示させるmessageTextBlockを非表示にします。ComboBoxからの秒数の選択を不可とします。
ランダムな数値を表示させるDataShowメソッドを実行します。[開始]ボタンの使用を不可とします。
新しいDispatcherTimerクラスのインスタンスmyTimerオブジェクトを作成します。Intervalに「1秒」を指定します。
AddHandlerステートメントで、指定したタイマーの間隔が経過し、タイマーが有効である場合に発生するTickイベントに、myTimer_Tickイベントハンドラを指定します。Startメソッドでタイマーを開始します。

  Private Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click
    messageTextBlock.Visibility = Windows.UI.Xaml.Visibility.Collapsed
    ComboBox1.IsEnabled = False
    DataShow()
    StartButton.IsEnabled = False
    myTimer = New DispatcherTimer
    myTimer.Interval = New TimeSpan(0, 0, 1)
    AddHandler myTimer.Tick, AddressOf myTimer_Tick
    myTimer.Start()
  End Sub

指定したタイマーの間隔が経過し、タイマーが有効である場合に発生するTickイベント処理

指定した秒数内でクリアできた場合はEndMessageメソッドを実行します。指定した秒数内にクリアできなかった場合は、FalseMessageメソッドを実行します。このFalseMessageメソッド処理は省略しています。ダウンロードしたサンプルのソースコードを参照してください。
それ以外の場合は、秒数を1ずつ減算し、メンバー変数myCountを1ずつ増加させます。timeTextBlockに秒数がマイナスされながら表示されます。

  Private Sub myTimer_Tick()
    If myCount <= mySecond AndAlso no.Equals(dummyTextBox.Text) Then
      EndMessage()
      _second = 0
      timeTextBlock.Text = "残り" & _second & "秒"
      Exit Sub
    ElseIf myCount > mySecond AndAlso Not no.Equals(dummyTextBox.Text) Then
      _second = 0
      timeTextBlock.Text = "残り" & _second & "秒"
      FalseMessage()
      Exit Sub
    Else
      timeTextBlock.Text = "残り" & _second & "秒"
      _second -= 1
      myCount += 1
    End If

  End Sub

クリアできた時の処理

タイマーを停止。ランダムに表示されていた数字をクリアします。
キャラクターに喋らせる言葉を格納するメンバー変数readingTextに値を指定しています。
syokoVoiceタスクを実行。messageTextBlockに「おめでとうございます!」と表示し、非表示から表示状態に切り替えます。
メンバー変数noを0で初期化します。秒数が格納されているメンバー変数_secondを0で初期化します。
timeTextBlockに残り時間を表示し、選択された数値を表示させていたdummyTextBox(非表示)内を空にします。ComboBox1の選択を可能にし、ComboBox1で選択されていた項目を解除します。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。

  Private Async Sub EndMessage()
    myTimer.Stop()
    GridView1.ItemsSource = Nothing
    'GridView1.IsEnabled = False
    readingText = "おめでとうございます。時間内にクリアできました。"
    Await syokoVoice()
    messageTextBlock.Text = "おめでとうございます!"
    messageTextBlock.Visibility = Windows.UI.Xaml.Visibility.Visible
    no = 0
    _second = 0
    timeTextBlock.Text = "残り" & _second & "秒"
    dummyTextBox.Text = String.Empty
    ComboBox1.IsEnabled = True
    ComboBox1.SelectedIndex = -1
    'RemoveHandler myTimer.Tick, AddressOf myTimer_Tick
  End Sub

結果をキャラクターが音声で喋る処理

この処理は、ここでは省略しているEndMessageやFalseMessageメソッドから呼び出しています。詳しくはダウンロードしたサンプルのソースコードを参照してください。
MediaElement型のmyMedia変数を宣言し、syokoMediaElementで初期化しておきます。
音声機能へのアクセスを提供する、新しいSpeechSynthesizerのインスタンス、synthオブジェクトを作成します。
SynthesizeTextToStreamAsyncメソッドで、指定した文字列から、音声出力を非同期に生成します。
SetSourceメソッドで、指定されたストリームおよびMIME型を使用してSourceプロパティを設定します。Playメソッドで音声を再生します。
音声にどんな言語で、どのような声で喋らすかは、SpeechSynthesizerのVoiceプロパティで参照できます。下記のURLを参照してください。
> SpeechSynthesizer.Voice | voice property

上記ページによると、Japanese JA は性別が「Female」で、名前は「Haruka」という女性が読み上げるようです。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。

Private Async Function syokoVoice() As Task
  Dim myMedia As MediaElement = Me.syokoMediaElement
  Dim synth = New Windows.Media.SpeechSynthesis.SpeechSynthesizer
  Dim stream = Await synth.SynthesizeTextToStreamAsync(readingText)
  myMedia.SetSource(stream, stream.ContentType)
  myMedia.Play()
End Function

今回はここまでです。次回の記事をお楽しみに。

Think IT会員限定特典
  • キャラクターが音声で応援する脳トレーニングアプリのサンプルプログラム

    『Windows 8.1+Visual Studio 2013によるWindows ストア・アプリ開発実例集』 第1回のサンプルプログラムです。
薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

他にもこの記事が読まれています