見出し画像

【Unity】3Dローグライクゲームの作り方〜Step12-10〜

前回の記事はこちら
前回はキャラクターIDの定数を定義し、オブジェクトの出現テーブルを作成しました。

アイテムをランダム配置する

アイテムをランダム配置させてみようと思います。
まずFieldクラスに新しいパラメーターとメソッドを追記し、SetObjectメソッドを以下のように書き換えましょう。

// スクリプトの最初に以下を追記
using System.Collections.Generic;

// パラメーターを追加
public ExcelAppearData appearDatabase;

// メソッドを追加
/**
* フィールドにアイテムを設置する
* nameに「Random」が指定されていた場合はその場所にランダムなアイテムを設置する
*/
private void SetItem(string name, int xgrid, int zgrid)
{
   Item itemData;
   EItem itemId = EItem.NONE;
   if (name.Equals("Random"))
   {
       List<ExcelAppearData.ItemAppearData> cItems =
           appearDatabase.ItemAppear.FindAll(n => !n.shoponly && n.start <= floorNum && n.end >= floorNum);
       int maxRate = 0;
       foreach (var cItem in cItems) maxRate += cItem.rate;
       int p = Random.Range(1, maxRate+1);
       foreach (var cItem in cItems)
       {
           Debug.Log(p);
           p -= cItem.rate;
           if (p <= 0)
           {
               itemId = cItem.id;
               break;
           }
       }
   }
   else if (!System.Enum.TryParse(name, out itemId)) return;
   if ((int)itemId > 1000) itemData = itemDatabase.Goods.Find(n => n.id == itemId);
   else itemData = itemDatabase.Equipments.Find(n => n.id == itemId);
   /*   省略   */
   return;
}

// メソッドを変更
public void SetObject(string name, string type, int xgrid, int zgrid)
{
   switch (type)
   {
       case "Stairs":
           /*   省略   */
       case "Enemy":
           /*   省略   */
       case "Item":
           SetItem(name, xgrid, zgrid);
           break;
   }
}

アイテムの候補のリストを取得し、その確率を全て足し合わせます。そこからランダムな数値を作り、確率を引いていくと最終的に0以下になります。その時のアイテムを作成するようにしています。
次にLoadFieldMapスクリプトを開き、RandomDungeonクラスのSetObjectsメソッドの最後に追記して下さい。

SetObject("Random", "Item", field, tmpData);

テストしてみます。以下のようにランダムにアイテムが配置されればOKです。

スクリーンショット 2020-06-08 17.20.26

スクリーンショット 2020-06-08 17.43.19

アイテムをランダムに複数配置する

とりあえずランダムに配置することはできましたので、今度は複数配置してみたいと思います。
その為に、マップデータファイルを以下のように編集します。

スクリーンショット 2020-06-08 20.22.34

まずGroup Layerを「3F」という名前で作成し、それにカスタムプロパティを上記のように4つ作成しましょう。それぞれそのマップでの敵の最大数、最小数、アイテムの最大数、最小数を表しています。
保存したら、Assetsフォルダ内のファイルを置き換えるのを忘れずに。
それではコードを書いていきたいと思います。
まずRandomDungeonクラスに新しいパラメーターを追加し、CreateとSetObjectsメソッドを変更します。

// パラメーターを追加
private int[] enemyNum;
private int[] itemNum;

// メソッドを変更
public Array2D Create(int w, int h, Field field, int[] eNum, int[] iNum)
{
   enemyNum = eNum;
   itemNum = iNum;
   data = new Array2D(w, h);
   /*   省略   */
}

private void SetObjects(Field field)
{
   /*   省略   */
   int num = Random.Range(itemNum[0], itemNum[1] + 1);
   for (int i = 0; i < num; i++)
       SetObject("Random", "Item", field, tmpData);
}

次にLoadFieldMapクラスのReadMapFileメソッドを変更します。

private Array2D ReadMapFile(string path)
{
   try
   {
       XDocument xml = XDocument.Load(path);
       XElement map = xml.Element("map");
       XElement group = null;
       foreach (var gp in map.Elements("group"))
       {
           if (gp.Attribute("name").Value.Equals(Field.floorNum + "F"))
           {
               group = gp;
               break;
           }
       }
       if (group == null) return null;
       int w = int.Parse(map.Attribute("width").Value);
       int h = int.Parse(map.Attribute("height").Value);
       Array2D data = null;
       foreach (var layer in group.Elements("layer"))
       {
           /*   省略   */
       }
       foreach (var objgp in group.Elements("objectgroup"))
       {
           /*   省略   */
       }
       if (data == null)
       {
           int[] enemyNum = new int[2];
           int[] itemNum = new int[2];
           foreach (var prop in group.Element("properties").Elements("property"))
           {
               int num = int.Parse(prop.Attribute("value").Value);
               switch (prop.Attribute("name").Value)
               {
                   case "EnemyNumMin":
                       enemyNum[0] = num;
                       break;
                   case "EnemyNumMax":
                       enemyNum[1] = num;
                       break;
                   case "ItemNumMin":
                       itemNum[0] = num;
                       break;
                   case "ItemNumMax":
                       itemNum[1] = num;
                       break;
               }
           }
           data = dungeon.Create(w, h, field, enemyNum, itemNum);
       }
       return data;
   }
   catch (System.Exception i_exception)
   {
       Debug.LogErrorFormat("{0}", i_exception);
   }
   return null;
}

テストしてみます。このようにランダムに複数個アイテムが置かれていればOKです。

スクリーンショット 2020-06-09 7.01.49

スクリーンショット 2020-06-09 7.06.04

といった所で、今回はおしまいです。
次回は敵の移動AIを改良したいと思います。

この記事が気に入ったらサポートをしてみませんか?