はじめに
JunShimuraさんの「[超初心者向け]Unityチュートリアル「はじめてのUnity」のブロック崩しと同等をC#で ::(1)ステージ配置~(6)ブロックを手作業で並べる)」をよりゲームらしく改造する。
作成する記事は下記の通りです。
- スコアの表示
- ゲームマネージャークラスを作る
- ブロックをスクリプトで配置(この記事)
- 音を鳴らす
前回の状態
前回の記事「ゲームマネージャークラスを作る」では、ゲームクリアー後にブロックが全て消えた状態でゲームスタートとなってしまいました。これはブロックの初期化(並べる)処理が入っていないためです。
何故かというとブロックが全て消えてしまうため、ブロックを複製することが出来なく無くなってしまうからです。
ブロックを複製するためには、ブロックのプレハブ(Prefab)化を行います。
プレハブ化とは
プレハブ(Prefab)とはオブジェクトの作り置きが出来る仕組みのことです。テンプレートとして使用できます。
BlockをPrefab化する
現在、HierarchyにBlock
を複数ある方は、1つのみ残して削除してください。
不要なBlock
を複数選択するにはShift
キーを押しながらBlock
を選択します。その後に右クリックメニューからDelete
を選択します。
Hierarchyから、Block
をAssetsにドラッグすると、Block
プレハブが出来上がります。
Block
プレハブができたら、HierarchyのBlock
を選択して右クリックメニューからDelete
で削除してください。
Prefabのメリットなどは下記記事を参照してください。
PrefabとInstantiateの基本(1)ブロックをScriptで配置:「はじめてのUnity」のブロック崩しを改造しながら学ぶ
Blockの色を変える準備
白一色だったブロックですが、複数の色のブロックにして色ごとに得点を分けるようにしたいと思っています。
「[超初心者向け]Unityチュートリアル「はじめてのUnity」のブロック崩しと同等をC#で::(2)色を変える」で壁の色を変える際に、Wall Material
を作成しました。
今回はブロックの色を変えるBlock Material
を作成します。
下に在るAssetsの左にある[Create]>[Material]をクリックして下さい。
名前をBlock Material
に変えます。
名前を間違えた場合、名前のところをクリックすれば編集できるようになります。
AssetsにあるBlock
を選択して、Inspector
を表示します。ちなみにプレハブ化された場合、水色の箱アイコンになります。
次にMaterials
のElement 0
のところにある○をクリックし、開いたリスト画面からBlock Material
を選択します。
色はスクリプトによって複数の色に変更するので、ここでは何もしません。
スクリプトの作成
先に空のゲームオブジェクトを作成します。
Hierarchyに下にある[Create]>[Create Empty]を選択して下さい。
名前をBlockMap
とします。Position
はXYZを0
にしておきます。
BlockMap
の[Inspector]タブの一番下にある[Add Compornent]ボタンをクリックして、Scriptアセットを作成、追加します。ファイル形式はcsを選びます。
ファイル名をBlockMap
とします。そうすると、Assetsの中に「BlockMap.cs」が出来ています。
※BとMは英大文字です。間違えた場合、ファイル名と中身のクラス名の両方を修正してください。
BlockMap.csを編集する
Assets内のBlockMap
スクリプト(C#のアイコン)をダブルクリックすると、エディタが開きます。
優先的に開かれるエディタは、多くの場合はMonoDevelopというソフトが起動されます。
少し長いのでコピー&ペーストで入力してしまいましょう。
※MonoDevelopでペーストが効かないに時はMonoDevelopを閉じ直してください。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BlockMap : MonoBehaviour {
public GameObject blockPrefab;
public Material material;
Color[] itemColor = { Color.clear, Color.red, Color.blue, Color.green, Color.yellow, Color.magenta };
// 0:None 1:Red 2:Blue 3:Green 4:Yellow 5:Magenta
int[,,] stageMap = {
{
{ 3, 3, 3, 3, 3},
{ 2, 0, 2, 0, 2},
{ 1, 1, 0, 1, 1},
{ 0, 0, 0, 0, 0}
},
{
{ 4, 4, 0, 4, 4},
{ 3, 0, 3, 0, 3},
{ 2, 2, 2, 2, 2},
{ 0, 1, 1, 1, 0},
},
{
{ 4, 5, 4, 5, 4},
{ 5, 3, 3, 3, 5},
{ 2, 5, 2, 5, 2},
{ 1, 1, 5, 1, 1},
}
};
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
// ステージ最大数
public int GetStageMax(){
return stageMap.GetLength(0);
}
// ステージ作成
public void CreateStage(int stage){
var parent = this.transform;
// 配置する座標を設定
Vector3 placePosition = new Vector3(-4,0,9);
// 初期化する座標を設定
Vector3 initPosition = placePosition;
// 配置する回転角を設定
Quaternion q = new Quaternion();
q = Quaternion.identity;
// ブロック全削除
var clones = GameObject.FindGameObjectsWithTag ("Block");
foreach (var clone in clones){
Destroy(clone);
}
// 配置
for (int i = 0; i < stageMap.GetLength(1); i++) {
placePosition.x = initPosition.x;
for (int j = 0; j < stageMap.GetLength(2); j++) {
int item = stageMap[stage-1, i, j];
if(item != 0){
// ブロックの複製
GameObject block = Instantiate(blockPrefab, placePosition, q, parent);
// ステージのブロック番号により色変更
Renderer r = block.GetComponent<Renderer>();
r.material.color = itemColor[item];
// ステージのブロック番号で名前を生成
block.name = "Block_" + item.ToString();
}
placePosition.x += blockPrefab.transform.localScale.x;
}
placePosition.z -= blockPrefab.transform.localScale.z * 2;
}
}
}
少し説明します。
- 3次元配列を用意し、ステージごとに2次元配列(5x4)をブロック番号をセットしています。
- ステージマップのブロック番号が1以上ならブロックのプレハブを複製し、各番号の色を変更しています。
- 名前にブロック番号を付与して、スコア処理で番号の判定をします。
Block PrefabとMaterialを設定する
スクリプト内でpublicにした型はInspectorに表示されます。
ここにBlockとBlock Materialをセットします。
Block Prefabの右横にある○をクリックし、開いたリスト画面からBlock
を選択します。
Materialの右横にある○をクリックし、開いたリスト画面からBlock Material
を選択します。
Manager.csを編集する
GameOpening
処理には、ステージ作成の処理を追加しています。
GameClear
処理には、3ステージまではステージクリアとして処理を追加しています。
// オープニング処理
void GameOpening ()
{
currentState = GameState.Opening;
// タイトル名のセット
SetTitle ("Game Start", Color.green);
// ボールの動作停止
Time.timeScale = 0;
// ラケットの初期位置をセット
racket.transform.position = new Vector3 (0.0f, 0.0f, -8.5f);
// ボールの初期位置をセット
ball.transform.position = new Vector3 (0.0f, 0.0f, -7.5f);
// ステージ作成
FindObjectOfType<BlockMap>().CreateStage(stage);
}
// ゲームクリアー処理
void GameClear ()
{
// ステージ最大数の取得
int stageMax = FindObjectOfType<BlockMap> ().GetStageMax();
// 次のステージへ
stage++;
if (stage > stageMax) {
// タイトル名のセット
SetTitle ("Game Clear", Color.yellow);
// ステージ初期値
stage = 1;
}
else {
// タイトル名のセット
SetTitle (string.Format("Stage {0} Clear", stage -1) , Color.yellow);
}
//3秒後にオープニング処理を呼び出す
Invoke ("GameOpening", 3f);
}
Block.csを編集する
これまで一律10
点だった得点をブロックの色ごとに得点を分けるようにします。
ブロックの名前の末尾を取得して、10
倍したのを得点とします。
void OnCollisionEnter(Collision collision) {
//衝突判定
if (collision.gameObject.tag == "Ball") {
if (FindObjectOfType<Manager> ().currentState == Manager.GameState.Playing) {
//スコア処理を追加
string name = this.name;
int score = int.Parse (name.Substring (name.Length - 1));
FindObjectOfType<Score> ().AddPoint (score * 10);
}
//相手のタグがBallならば、自分を消す
Destroy(this.gameObject);
}
}
改善
テスト用に一時的に、Ball.cs
のゲームオーバー判定をコメントアウト。
ボールが壁を突き抜ける
たまにボールが壁を突き抜けてしまうことが判明、下記の記事を参考にボールにも適用してみます。
衝突判定の再考、壁抜けを止める:「はじめてのUnity」のブロック崩しを改造しながら学ぶ
Ball
を選択し、[Inspector]タブでRigidbody
のCollision Detection
をContinuos
に変更します。
ラケットの形状を変更
ボールが垂直方向のままで方向変更ができないことがあるます。
これはラケットがCube
になっているので、末端を丸みがあるようにCapsule
に変更します。
Mesh
のところにある○をクリックし、開いたリスト画面からCapsule
を選択します。
このままだとBox Collider
のままなので、Capsule Collider
に変更します。
一旦、Box Collider
コンポーネントを削除します。
Box Collider
コンポーネントの右横にある歯車をRemove Compornent
を選択します。
次に[Inspector]タブの一番下にある[Add Compornent]ボタンをクリックして、[Physics]の[Capsule Collider]を追加します。
Height
を1
、Direction
をX-Axis
にします。
ラケットのサイズを変更
ついでにラケットのサイズを大きくします。Scale
のX
を5
にします。
実装を確認する
エディタ画面中央の実行ボタンを押してみましょう。
オープニング画面でスペースキーで押すとゲームスタートとなります。
ブロックが全て無くなるとステージクリアーになり、次のステージとなります。
現在は、3ステージまでしか用意していません。
学んだこと
- プレハブ化することでテンプレートとして使用できること
- スクリプトによりブロックを自由に配置できること
- スクリプトによりブロックの色を変更できること