やりたいこと
業務アプリなどでは自作のExceptionクラスを作成し、それをthrowすることで呼び出し元が例外に応じて何か処理する(対応するエラーメッセージを表示する)などがあります。
(都度都度エラー処理をそこに細かく書かなくても、正常系の処理がスッキリするから)
Unityでも自作クラスで、「攻撃対象がいなかったらExceptionA」「行動できない状態だったらExceptionB」を投げよう、と思い同じように自作クラスのthrow、tyr-catchをさせようとしました。
ただし、呼び出し元へthrowしてしまうと、Editor上ではcatchの度に処理が止まってしまい、止めるほどの例外のつもりではないのになぁと悩んでいました。
今回は自作クラスをthrowする代わりに、子メソッドで戻り値を返し、最終的な判断を呼び出し元で処理する方法を作成してみました。
※拡張性などはあまり考慮していません・・・
実装
///呼び出される方
public override async UniTask<object> ActionSkill(List<BattleUnit> party, List<BattleUnit> enemyParty, BattleUnit owner)
{
int damage = await base.ConvertDataTable(party, enemyParty, owner);
damage = owner.CalcBaseDamage(damage);
if (!(enemyParty.Count > owner.PartyIndex && owner.PartyIndex >= 0))
return new TargetNotAwakenException(damage);
if (!(enemyParty[owner.PartyIndex] != null && enemyParty[owner.PartyIndex].isAwaken()))
return new TargetNotAwakenException(damage);
Debug.Log($"ダメージ処理:{actionName}=>{damage}");
enemyParty[owner.PartyIndex].GetDamage(damage);
return null;
}
親子継承関係で、共通してasyncになっていますがいったん細かいところは無視します。
このメソッドでは、戻り値にとりあえず「object」を返すよう定義しています。
※処理の内容によっては、intだったり自作例外クラスだったりするため。
そして何もなければ共通して「null」を返すようにします。
///呼び出し元
object result = await actions[i].ActionSkill(party, enemy, owner);
if (result != null)
{
if(result.GetType() == typeof(TargetNotAwakenException))
{
UIManager.Instance.OpenDialog1("エラー", (result as TargetNotAwakenException).Message);
owner!.CalcScore((int)(result as TargetNotAwakenException).scoreEffect);
}
}
「if(result.GetType() == typeof(TargetNotAwakenException))」では、「攻撃対象がいなかったので戦闘計算するまえに例外クラスを返す、スコアの加算処理だけ」を行ってます。
スキルアクションとして、アクションの処理の中で本来はダメージ処理までするのですが、対象がいなかった場合は共通して呼び出し元にスコア計算だけなげてしまうという方法です。
苦肉の策です。