超初心者のゲーム開発記~Unity~

超初心者がUnityでゲーム(目標はAndroidアプリ )を開発していくブログです!

【Unity 2Dローグライク】公式チュートリアルをやってみる part.5~ランダムなステージ生成

こんにちは!ヤギです!

Unityの2Dローグライクの
公式チュートリアルをやってみる part.5になります!
※前回(part.4)の記事はこちら
www.yagigame.com

記事概要

今回の記事では、ゲームのステージをランダムに生成するためのスクリプトを作成します!
※part.5に対応する公式チュートリアルの章は、Creating the Tile Prefabsです!
unity3d.com
※この記事は、ひよこのたまご様の記事をリスペクトしています。
hiyotama.hatenablog.com

スクリプトの前準備

1. Project > Create > c#Scriptから、スクリプトを2つ作成します。
※名前をBordManagerと、GameManagerとします。
f:id:yagigame:20181031085716p:plain
2. Hierarchy > Create Emptyでからのゲームオブジェクトを作成します。
※名前をGameManagerとします。
f:id:yagigame:20181031085904p:plain

スクリプト(BoardManager)の作成

ステージを生成するためのスクリプト(BoardManager)を書いていきます。
※スクリプト内にコメントに説明を書きましたので、ご参照ください。

using System.Collections;
using System.Collections.Generic; //配列を使う
using UnityEngine;
using System;
using Random = UnityEngine.Random; //ランダム要素を使う

public class BoardManager : MonoBehaviour {

    [Serializable] //Inspectorに表示する
    public class Count{
        public int minimum;
        public int maximum;

        public Count(int min, int max){
            minimum = min;
            maximum = max;
        }
    }

    public int columns = 8; //ステージの横幅
    public int rows = 8; //ステージの縦幅

    public Count wallCount = new Count(5, 8); //壁の個数の最小と最大を決める
    public Count foodCount = new Count(1, 5); //食料の個数の最小と最大を決める
    public GameObject exit;
    public GameObject[] floorTiles;
    public GameObject[] wallTiles;
    public GameObject[] foodTiles;
    public GameObject[] enemyTiles;
    public GameObject[] outerWallTiles;

    private Transform boardHolder; //オブジェクトの位置を保存
    private List<Vector3> gridPositions = new List<Vector3>(); //オブジェクトを配置できる範囲を指定

    //敵やアイテム、内側の壁(Wall)を配置できる位置を特定
    void InitializeList(){
        //gridPositionsを初期化
        gridPositions.Clear();
        //gridPositionsに敵やアイテムを配置できる範囲を設定する
        //横方向の範囲
        for (int x = 1; x < columns - 1; x++){
            //縦方向の範囲
            for (int y = 1; y < rows - 1; y++){
                //範囲をgridPositionsに追加していく
                gridPositions.Add(new Vector3(x, y, 0f));
            }
        }
    }

    //外側の壁(OuterWall)、床を配置する
    void BoardSetUp(){
        //boradHolderを位置情報を持つゲームオブジェクト(Board)として初期化する
        boardHolder = new GameObject("Board").transform;
        for (int x = -1; x < columns + 1; x++){
            for (int y = -1; y < rows + 1; y++){
                //床をランダムに選択
                GameObject toInstantiate = floorTiles[Random.Range(0, floorTiles.Length)];
                if(x == -1 || x == columns || y == -1 || y == rows){
                    //ステージの外周には、OuterWallを選択する
                    toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];
                }
                //選択した床や、壁を実際に生成する
                GameObject instance = Instantiate(toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;
                //生成したオブジェクトをBoardオブジェクトの子オブジェクトとする
                instance.transform.SetParent(boardHolder);
            } 
        }
    }

    //ランダムな位置を返す
    Vector3 RandomPosition()
    {
        //返す位置の範囲は、アイテムを配置できる範囲
        int randomIndex = Random.Range(0, gridPositions.Count);
        //ランダムな位置の座標を取得
        Vector3 randomPosition = gridPositions[randomIndex];
        //重複しないように、取得した場所は削除する
        gridPositions.RemoveAt(randomIndex);
        //位置の座標を返す
        return randomPosition;
    }

    //敵やアイテム、内側の壁(Wall)を配置する ※SetupSceneから呼ばれる
    void LayoutObjectAtRandom(GameObject[] tileArray,int minimum, int maximum){
        //ランダムな回数ループする
        int objectCount = Random.Range(minimum,maximum+1);
        for (int i = 0; i < objectCount; i++){
            //gridPositionからランダムな位置を取得
            Vector3 randomPosition = RandomPosition();
            //tileArrayからオブジェクトの種類をランダムに選択
            GameObject tileChoice = tileArray[Random.Range(0, tileArray.Length)];
            //ランダムで決めた位置に、ランダムに決めたオブジェクトを配置
            Instantiate(tileChoice, randomPosition, Quaternion.identity);[f:id:yagigame:20181031102151p:plain]
        }
    }

    //レベルに応じてステージを作成する ※GameManager.csから呼ばれる
    public void SetupScene(int level){
        //外側の壁(OuterWall)、床を配置する
        BoardSetUp();
        //敵やアイテム、内側の壁(Wall)を配置できる位置を特定
        InitializeList();
        //敵やアイテム、内側の壁(Wall)を配置する
        LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);
        LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum);
        //敵の数をLogで計算
        int enemyCount = (int)Mathf.Log(level,2f);
        LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);
        //出口を右上に配置する
        Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
    }
}

スクリプト説明

  • InitializeList():以下の画面の範囲にに、敵や食料を配置する場所を設定します。

f:id:yagigame:20181031102040p:plain

  • BoardSetUp():以下の画面の範囲に、外側の壁を設定します。

f:id:yagigame:20181031102151p:plain

  • RandomPosition():ゲームオブジェクトを配置するランダムな座標を特定します。
  • LayoutObjectAtRandom(GameObject[] tileArray,int minimum, int maximum):実際に、敵やアイテムを配置します。
  • SetupScene:上4つの関数を呼び出すことで、ステージを作成します。

※ランダムなステージを作成するためのスクリプト(BoardManager)が完成しました!

次回予告

次回の記事では、今回作成したBordManagerを呼び出すGameManagerの作成について書いていきたいと思います。
次回の記事で、ランダムなステージの作成が完了します。
※Unityのチュートリアルの章としては、次回は(Writing the Game Manager)となります!

読んでいただきありがとうございました!