はじめに
前回は、UI系の作成をしました。
今回は、エンカウント処理を実装します。
スクリプトの作成
新しく「MapEncounter」という名前のスクリプトを作成し、以下をコピペしてください。
// MapEncounter.cs
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MapChunk))]
public class MapEncounter : MonoBehaviour
{
[Header("Encounter settings")]
[Range(0f, 1f)]
[Tooltip("プレイヤーが1歩進むごとにこの確率でエンカウント判定を行う(典型は 0.05 = 5%)。")]
public float encounterRate = 0.10f;
[Tooltip("最大で一度に出現する敵数(RollEnemies 呼び出しのデフォルト値に使う)")]
public int defaultMaxEnemies = 3;
[Tooltip("同種の敵を複数体出現させることを許可するなら true。\nfalse にすると同一 EnemyData は1回しか選ばれなくなる。")]
public bool allowDuplicates = true;
[System.Serializable]
public struct Entry
{
public EnemyData enemy;
[Range(0f, 1f)]
public float weight;
}
[Header("Enemy pool (assign EnemyData and weight)")]
public List<Entry> enemyPool = new List<Entry>();
public List<EnemyData> RollEnemies(int maxCount = -1)
{
var result = new List<EnemyData>();
if (enemyPool == null || enemyPool.Count == 0) return result;
int actualMax = (maxCount <= 0) ? Mathf.Max(1, defaultMaxEnemies) : maxCount;
var candidates = new List<Entry>(enemyPool);
float total = 0f;
foreach (var e in candidates) total += Mathf.Max(0f, e.weight);
if (total <= Mathf.Epsilon)
{
var nonNullList = new List<EnemyData>();
foreach (var e in candidates)
{
if (e.enemy != null) nonNullList.Add(e.enemy);
}
if (nonNullList.Count == 0) return result;
int count = Random.Range(1, actualMax + 1);
for (int i = 0; i < count; i++)
{
var pick = nonNullList[Random.Range(0, nonNullList.Count)];
result.Add(pick);
if (!allowDuplicates) nonNullList.Remove(pick);
if (nonNullList.Count == 0) break;
}
return result;
}
int pickCount = Random.Range(1, actualMax + 1);
for (int p = 0; p < pickCount; p++)
{
float r = Random.value * total;
float acc = 0f;
EnemyData chosen = null;
for (int i = 0; i < candidates.Count; i++)
{
var e = candidates[i];
float w = Mathf.Max(0f, e.weight);
acc += w;
if (r <= acc)
{
chosen = e.enemy;
if (!allowDuplicates)
{
total -= w;
candidates.RemoveAt(i);
}
break;
}
}
if (chosen == null)
{
for (int i = 0; i < candidates.Count; i++)
{
if (candidates[i].enemy != null)
{
chosen = candidates[i].enemy;
if (!allowDuplicates)
{
total -= Mathf.Max(0f, candidates[i].weight);
candidates.RemoveAt(i);
}
break;
}
}
}
if (chosen != null)
result.Add(chosen);
if (candidates.Count == 0) break; // no more candidates
}
return result;
}
}
スクリプトができたら、これを 全てのチャンクプレハブにアタッチ してください。
インスペクターの調整
このうち、EnemyPoolで出現する敵を調整することができます。
Enemyという欄には、以前作成したEnemyDataを入れてください。
その下のWeightをいじることで、各敵の出現率を変えることができます。
実際の動き
ここまできちんと実装できていれば、プレイヤーが移動した際、エンカウント処理が発生するはずです。
また、その後の戦闘処理もうまくいくと思います。
おわり
今回をもって、本シリーズは終了です。
面倒くさい工程もありましたが、ここまで作業していただき、本当にありがとうございました。
このシリーズを通して、Unityのことがより好きになっていただけたら嬉しいです。
