今回はUnity C# 音ゲーの作り方講座の第9回目、「Sliderをスコアに合わせて動かそうをチュートリアル形式で説明していきます。
第7,8回目に『musicbox』が『collisionbox』に衝突した時に加点・減点・コンボの仕組みを作りました。
前回の記事:Unity C# 音ゲーの作り方8 コンボをカウントするスクリプトを作成しよう
第9回目は、スコアの加点や減点に合わせてSliderを動かしていきます。これにより上手に音ノーツを叩いて獲得した得点スコアが増えていくことが視覚的にわかるようになります。
また、第3回目に作成したゲーム結果を音ゲーのBGMが終わる時に表示させる仕組みも作っていきます。
今回で音ゲーの基本処理の開発はすべて完成します。最後に補講でコードの汎用性を高めるリファクタリングにも触れていきます。
音ゲーのスコアに合わせてSliderを動かすスクリプトを作成しよう
音ゲーのスコアが加点された時にSliderが右にスライドして減点された時に左にスライドするようにしていきます。
そのためSliderが右にスライドするスクリプトと左にスライドするスクリプトの2つを作成していきます。
それでは、Sliderが右にスライドするスクリプトから作成していきます。
『Script』フォルダーの中でスクリプトを作成して名前を『ScoregaugeManager』に変更して開いてください。
以下に完成したスクリプトを掲載するのでコピーして入力してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ScoregaugeManager : MonoBehaviour { //スライダーを格納する public Slider scoregauge; // Start is called before the first frame update void Start() { //コンポーネントからscoregaugeを検出する scoregauge = GameObject.Find("scoregauge").GetComponent<Slider>(); //0からスタートする scoregauge.value = 0; } //衝突した時 private void OnCollisionEnter(Collision collision) { //"Player"タグのオブジェクトに衝突した場合 if (collision.gameObject.tag == "Player") { //0.008増加する scoregauge.value += 0.008f; } } } |
『ScoregaugeManager』スクリプトの解説をしていきます。
SliderはUIなので以下のコードは必須になります。他のUIを操作する場合も必要になります。
1 |
using UnityEngine.UI; |
動かすSliderを指定するためにSliderを格納するコードを入力します。
1 2 |
//スライダーを格納する public Slider scoregauge; |
スクリプトからSliderを紐付けるために『scoregauge』を検出するコードを入力します。Sliderの値は0からスタートするように設定します。
1 2 3 4 5 6 7 8 |
// Start is called before the first frame update void Start() { //コンポーネントからscoregaugeを検出する scoregauge = GameObject.Find("scoregauge").GetComponent<Slider>(); //0からスタートする scoregauge.value = 0; } |
『musicbox』が『Player』タグの付いた『collision』オブジェクトに衝突した際にSliderの値が0.008ずつ右に進むように設定しています。スコア系のオブジェクトやスクリプトと直接紐づけている訳ではなく、計算上スコアの満点になる時にSliderが満たされるように速度を設定しています。
1 2 3 4 5 6 7 8 9 10 |
//衝突した時 private void OnCollisionEnter(Collision collision) { //"Player"タグのオブジェクトに衝突した場合 if(collision.gameObject.tag == "Player") { //0.008増加する scoregauge.value += 0.008f; } } |
『ScoregaugeManager』スクリプトの入力ができたらヒエラルキーの中にある『musicbox.pink』の『>』を選択してインスペクターにスクリプトをドロップしてください。
ドロップしたらヒエラルキーにある『<』を選択して戻ります。
『musicbox.pink』のインスペクターにある『ScoregaugeManager』スクリプトの◉を選択して『scoregauge』を選択してください。
同じやり方で『musicbox.green』『musicbox.blue』『musicbox.orange』のインスペクターにスクリプトをドロップさせて『scoregauge』を選択してください。
これでSliderが右にスライドするスクリプトの作成・設定ができました。
次にSliderが左にスライドするスクリプトを作成していきます。
『Script』フォルダーの中でスクリプトを作成して名前を『MinusScoregaugeManager』に変更して開いてください。
以下に完成したスクリプトを掲載するのでコピーして入力してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class MinusScoregaugeManager : MonoBehaviour { //スライダーを格納する public Slider scoregauge; // Start is called before the first frame update void Start() { //コンポーネントからscoregaugeを検出する scoregauge = GameObject.Find("scoregauge").GetComponent<Slider>(); //0からスタートする scoregauge.value = 0; } //衝突した時 private void OnCollisionEnter(Collision collision) { //"Player"タグのオブジェクトに衝突した場合 if (collision.gameObject.tag == "Player") { //0.002減少する scoregauge.value -= 0.002f; } } } |
『MinusScoregaugeManager』スクリプトの解説をしていきます。
基本的には『ScoregaugeManager』と同じです。違う点は、『musicbox』が『Player』タグの付いた『collision』オブジェクトに衝突した際にSliderの値が0.002ずつ左に進むように設定しているところです。
1 2 3 4 5 6 7 8 9 10 |
//衝突した時 private void OnCollisionEnter(Collision collision) { //"Player"タグのオブジェクトに衝突した場合 if (collision.gameObject.tag == "Player") { //0.002減少する scoregauge.value -= 0.002f; } } |
『MinusScoregaugeManager』スクリプトの入力ができたらヒエラルキーの中にある『musicbox.bakudan』の『>』を選択してインスペクターにスクリプトをドロップしてください。
ドロップしたらヒエラルキーにある『<』を選択して戻ります。
『musicbox.bakudan』のインスペクターにある『MinusScoregaugeManager』スクリプトの◉を選択して『scoregauge』を選択してください。
これでSliderが左にスライドするスクリプトの作成・設定ができました。
音ゲーのゲーム結果を遅らせて表示させるスクリプトを作成しよう
音ゲーのBGMが終わる頃にランク制のゲーム結果を表示させていきます。
ゲーム結果の中でも文字と画像の表示タイミングを変えたいので2種類のスクリプトを作成していきます。
『Script』フォルダーの中でスクリプトを作成して名前を『Next1』に変更して開いてください。
以下に完成したスクリプトを掲載するのでコピーして入力してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Next1 : MonoBehaviour { // Start is called before the first frame update void Start() { //オブジェクトを非アクティブにする this.gameObject.SetActive(false); //95秒後にOpen関数を実行する Invoke("Open", 95); } // void Open() { //オブジェクトをアクティブにする this.gameObject.SetActive(true); } } |
『Next1』スクリプトの解説をしていきます。
音ゲーのスタート時はスクリプトをアタッチしたオブジェクトを非表示するよう設定しています。Invoke関数は指定した秒数に合わせて指定する関数を実行することができます。95秒後にUpdate関数を実行するということです。
1 2 3 4 5 6 7 8 |
// Start is called before the first frame update void Start() { //オブジェクトを非アクティブにする this.gameObject.SetActive(false); //95秒後にOpen関数を実行する Invoke("Update", 95); } |
この95秒は曲が終わるタイミングを意味していますが、ちゃんと変数で与えておくほうが本当は良いです。
このようにそのまま変数化せずに突然出てくる数値をマジックナンバーといい、後でスクリプトを見た時に何の数字だったかわからなくなりがちです。保守性を下げるので本当は良くない書き方です。
マジックナンバーを使うことがなぜ良くないかをこの記事の後半で実際に解説しますね。
さて、Open関数は以下になります。内容としてはオブジェクトを表示してくれます。95秒後にオブジェクトを表示させるということです。
1 2 3 4 5 |
void Open() { //オブジェクトをアクティブにする this.gameObject.SetActive(true); } |
『Next1』スクリプトの入力ができたらヒエラルキーの中にあるゲーム結果で使用している『Panel1』を選択してインスペクターにスクリプトをドロップしてください。
また、同時にインスペクターの名前の横にある表示のチェックを入れてください。
同じやり方で以下のオブジェクトにもスクリプトをインスペクターにドロップさせてください。
以下のようになっていれば1つ目のゲーム結果を遅らせて表示するスクリプトの作成・設定が完了です。
次にゲーム結果の画像を遅らせて表示させるスクリプトを作成していきます。
『Script』フォルダーの中でスクリプトを作成して名前を『Next2』に変更して開いてください。
以下に完成したスクリプトを掲載するのでコピーして入力してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Next2 : MonoBehaviour { // Start is called before the first frame update void Start() { //オブジェクトを非アクティブにする this.gameObject.SetActive(false); //96秒後にOpen関数を実行する Invoke("Open", 96); } void Open() { //オブジェクトをアクティブにする this.gameObject.SetActive(true); } } |
『Next2』スクリプトは『Next1』スクリプトとほぼ同じ内容です。実行する秒数のみ変更しています。
『Next2』スクリプトの入力ができたらヒエラルキーの中にある『Image.Bad』を選択してインスペクターにスクリプトをドロップしてください。
また、同時にインスペクターの名前の横にある表示のチェックを入れてください。
同じやり方で以下のオブジェクトにもスクリプトをインスペクターにドロップさせてください。
以下のようになっていれば2つ目のゲーム結果の画像を遅らせて表示するスクリプトの作成・設定が完了です。
音ゲーの作り方第9回のまとめと次回
第9回目の開発お疲れさまでした。
今回はゲーム結果を遅らせて表示させるスクリプトを作成しました。
Invoke関数は様々な関数の実行を遅らせることができるのでゲーム作りをする時は覚えておくと便利です。
次回は、第10回の「Unity C# 音ゲーの作り方10 タイトル画面を作成してゲームシーンをチェンジさせよう」です。
ですが、今回はその前に補講です!
ただゲーム機能を実装しただけではまだまだUnityを上手に操れてるとは言えません。
実はここまでに作ってきたスクリプトの作り方にはとても無駄が多かったのです。
もしかしたら読者さんの中には「なんでこんな書き方をしているんだろう?」と気づいた方もいたかもしれません。
補講:実はスクリプトをもっと使いまわせた/リファクタリングと汎用化のススメ
ここまでの講座では同じような処理を別のスクリプトとして保存してアタッチしていました。
少々泥臭い作り方にはなりますが、プログラミングの文法をたくさん覚えることなく作ることができました。
より進んだ実際の開発では変数、条件分岐、メソッド化、クラス化などを使って一度作ったスクリプトで同じような処理は共通化してゲームを作っていきます。
その考え方の一部をここで解説します。
マジックナンバーをなくして変数を使えばスクリプトを使いまわせるようになります
今回までの記事で時々同じような処理を二回作っていたことに気付いておられますか?
例えば、スライダーの変更ではプラス方向にスライダーを動かす処理とマイナス方向にスライダーを動かす処理。
最後の結果を表示するNext1.csやNext2.csでは表示する秒数の違いがあるだけでやっていることは同じでした。
実はあの二つのスクリプトは一つにまとめることができます。以下のように『Next』というスクリプトを作ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Next : MonoBehaviour { [SerializeField] int openTime = 95; // Start is called before the first frame update void Start() { //オブジェクトを非アクティブにする this.gameObject.SetActive(false); //95秒後にOpen関数を実行する Invoke("Open", openTime); } // void Open() { //オブジェクトをアクティブにする this.gameObject.SetActive(true); } } |
このスクリプトは先ほど作ったNext1,Next2に出てきたマジックナンバー95,96を7行目と15行目でopenTimeという変数に変更しています。
先ほどNext1, Next2をアタッチした全てのオブジェクトにこのスクリプトをアタッチしてみましょう。そしてNext1,Next2のスクリプトをそれぞれのコンポーネントから削除しておきましょう。
そしてNext2.csをアタッチしていたゲームオブジェクトのインスペクターで96を入力しておきます。
こうすると一つのスクリプトで95秒後に実行する処理と96秒後に実行する処理を同時に実現できました。
このように変数で定義してマジックナンバーをなくすとソースコードを使いまわせるようになりますし、今後別の曲を演奏するときにもコードを書き換えることなくインスペクターの値を変えるだけで実現できますね。
もしくはこのゲームを改造していったとき、曲の途中で何かエフェクトのようなものを表示させたくなったときにも秒数を変えたら同じスクリプトが使えそうですよね?
どうでしょうか?
ちょっとの違いですがスクリプトの数が減って使いまわせる部分が増えたことで見通しが良いプログラミングができるようになりました。
このように一度完成した機能をより使いやすい形に書き換えていくことをリファクタリングといいます。
実は他にもNext.csと同じようなことができる箇所がありますよ。
そうですね。例えば「ScoregaugeManager.cs」と「MinusScoregaugeManager.cs」は本当に2つ必要でしょうか?
ここから先はあなたが実際に試してみてくださいね。
ゲームの機能開発とリファクタリングはバランスよく行おう
実際のゲーム開発は今回のミニゲームの音ゲーを作るときよりも長丁場です。
まとまった処理が出来上がったときなどにリファクタリングをやっておくとその後の開発効率が大幅にアップします。
逆にいきなり完璧を目指しすぎるとなかなか作りたい機能が完成しない罠にはまることもあります。
機能の実現とスクリプトの改善をバランスよく行えるようになると一歩先行くゲームプログラマーになれますね。
では、今度こそ9章は終わりです。お疲れ様でした!
次回記事はいよいよ音ゲーの作り方講座の最後、「Unity C# 音ゲーの作り方10 タイトル画面を作成してゲームシーンをチェンジさせよう」になります。
コメント