このページでも、前回に引き続き、ゲームの監督スクリプトを記述していきます。前回も書きましたが、ワガハイ式テトリスにおける監督スクリプトの主なお仕事を書き出すと以下のようになります。
・ブロック落下が完了次第、10ブロック分スキマ無くしき詰めた列のブロックを消滅させる
・ブロックを消した際、右上の「○○列消した」の所の数字を更新
・10列ブロックを消すごとに、左上にあるレベルを1つ上げ、ミノの落下速度を上げる
・ブロック消滅後、残ったブロックに落下の指示
・ミノ出現位置にブロックが残っていたらゲームオーバー画面に移行
そして、前回は一番上のブロック落下が完了次第、10ブロック分スキマ無くしき詰めた列のブロックを消滅させるのスクリプト文が完成しましたね。本ページでは、それ以外の残り4つのお仕事をスクリプトに一気に書き上げていきます!!
以前のぷよぷよでも似たようなことをしました(ぷよぷよ制作手順5-5参照)が、今回は消えた列数を右上に表示させます。やっぱりこういうゲームの進行度を現す物が無いと、面白くないですよね。しかも今回のテトリスでは、後程スクリプト化しますが、10列ごとに落下速度が上がりますので、消した列数って凄く重要な数字になります!
文字テキスト(text UI)を更新するスクリプトはこの本にも載っています(4-6章参照)し、問題無いと思います。後は数字の算出方法ですが、ブロックが消えた時に消えた列数=前回定義した動的配列deleteyset(ブロックが消える列のy座標リスト)の要素数(Count)だけ増やしていけば良いですよね!ということで、こんな具合でしょうか。
GameObject deleterowtext; //右上テキスト int deleteall = 0; //これまでに消した全列数 //以下、Startメソッド内に記述 this.deleterowtext = GameObject.Find("rownum"); //以下、ミノの落下完了時に呼び出されるメソッド内に記述 //textに総削除列数表示…削除列数決定後に以下を挿入 this.deleteall += this.deleteyset.Count; this.deleterowtext.GetComponent<Text>().text = this.deleteall.ToString("D3") + "列消した";
最初がレベル1から始まった場合、10列消すとレベル2、20列消すとレベル3、…という具合にレベルが上がっていく仕組みをスクリプト化していきます。
GameObject leveltext; //左上テキスト int nextgoal = 10; //次にレベルアップする列数 //以下、Startメソッド内に記述 this.leveltext = GameObject.Find("LEVEL"); //以下、ミノの落下完了時に呼び出されるメソッド内に記述 //10の倍数列消したらレベル1追加 if (this.deleteall - this.deleteyset.Count < this.nextgoal && this.deleteall >= this.nextgoal) { levelchoice = chooselevel.addlevelchoice(); this.leveltext.GetComponent<Text>().text = "LEVEL " + levelchoice.ToString("D2"); this.nextgoal += 10; //次のレベルアップ列数を設定(10→20→30→…) }
制作手順2-1でもお話しましたように、基本的にゲーム中のレベル情報は別途「chooselevel.cs」というスクリプト中の変数「levelchoice」で管理しており、そのスクリプト中のaddlevelchoice メソッドを用いると、ゲームのレベルが1つアップします。
今回は、各ブロックごとの変数fally[i]を用意します。この変数はi番ブロックが落下後どれだけ落下するかを表す変数となっており、この変数の値を決めるスクリプトは以下のように書きます。
float[] fally = new float[1000]; //以下、ミノの落下完了時に呼び出されるメソッド内に記述 //現状のフィールド中の全blockオブジェクトの位置調査…前回書いたこの部分に1行追加 i = 0; this.blocks = GameObject.FindGameObjectsWithTag("block"); foreach (GameObject block in this.blocks) { this.blockx[i] = Mathf.RoundToInt(block.transform.position.x * 10.0f) / 10.0f; this.blocky[i] = Mathf.RoundToInt(block.transform.position.y * 10.0f) / 10.0f; this.fally[i] = 0.0f; //【この行を追加】 i++; } //block削除後の落ちる高さを算出【以下は全て削除列数決定後に追加】 j = 0; foreach (GameObject block in this.blocks){ for (i = 0; i < this.deleteyset.Count; i++){ //j番ブロックのy座標が削除列y座標リストの要素より大きければ落下+1.0f追加 if (this.blocky[j] >= this.deleteyset[i]) this.fally[j] += 1.0f; } j++; }
そして、後は落下の指示ですね。更に、ブロック削除後のタイミングで以下のようなスクリプトを追加します。
//削除後のblock一斉落下処理 for (j = 0; j < this.blocks.Length; j++){ if (this.deleteyset.Contains(this.blocky[j]) == false){ //削除されてないblockに対してのみ落下の指示 this.blocks[j].transform.Translate(0, -this.fally[j] , 0, Space.World); } }
こちらのページでも解説しておりますが、動的配列.Contains(○○)は、値○○が含まれているか(→true)否か(→false)を返してくれる検索機能になります。要するにdeleteyset のリストに含まれるy座標のブロックは既に削除されておりますので、本if文を入れておかないと、既に消滅済のブロックまでムリヤリ呼び出すことになり、NullReferenceException のエラーが発生してしまいます!!
最後はこちらの機能ですが、これはぷよぷよでも実装した機能(ぷよぷよ制作手順5-5中間部参考)ですので、こちらでは結果のスクリプト文だけ書いておきます。ちなみに、今回のテトリスでのゲームオーバー位置=(-0.5f,11.5f)になります。
//以下、ミノの落下完了時に呼び出されるメソッド内に記述 //削除列数決定後に以下を挿入 i = 0; if (this.deleteyset.Count == 0) { //削除数0かつblock出現位置に残っている場合はgameoverへ foreach (GameObject block in this.blocks){ if(this.blockx[i] == -0.5f && this.blocky[i] == 11.5f ) { SceneManager.LoadScene("gameover"); } i++; }
今回で、監督スクリプトの主なお仕事5つについては無事スクリプトに書き下すことが出来ました。実際のワガハイ式テトリスではもっと他にも沢山の細かなお仕事をこなしていますが、監督スクリプトの重要な部分はこれで以上になります。さらに詳しい話を知りたい方は私ワガハイの方までお問い合わせ下さい。ありがとうございました!!