ITエンジニアのための勉強会・イベントレポート情報メディア

Unityで作ろう!ゲームアルゴリズム(15)音ゲーのアルゴリズムを作ってみる その3(ゲーム実装編)
skill

Unityで作ろう!ゲームアルゴリズム(15)
音ゲーのアルゴリズムを作ってみる その3(ゲーム実装編)

2018.02.08

 
  • このエントリーをはてなブックマークに追加

コンニチワ。
大炎上中の案件に入り、人間らしい生活ができていない筆者です。

こんなときに筆者が心の拠り所にしているのは、社会人になりたてのころに上司からかけられた「どんな案件もいつか終わる」という言葉。

当たり前で何のことは無い言葉ですが、確かにそのとおりなんですよね。
大変な状況もいつか終わるってことが意識できれば、心がちょっぴり軽くなるワケで。

さて、今回はいよいよ音ゲーの実装に入りますよ。

賀好 昭仁

要件を洗い出してみる

音ゲーのサンプルを作るにあたって、今回目指すゴールは

  • ・曲に合わせてノートが流れてくる
  • ・ノートに合わせてキーを叩けばスコアが増える
  • ・キーを叩くタイミングが良いほどスコアが上がる
  • ・何度か失敗したらゲームオーバー

としてみましょう。

では早速実装を・・・おっと、その前にやるべきことがありました。

録音データをファイル化する

前回、楽譜データを作るために自分の演奏を録音できるようにしました。
ただ、今は録音データを変数に持っているだけですので、ゲームを閉じると消えてしまいます。
ということで、まずは録音データの保存処理を作りましょう。

方法はと言うと、Unity5.3から実装されたJsonUtilityというクラスを使います。
https://docs.unity3d.com/jp/540/ScriptReference/JsonUtility.html

これを使えば、オブジェクトを丸ごとJSON文字列に変換(シリアライズ)することができます。

JSONについて

ゲーム開発において、JSONのお世話になることは多々あります。(Unity本体に組み込まれたという点からも、うかがい知ることができますね)
良い機会ですので、JSONについてざっとご説明します。

JSONはデータの記述フォーマットで、元はJavaScriptをベースにしたものです。
データの中身は"キー":"内容"の組み合わせで構成されるわかりやすいもので、数値や文字列などデータ型も持てるという特徴があり、現在はJavaScriptのみならず、さまざまなプログラミング言語で簡単にJSONを扱えるようになっています。そのため、異なる言語間の通信をJSONで行うこともしばしば。

カンマ区切りのCSVも扱いやすいデータですが、JSONは階層を持てる点で大きなアドバンテージがあると言えるでしょう。反面、CSVと比べるとデータサイズは大きくなります。

JSONにシリアライズしてみた

録音データをJSONにシリアライズし、任意のディレクトリに出力する仕組みを実装しました。

使い方は以下の通りで、とってもカンタン。

var songData = new SongData();
録音データをsongData.notesに投入
songData.Save("保存先パス");

実装の詳細は、サンプルプロジェクトの
Assets/Scripts/Common/Data/SongData.cs
をどうぞ。

余談:JsonUtilityを使うときの注意点
とっても便利なJsonUtilityですが、ちょっぴりクセがあります。
以下の2点を心に留めておきましょう。

・Dictionary型は扱えない
Dictionary型はよく使うので少々残念ですが、扱えないものはしょうがない(笑)。
ただ、C#にはLINQという強力なクエリ機能がありますので、大抵の場合はList型+LINQで事足りるでしょう。

・列挙型を直接シリアライズ/デシリアライズすることはできない
JsonUtility.FromJson<List<string>>のように、列挙型を直接扱うことはできません。
列挙型のフィールドを持つクラスを作ってあげましょう。

楽譜データのズレを補正する

さて、メイン処理を実装する前に、もうワンステップ踏みましょう。

今回の楽譜データ作成ツールは「演奏を録音するツール」です。

そのため、どれだけ頑張って演奏しても、意図したタイミングと誤差が出てしまいます。

そこで、あらかじめ決められたタイミングでしか音符を置けないようにし、それ以外のタイミングで音符を置こうとしたときは自動的に一番近いタイミングに補正するよう調整してみます。

ズレの補正にBPMを使ってみる

BPMとはBeats Per Minuteの略で、演奏のテンポ(曲の速さ)を表すための単位です。BPMの値は「1分間に4分音符が何回鳴るか」を表しています。
今回はこのBPMを使って、「16分音符のタイミングでしか音符を置けない」ようにしたいとします。

まず、今回のサンプル楽曲のテンポは120BPMです。1分=60秒ですので、120BPMでの4分音符の長さは60 / 120 = 0.5秒となります。
そして、16分音符は4分音符の1/4の長さですので、16分音符の長さは0.5 / 4 = 0.125秒となります。

ということで、16分音符のタイミングでしか音符を置けないようにしたいのであれば、

Mathf.Round(キーを押した秒 / 0.125) * 0.125

の計算を行えばOKです。

結局は0.125秒の単位で正確に演奏しないといけないので、ホントは打ち込み機能が欲しいところですね。(今回はご容赦くださいませm(_ _)m)

メインの処理を実装する

準備も終わり、いよいよゲーム部分の実装に入ります。
まずは要件を洗い出し、それらをどう実装していくか考えていきましょう。

■曲に合わせてノートが流れてくる

ノートが一定速度で流れてくるようにするためには、RidigBody.velocityやTweenアニメーションを使うとカンタンです。

ただ、RidigBody.velocityやTweenアニメーションはゲーム内時間と連動して動いています。
普通ならコレでOKなのですが、音ゲーとなるとノートと音楽は必ずマッチさせる必要があります。
ただ、残念ながらゲーム内時間と楽曲の再生位置は100%一致するという保証がありません。(むしろ、デバイスのCPU負荷などでカンタンにズレちゃいます)

誤差を最小限にするのであればUpdate()メソッド内で曲の再生位置を元に座標を計算することをオススメします。

ちなみに、このへんの考え方がシビアなのは筆者が音楽系のアプリ開発に絡んでいるせいです(笑)。

計算式は、

Y座標 = Y座標原点 + (ノート配置タイミング - 曲の再生位置) * 1秒あたりの移動距離

といった感じでOKです。

もう1点注意すべき点として、ノートのGameObject生成時にInstantiate()を使うと処理が重くなってしまいがちです。(Instantiateはとってもパフォーマンスを喰います)

シーンのロード時などで先にノートオブジェクトをたくさん生成しておき、SetActive()で表示したり隠したりして使いまわした方が良いでしょう。

■ノートに合わせてキーを叩けばスコアが増える

■キーを叩くタイミングが良いほどスコアが上がる

これらはひとまとめにして考えられそうですね。

処理の流れとしては、まずキーを押した際、そのキーに対応した、距離が一番近いノートを取得。

ノートの配置タイミング - 曲の再生位置 = ズレ

の計算を行い、キータッチとノートのタイミングのズレを判定。
ズレに応じてスコアを付与する、といった感じで良さそうです。

■何度か失敗したらゲームオーバー

これはとてもカンタン。

  • ・キーを押したとき、ズレが一定以上だった場合
  • ・ノートが最後まで流れていって消えてしまった場合

にダメージを受ける処理を入れればOKそうです

実装してみた

今回の流れを一通り盛り込み、サンプルを作成してみました。
https://github.com/akako/gamealgorithm-music-game/releases/tag/for_algorithm15

それっぽいというか、ちゃんと音ゲーですね。ここまで来ると、もう少し作り込みたくなっちゃいます(笑)。

まとめ

全3回に渡ってお送りした音ゲーの開発、いかがでしたでしょうか。
音ゲーはシステムがシンプルで実装しやすい反面、コンテンツが勝負のキモになりがちです。良い楽曲に加え、プレイを盛り上げるためのハデな演出など、ジャンル的には「芸術」方面に属する部分を欠かす事ができません。その点では、開発のハードルは高めとも言えるでしょう。

ただ、幸いなことに最近は商用フリーの楽曲を配布してくださっている方もたくさんいらっしゃいます。
色々な楽曲を拝借し、自分なりの表現でゲームとして組み立ててみるのもとても面白そうです。

さて、次回からはスマホ時代に登場した新ジャンル、「ひっぱりアクション」のアルゴリズムを考えてみようと思います。

原稿: 賀好 昭仁
qnoteスマホアプリ開発チーム技術主任。PHP・Android・iOS・Unityなど複数のプラットフォームでの開発を行う。
しばしば7匹の先輩猫社員たちにイスを占領される。

Unityで作ろう!ゲームアルゴリズム(15)音ゲーのアルゴリズムを作ってみる その3(ゲーム実装編)

この記事はどうでしたか?

おすすめの記事

キャリアを考える

BACK TO TOP ∧

FOLLOW