コガネブログ

平日更新を目標に Unity や C#、Visual Studio などのゲーム開発アレコレを書いていきます

【Unity 入門】【チュートリアル】ボンバーマン風のゲームを作る

はじめに

このチュートリアルは、上記のサイト様が公開されている
ボンバーマン風のゲームを作るチュートリアルを翻訳したものになります

このチュートリアルでは、あらかじめ用意された
モデルやアニメーション、エフェクトのデータを活用して
ボンバーマン風のゲームを作成していきます

目次

開発環境

  • Unity 2017.4.0f1
  • Windows 10

完成図

f:id:baba_s:20180329150031g:plain

Unity プロジェクトの準備

https://koenig-media.raywenderlich.com/uploads/2017/09/Bomberman-HowTo-Starter-Project-1.zip

まず、上記のページにアクセスして、
「Bomberman-HowTo-Starter-Project-1.zip」をダウンロードして展開します

f:id:baba_s:20180329150555p:plain

次に、Unity を起動して「Open」を選択し、
展開した「Bomberman HowTo - Starter Project」フォルダを選択します
(「Assets」フォルダと「ProjectSettings」フォルダが格納されているフォルダです)

f:id:baba_s:20180329150822p:plain

もし、上記のようなダイアログが表示されたら「Continue」を押します

f:id:baba_s:20180329151038p:plain

しばらくすると、Unity プロジェクトが立ち上がります

エディタのレイアウトの変更

次は、作業をしやすくするために Unity エディタのレイアウトを変更します

f:id:baba_s:20180328203648p:plain

エディタ右上のボタンを押して、

f:id:baba_s:20180328203654p:plain

「2 by 3」を選択します

f:id:baba_s:20180328203700p:plain

そして、「Project」と書かれているタブの右側にある三本線のアイコンを押して、

f:id:baba_s:20180328203705p:plain

「One Column Layout」を選択します
これでレイアウトの変更が完了しました

Unity プロジェクトの解説

f:id:baba_s:20180329151446p:plain

今回は、上記のようにモデルやアニメーション、
エフェクトなどのデータがすでに用意されており、これらを活用していきます

それぞれのフォルダには、下記のようなアセットが用意されています

フォルダ 内容
Animation Controllers プレイヤーモデルのアニメーション
Materials ステージに配置されているブロックのマテリアル
Models プレイヤー、ステージ、爆弾のモデルとマテリアル
Music BGM
Physics Materials プレイヤーの物理特性
Prefabs 爆弾と爆発エフェクトのプレハブ
Scenes ゲームのシーン
Scripts ゲームの挙動を実装するスクリプト
Sound Effects 爆弾と爆発エフェクトの SE
Textures プレイヤーのテクスチャ

ゲームの操作方法

f:id:baba_s:20180329152013p:plain

「Scenes」フォルダ内の「Game」シーンをダブルクリックして開くと、

f:id:baba_s:20180329152057p:plain

プレイヤーとステージが配置されたシーンが立ち上がります

f:id:baba_s:20180329152147p:plain

そして、Unity エディタ上部の再生ボタンを押してゲームを再生すると
すでにプレイヤーが操作できるようになっていることが確認できます

  1P 2P
移動 WASD 矢印キー
爆弾の配置 Space Enter

しかし、まだ爆弾の配置はできません
まずは、爆弾を配置するコードを実装していきましょう

コードの実装

爆弾の配置

f:id:baba_s:20180329152703p:plain

「Scripts」フォルダ内の「Player.cs」をダブルクリックすると、

f:id:baba_s:20180329153020p:plain

お使いの環境に合わせて Visual Studio や MonoDevelop などの、
プログラムを書くためのコードエディタが起動します

/// <summary>
/// Drops a bomb beneath the player
/// </summary>
private void DropBomb ()
{
    if (bombPrefab)
    { //Check if bomb prefab is assigned first

    }
}

176行目あたりに、DropBomb 関数が定義されており、
Space キーや Enter キーを押すと、この関数が呼び出されるようになっています

プレイヤーの足元に爆弾を配置するには、if 文の中に次の行を追加します

// 爆弾のゲームオブジェクトを作成
Instantiate
( 
    bombPrefab, 
    myTransform.position, 
    bombPrefab.transform.rotation 
);

f:id:baba_s:20180329153424g:plain

そして、スクリプトを保存して Unity に戻り、
Unity を再生して Space キーや Enter キーを押すと、
プレイヤーの足元に爆弾を配置できるようになったことが確認できます

確認ができたら Unity を停止します
今後も、ゲームの動作確認が終わったら
Unity を停止することをわすれないようにしましょう

Unity を停止せずに編集を続けてしまうと、
作業内容が消えてしまう可能性があります

爆弾の配置位置のスナップ

爆弾を配置できるようになりましたが、
配置位置が床のグリッドとズレてしまっているので、修正していきます

Player.cs で先ほど追加したコードを下記のように変更します

// X 座標と Y 座標を四捨五入
var pos = new Vector3
(
    Mathf.RoundToInt( myTransform.position.x ),
    bombPrefab.transform.position.y,
    Mathf.RoundToInt( myTransform.position.z )
);

// 爆弾のゲームオブジェクトを作成
Instantiate
(
    bombPrefab,
    pos,
    bombPrefab.transform.rotation
);

Mathf.RoundToInt を使用すると、指定された値を四捨五入できます
今回のステージは、床のグリッドの間隔が 1 ずつになっているため、
Mathf.RoundToInt を使用することで、爆弾をキレイに配置できるようになります

f:id:baba_s:20180329154132g:plain

そして、スクリプトを保存して Unity に戻り、
Unity を再生して Space キーや Enter キーを押すと、
爆弾がキレイに配置できることが確認できます

爆弾の爆発

次は、爆弾の爆発を実装していきます
そのためには、新しいスクリプトが必要になります

f:id:baba_s:20180329154619p:plain

「Scripts」フォルダを右クリックして「Create>C# Script」を選択します

f:id:baba_s:20180329154704p:plain

作成したスクリプトに「Bomb」と名前を付けます

f:id:baba_s:20180329154859p:plain

次に、「Prefabs」フォルダ内の「Bomb」を選択して、
「Add Component」ボタンを押して、

f:id:baba_s:20180329155001p:plain

入力欄に「Bomb」と入力して、表示された「Bomb」を選択します

f:id:baba_s:20180329155056p:plain

これで、先ほど作成した爆弾のスクリプトを、
爆弾のプレハブに適用することができました

今度は、コードエディタで「Bomb.cs」を開き、
Start 関数に次のコードを追加します

// 3 秒後に Explode 関数を実行
Invoke( "Explode", 3f );

これで、爆弾が作られてから 3 秒後に Explode 関数が呼び出されるようになりました
次は、下記の Explode 関数を Update 関数の下に追加します

// 爆弾が爆発する時の処理
private void Explode()
{
}

爆弾が爆発したら、爆発エフェクトを表示する必要があるので
Unity エディタから爆発エフェクトを設定できるようにするために、
下記の public 変数を Start 関数の上に追加します

public GameObject explosionPrefab; // 爆発エフェクトのプレハブ

ここで、一旦スクリプトを保存して Unity に戻ります

f:id:baba_s:20180329155815p:plain

そして、「Prefabs」フォルダ内の「Bomb」プレハブを選択し、
「Explosion」プレハブを「Explosion Prefab」の欄にドラッグします

これを済ませたら、コードエディタに戻り、Explode 関数に次のコードを追加します

// 爆弾の位置に爆発エフェクトを作成
Instantiate( explosionPrefab, transform.position, Quaternion.identity );

// 爆弾を非表示にする
GetComponent<MeshRenderer>().enabled = false;
transform.Find( "Collider" ).gameObject.SetActive( false );

// 0.3 秒後に非表示にした爆弾を削除
Destroy( gameObject, 0.3f );

f:id:baba_s:20180329160227g:plain

スクリプトを保存して Unity に戻り、
Unity を再生して Space キーや Enter キーを押すと、
爆弾が 3 秒後に爆発することが確認できます

レイヤーの追加

現在、爆弾の爆風は1マス分しか発生しないため、
3マス分広がるようにしていきます
そして、爆風が壁を突き抜けてしまうといけないため、
爆風と壁の当たり判定に使用するレイヤーを作成します

f:id:baba_s:20180329160743p:plain

Unity エディタ右上の「Layers」ボタンを押し、「Edit Layers...」を選択します

f:id:baba_s:20180329160855p:plain

そして、「Layers」の左の三角マークを押して
表示された「User Layer 8」の欄に「Blocks」と入力します

次は、作成した「Blocks」レイヤーを、ステージに配置されているブロックに適用します

f:id:baba_s:20180329161130p:plain

Hierarchy の欄の「Map」オブジェクト内の「Blocks」を選択し、
Inspector の「Layer」のプルダウンメニューを開き、「8. Blocks」を選択します

f:id:baba_s:20180329161248p:plain

確認ダイアログが表示されたら、「Yes, change children」を選択します
これで、ステージに配置されているすべてのブロックに
「Blocks」レイヤーを適用することができました

最後に、コードエディタで「Bomb.cs」を開いて、
explosionPrefab 変数の下に下記のコードを追加します

public LayerMask levelMask; // ステージのレイヤー

ここで、一旦スクリプトを保存します

爆風を3マスに広げる

「Bomb.cs」の Explode 関数の下に、次のコードを追加します

// 爆風を広げる
private IEnumerator CreateExplosions( Vector3 direction )
{
    // 2 マス分ループする
    for ( int i = 1; i < 3; i++ )
    {
        // ブロックとの当たり判定の結果を格納する変数
        RaycastHit hit;

        // 爆風を広げた先に何か存在するか確認
        Physics.Raycast
        (
            transform.position + new Vector3( 0, 0.5f, 0 ),
            direction,
            out hit,
            i,
            levelMask
        );

        // 爆風を広げた先に何も存在しない場合
        if ( !hit.collider )
        {
            // 爆風を広げるために、
            // 爆発エフェクトのオブジェクトを作成
            Instantiate
            (
                explosionPrefab,
                transform.position + ( i * direction ),
                explosionPrefab.transform.rotation
            );
        }
        // 爆風を広げた先にブロックが存在する場合
        else
        {
            // 爆風はこれ以上広げない
            break;
        }

        // 0.05 秒待ってから、次のマスに爆風を広げる
        yield return new WaitForSeconds( 0.05f );
    }
}

少しコードが長いため、一見複雑に見えますが、実際にはブロックと当たり判定を行い、
ブロックが存在しない場合は爆風を広げる、というシンプルな処理になります
詳しくはコード中のコメントを参照してください

これで、爆風を広げる CreateExplosions 関数が準備できたので、
爆発処理を実装している Explosion 関数から呼び出すようにしていきます

Explosion 関数の GetComponent<MeshRenderer>().enabled = false; の下に
下記のコードを追加します

// 爆風を広げる
StartCoroutine( CreateExplosions( Vector3.forward ) ); // 上に広げる
StartCoroutine( CreateExplosions( Vector3.right ) ); // 右に広げる
StartCoroutine( CreateExplosions( Vector3.back ) ); // 下に広げる
StartCoroutine( CreateExplosions( Vector3.left ) ); // 左に広げる

これで、爆風を広げるコードの実装が完了したので、
スクリプトを保存して Unity に戻ります

f:id:baba_s:20180329163720p:plain

最後に、「Prefabs」フォルダ内の「Bomb」プレハブを選択し、
Inspector で「Level Mask」を「Blocks」に変更します

f:id:baba_s:20180329163947g:plain

これで、Unity を再生して Space キーや Enter キーを押すと、
爆弾が 3 マスに広がって爆発することが確認できます

連鎖

次は、爆風が別の爆弾に触れたら、その爆弾も爆発するようにしていきます

コードエディタで「Bomb.cs」を開き、CreateExplosions 関数の下に
下記のコードを追加します

// 他のオブジェクトがこの爆弾に当たったら呼び出される
public void OnTriggerEnter( Collider other )
{
}

さらに、すでに爆弾が爆発している場合は連鎖しないようにするために、
levelMask 変数の下に、爆発したかどうかを管理する下記の変数を追加します

private bool exploded = false; // すでに爆発している場合 true

そして、先ほど追加した OnTriggerEnter 関数の中に下記のコードを追加します

// まだ爆発していない、
// かつ、この爆弾にぶつかったオブジェクトが爆発エフェクトの場合
if ( !exploded && other.CompareTag( "Explosion" ) )
{
    // 2 重に爆発処理が実行されないように
    // すでに爆発処理が実行されている場合は止める
    CancelInvoke( "Explode" );

    // 爆発する
    Explode();
}

最後に、Explosion 関数の GetComponent<MeshRenderer>().enabled = false; の下に
爆発したかどうかを管理する exploded を更新する下記のコードを追加します

// 爆発した
exploded = true;

f:id:baba_s:20180329164828g:plain

これで、Unity を再生して Space キーや Enter キーを押すと、
爆弾が連鎖して爆発するようになったことが確認できます

プレイヤーの死

ここまでで、爆弾が爆発する処理の実装が完了したので、
あとは、ゲームの終了処理を作成していきます

f:id:baba_s:20180329171933p:plain

まず、コードエディタで「Player.cs」を開き、
canMove 変数の下に下記のコードを追加します

public bool dead = false; // 死亡した場合 true

この変数は、プレイヤーが爆発で死亡したかどうかを管理する変数です
続いて、下記のコードも追加します

public GlobalStateManager globalManager; // ゲームの状態を管理するスクリプト

GlobalStateManager は、どのプレイヤーが勝利したのかを判断するスクリプトです
プレイヤーが死亡したら、globalManager 変数に通知します

「Player.cs」の末尾には、OnTriggerEnter 関数がすでに定義されており、
プレイヤーが爆風に触れたかどうかを確認する if 文が記述されています

OnTriggerEnter 関数の Debug.Log の呼び出しの下に、下記のコードを追加します

// 死亡した
dead = true;

// ゲームの状態を管理するスクリプトに
// 死亡したプレイヤーの番号を通知
globalManager.PlayerDied( playerNumber );

// プレイヤーを削除
Destroy( gameObject );

ここで、一旦スクリプトを保存して Unity に戻り、

f:id:baba_s:20180329170018p:plain

Hierarchy の欄で「Player1」と「Player2」を選択します
(Ctrl キーを押しながらクリックすると、同時に選択できます)

f:id:baba_s:20180329170147p:plain

「Global State Manager」オブジェクトを、
「Global Manager」の欄にドラッグして設定します

f:id:baba_s:20180329170316g:plain

これで、Unity を再生すると、
爆風がプレイヤーに触れた時に、プレイヤーが死亡することが確認できます

勝敗判定

最後に、どちらのプレイヤーが勝利したのか判定する処理を実装していきます

f:id:baba_s:20180329171951p:plain

コードエディタで「GlobalStateManager.cs」を開き、
PlayerDied 関数の上に、下記のコードを追加します

private int deadPlayers = 0; // 死亡したプレイヤーの数
private int deadPlayerNumber = -1; // 死亡したプレイヤーの番号

次に、PlayerDied 関数の中に下記のコードを追加します

// 死亡したプレイヤーの数を増やす
deadPlayers++;

// 1 人のプレイヤーが死亡したら
if ( deadPlayers == 1 )
{
    // 死亡したプレイヤーの番号を保持し、
    deadPlayerNumber = playerNumber;

    // 0.3f 秒後に CheckPlayersDeath 関数を呼び出す
    Invoke( "CheckPlayersDeath", 0.3f );
}

そして、最後に、PlayerDied 関数の下に下記のコードを追加します

void CheckPlayersDeath()
{
    // 死亡したプレイヤーが 1 人だけの場合
    if ( deadPlayers == 1 )
    {
        // プレイヤー 1 が死亡した場合
        if ( deadPlayerNumber == 1 )
        {
            // プレイヤー 2 が勝利した
            Debug.Log( "プレイヤー 2 の勝利!" );
        }
        // プレイヤー 2 が死亡した場合
        else
        {
            // プレイヤー 1 が勝利した
            Debug.Log( "プレイヤー 1 の勝利!" );
        }
    }
    // すべてのプレイヤーが死亡した場合
    else
    {
        // 引き分け
        Debug.Log( "引き分け" );
    }
}

f:id:baba_s:20180329171409g:plain

これで、スクリプトを保存して Unity に戻り、
Unity を再生して、爆風がプレイヤーに触れると、
Console ウィンドウに対戦結果が出力されることが確認できます

(Console ウィンドウは Ctrl + Shift + C を押すと表示されます)

以上で、ボンバーマン風のゲームを作るチュートリアルが終わりとなります

さいごに

https://koenig-media.raywenderlich.com/uploads/2017/09/Bomberman-How-To-Final-Project.zip

チュートリアルの完成プロジェクトは、上記のページからダウンロードできます

このチュートリアルでは、主に爆弾の配置や爆発、
勝敗判定の実装方法を紹介してきました

興味があれば、下記のようなロジックも実装してみて頂ければと思います

  • 爆弾を押せるようにする
  • 配置できる爆弾の数を制限する
  • リトライ機能を実装する
  • 爆風で破壊できるブロックを配置する
  • パワーアップアイテムを作成する
  • 勝敗判定の結果を UI で表示する
  • より多くのプレイヤーを操作できるようにする

関連記事