メインコンテンツまでスキップ

パブリック API

公開 API は Indie、Pro、Source、Studio の各エディションに含まれます(Starter では API は非公開です)。C# の完全なソースコードは Source と Studio にのみ含まれます。このガイドでは、ゲームプレイのコードを内部に結合させることなく、独自の C# スクリプトから MCE とやり取りし、拡張するために使える、安定したパブリック API の範囲を説明します。

パブリック API

安定性とは、名前についての約束です。それ以外はバージョン間で変わりえます。

SDK 名前空間​

MCE は、OpenMon.MCE.SDK 名前空間を通じてパブリック API を公開しています。ここには、コードを内部実装に結合させずにエンジンのサブシステムへアクセスできる、クリーンなインターフェースが含まれます。

IMonsterCaptureEngine​

主要なエントリポイントです。ほかのすべてのインターフェースは、これを通じてアクセスします。

using OpenMon.MCE.SDK;

public class MyGameManager : MonoBehaviour
{
[Inject] private IMonsterCaptureEngine engine;

private void Start()
{
Debug.Log($"MCE Version: {engine.Version}");
Debug.Log($"Monsters in DB: {engine.Database.MonsterCount}");
Debug.Log($"Player name: {engine.Player.PlayerName}");
}
}

プロパティ:

プロパティ型説明
DatabaseIMonsterDatabaseモンスター/技/アイテムデータベースへの読み取り専用アクセス
BattleIBattleSystemバトルの状態とイベント
PlayerIPlayerDataプレイヤーのロースター、お金、名前、バッジ
SaveSystemISaveSystemセーブとロードの操作
VersionstringMCE エンジンのバージョン文字列

IMonsterDatabase​

モンスター、技、特性、アイテム、タイプを問い合わせます。

IMonsterDatabase db = engine.Database;

// Get a monster by dex number (National Dex; the parameter is a uint)
MonsterEntry flameleon = db.GetMonster(152u);

// Get a monster by name
MonsterEntry sparkbit = db.GetMonster("Sparkbit");

// Get all monsters
IReadOnlyList<MonsterEntry> allMonsters = db.GetAllMonsters();

// Get a move
Move thunderbolt = db.GetMove("Thunderbolt");

// Get all moves
IReadOnlyList<Move> allMoves = db.GetAllMoves();

// Get type effectiveness. Types are ScriptableObjects fetched from the database
// (there is no MonsterType enum), so look them up by name first:
MonsterType electric = db.GetAllTypes().FirstOrDefault(t => t.name == "Electric");
MonsterType water = db.GetAllTypes().FirstOrDefault(t => t.name == "Water");
float effectiveness = db.GetTypeEffectiveness(electric, water);
// Returns 2.0 (super effective)

// Get all types
IReadOnlyList<MonsterType> types = db.GetAllTypes();

// Get total count
int count = db.MonsterCount;

IBattleSystem​

バトルの状態とイベントのための SDK コントラクトです。

IBattleSystem battle = engine.Battle;

// Is a battle in progress?
if (battle.IsInBattle) { /* ... */ }

// Subscribe to battle events
battle.OnBattleStarted += HandleBattleStarted;
battle.OnBattleEnded += HandleBattleEnded; // bool playerWon
エンジンはまだこれらを発生させません

IsInBattle、OnBattleStarted、OnBattleEnded は、現在のエンジンが呼び出さないエンジンフック(BattleSystemFacade.NotifyBattleStarted / NotifyBattleEnded)によって供給されるため、動作しないままです。代わりにバトルランチャーを通じてバトルを監視してください -- パターン 1 と IBattleSystem の注記を参照してください。

IPlayerData​

プレイヤーの現在の状態にアクセスします。

IPlayerData player = engine.Player;

// Player's monster team
Roster roster = player.PlayerRoster;
int teamSize = roster.RosterSize;
MonsterInstance firstMonster = roster[0];

// Player's money, as of the last save (the live balance is in the bag)
int money = player.Money;

// The name of the player's CharacterData asset
string name = player.PlayerName;

// Player's badge count
int badges = player.BadgeCount;

ISaveSystem​

セーブとロードのための SDK コントラクトです。

ISaveSystem saves = engine.SaveSystem;

saves.Save(1);
saves.Load(1);
bool hasData = saves.HasSaveData(1);
saves.DeleteSave(1);

saves.OnSaved += (slot) => Debug.Log($"Saved to slot {slot}");
saves.OnLoaded += (slot) => Debug.Log($"Loaded from slot {slot}");
エンジンのセーブにはまだ接続されていません

現在のエンジンでは、engine.SaveSystem は SavegameManager に接続されていません。Save と Load は、誰も処理しないリクエストを発生させるだけで、イベントは決して発火しません。エンジンは名前付きのフォルダーとして保存します(セーブシステム ガイドを参照)。独自のフラグやカウンターをプレイヤーのセーブとともに永続化するには、GlobalGameData のゲーム変数を使ってください(パターン 3 を参照)。

依存性注入​

MCE は依存性注入に Zenject(Extenject)を使います。スクリプトで SDK インターフェースにアクセスするには、[Inject] 属性を使います。

using Zenject;
using OpenMon.MCE.SDK;

public class MyCustomFeature : MonoBehaviour
{
// IMonsterCaptureEngine is the only SDK interface bound in DI
// (see SDKInstaller). Reach the subsystems through its properties.
[Inject] private IMonsterCaptureEngine engine;

private IMonsterDatabase database;
private IBattleSystem battle;

private void Awake()
{
// engine is injected before Awake/Start runs
database = engine.Database;
battle = engine.Battle;
}
}
Zenject の経験がない場合

依存性注入に不慣れなら、簡単に言うとこうです。private な IMonsterCaptureEngine フィールドの上に [Inject] を付ければ、Zenject が自動的に値を入れてくれます。GetComponent や FindObjectOfType を呼ぶ必要はありません。フィールドは Start() が実行される前に設定され、ほかの SDK インターフェースはそこからぶら下がっています(engine.Database、engine.Battle、engine.Player、engine.SaveSystem)。

スクリプトが Zenject に管理される MonoBehaviour でない場合は、手動で解決できます。

var engine = ProjectContext.Instance.Container.Resolve<IMonsterCaptureEngine>();

Inspector で設定できるオプション​

MCE の多くのシステムは、コードなしで Unity の Inspector から設定を公開しています。

ScriptableObject による設定​

アセット目的
MCESettingsゲーム全体の設定:タイプごとのエンカウント確率(TileEncounterChance)、野生の色違いの確率、経験値のルール、ゲーム内 1 日の長さ、感情バルーン
BattleConfigurationFileプレイヤー向けのバトル設定:バトルスタイルとアニメーションの高速化
BattleLauncherバトルシーン、野生とトレーナーのバトル音楽、デフォルトのバトル AI
MonsterEntryモンスターの種のデータ
Move技の定義(技ごとに 1 つの具象クラス)
WildEncountersSetエンカウントテーブル。各マップの SceneInfo アセットからリンクされる
BattleAIAI 戦略。Fallback で連結される

コンポーネントによる設定​

MCE のほとんどのコンポーネントは、主要な設定を Inspector に公開しています。

  • MCECharacterController / PlayerCharacter:1 歩あたりの秒数での速度、表示するキャラクターまたはモンスター。
  • EncounterTile:タイルのエンカウントタイプ。
  • SceneInfo(とその SceneInfoAsset):マップ名、音楽、地方、天候、エンカウント。
  • Actor とそのサブクラス:CommandGraph のスロット(有効化時、ループ、インタラクト、オンデマンド)。

イベントとコールバック​

MCE はコンポーネントに UnityEvent フィールドを使わず、スクリプトから購読する通常の C# イベントとコールバックを発生させます。最も便利なもの:

場所イベント発生するタイミング
IBattleLauncherSubscribeToBattleLaunched、SubscribeToBattleToUnload、SubscribeToBattleEnded(Action<BattleResultParameters>)バトルシーンが起動された、アンロードされる直前、またはバトルが終了したとき
IBattleSystemOnBattleStarted、OnBattleEnded(bool playerWon)予約:エンジンがフックを呼び出したときに SDK ファサードが発生させる(まだ接続されていません)
RosterOnRosterUpdatedロースターのモンスターが変わったとき
QuestManagerOnQuestStarted、OnObjectiveProgressed、OnObjectiveChanged、OnQuestCompleted、OnQuestFailed、OnRewardsGranted対応するクエストイベント
PlayerEmotes(静的)Played(string balloonName)ローカルプレイヤーが感情バルーンを表示したとき

グラフから独自の C# を実行するには、カスタムノードを書きます(次のセクション)。

ソースコードなしで MCE を拡張する​

パターン 1:イベントリスナー​

MCE のイベントを購読し、独自のロジックを発動する MonoBehaviour を作成します。バトルランチャーは DI にバインドされており、バトルが終了したときに通知します。

using OpenMon.MCE.Battle;

public class AchievementTracker : MonoBehaviour
{
[Inject] private IBattleLauncher battleLauncher;

private int battlesWon;

private void OnEnable() => battleLauncher.SubscribeToBattleEnded(OnBattleEnded);

private void OnDisable() => battleLauncher.UnsubscribeFromBattleEnded(OnBattleEnded);

private void OnBattleEnded(BattleResultParameters result)
{
if (!result.PlayerWon) return;

battlesWon++;
if (battlesWon >= 100)
UnlockAchievement("Battle Master");
}
}

パターン 2:データベースへの問い合わせ​

データベース API を使って、独自の機能を構築します。

public class TypeMatchupHelper : MonoBehaviour
{
[Inject] private IMonsterCaptureEngine engine;

private IMonsterDatabase database;

private void Awake()
{
database = engine.Database;
}

public List<MonsterType> GetWeaknesses(MonsterType type)
{
var weaknesses = new List<MonsterType>();
foreach (var attackType in database.GetAllTypes())
{
if (database.GetTypeEffectiveness(attackType, type) > 1f)
weaknesses.Add(attackType);
}
return weaknesses;
}
}

パターン 3:セーブとの統合​

独自のフラグやカウンターを、GlobalGameData(CommandGraph が使うのと同じストア)のゲーム変数として保存することで、プレイヤーのセーブに保持します。ほかのすべてのものと一緒に、保存、ロード、リセットされます。

using OpenMon.MCE.Player;

// The marker interface IPlayerDataReceiver is what makes the player's data
// (GlobalGameData, Roster, CharacterData...) injectable into a class.
public class AchievementCounters : MonoBehaviour, IPlayerDataReceiver
{
[Inject] private GlobalGameData globalGameData;

public void CountBattleWon()
{
int won = globalGameData.GetVariable<int>("battlesWon");
globalGameData.SetVariable("battlesWon", won + 1);
}
}

変数はホルダー上に存在している必要があります(GlobalGameData アセットのゲーム変数で定義してください)。セーブシステム ガイドを参照してください。

パターン 4:カスタム CommandGraph ノード​

ビジュアルスクリプティングから独自の C# を呼び出すには、ノードを書きます。ノードは、あなた自身のアセンブリにある、SingleExecutionPathCommandNode を継承する小さな [Serializable] クラスで、エディターは、その名前空間の最後のセグメントのもとで、グラフの Create Command メニューに一覧表示します。

using System;
using System.Collections;
using OpenMon.MCE.Actors.CommandGraph;

namespace MyGame.Events
{
[Serializable]
public class AwardAchievement : SingleExecutionPathCommandNode
{
[UnityEngine.SerializeField] private string AchievementId;

protected override IEnumerator Run(CommandParameterData parameterData,
Action<CommandParameterData> callback)
{
MyAchievements.Unlock(AchievementId);
yield break;
}
}
}

すると、ノードは Create Command / Events / AwardAchievement として表示されます。ノードが読み取れるコンテキスト(CommandParameterData)については、CommandGraph API を参照してください。

ソースコードなしではできないこと​

制限回避策
ダメージ計算式そのものを変更する特性、アイテム、状態、技(ScriptableObject)を通じて係数を追加する。計算式は Source / Studio エディションに含まれる
新しいバトルモジュールを追加するモジュールはエンジンのコンポーネント(Source / Studio エディション)。IBattleSystem のイベントを通じて反応する
移動の物理を変更するステップの速度と、TileData のタイルタイプを調整する
バトルループの順序付けを変更するSource / Studio エディション
UI レイアウトを変更するプレハブを上書きする(公開されていれば)、または独自の UI を上に重ねる
もっと制御が必要ですか?

パブリック API がプロジェクトにとって制限が多すぎると感じる場合は、Source エディションへのアップグレードを検討してください。深いカスタマイズのための、完全な C# ソースコードとアーキテクチャのドキュメントが含まれています。

アセンブリ参照​

スクリプトで MCE の型を参照するには、アセンブリ定義(.asmdef)で次を参照する必要があります。

{
"references": [
"OpenMon.MCE.Runtime"
]
}

アセンブリ定義を使っていない場合、MCE の型は DLL を通じてグローバルに利用できます。

ベストプラクティス​

  1. 実装ではなくインターフェースに依存する。具象クラスではなく IMonsterCaptureEngine を使います。
  2. イベントの購読を解除する。メモリリークを防ぐため、イベントハンドラーは必ず OnDisable または OnDestroy で削除します。
  3. 古いデータをキャッシュしない。特に IPlayerData では、最新のデータが必要なたびに SDK に問い合わせます。
  4. Zenject の注入を使う。MCE へのアクセスに FindObjectOfType やシングルトンを使うのは避けます。
  5. API リファレンスを確認する。SDK のインターフェースには、すべてのメンバーに XML ドキュメントがあります。IDE がツールチップを表示します。