2014年2月19日水曜日

[Unity][C#][ラムダ式]他オブジェクトに依存する処理のレシピ

こんにちは。開発の松本です。
しばらくObjective-Cをやっていましたが、久しぶりにUnityでゲーム開発をしています。
コンポーネント指向のUnityではMVCやオブジェクト指向がはまらず、勘を取り戻すのにやや苦労しました。

さて...
ゲームに限らず、他オブジェクトに依存する処理は、よくあると思います。
MVCだと「コントローラが、モデルなど他オブジェクトの状態を見て制御」ですが、Unityではしっくりこない気がします。(自分だけ?)
そこで今回、私が実装したレシピをご紹介します。(C#。見やすくするためnullチェックは省略)

例)魔法「イレカワール」

仕様

  • 自キャラと、仲間ターゲットキャラの位置が入れ替わる
  • 仲間ターゲットキャラが、攻撃中、魔法詠唱中、被ダメージ中、スタン中は、入れ替われない
  • 敵キャラとは入れ替われない

実装

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

using MagicParams = System.Collections.Generic.Dictionary<string, object>;
public delegate void MagicCallback (GameObject sender, MagicParams userParams);

public class Magic : MonoBehaviour {
 
 /** 入れ替わり */
 void Replace (GameObject him) {
  // コールバック
  MagicCallback replaceRes = (sender, resParams) => {
   // 返答OKの場合
   if ((bool)resParams ["result"]) {
    // 移動
    transform.position = (Vector3)resParams ["position"];
   }
   // 返答NG
   else {
    // 失敗メッセージ出力などを実装
   }
  };
  // 要求パラメータ
  MagicParams reqParams = new MagicParams () {
   {"sender", gameObject},
   {"position", transform.position},
   {"callback", replaceRes},
  };
  // 入れ替わり要求
  him.SendMessage ("ReplaceReq", reqParams);
 }
 
 /** 入れ替わり要求 */
 void ReplaceReq (MagicParams reqParams) {
  // 要求パラメータ
  GameObject sender = (GameObject)reqParams ["sender"];
  MagicCallback cb = (MagicCallback)reqParams ["callback"];
  // 返答パラメータ
  MagicParams resParams = new MagicParams () {
   {"sender", gameObject},
   {"position", transform.position},
  };
  // 入れ替わり可能かチェック
  if (!IsReplacable(sender)) {
   resParams ["result"] = false;
   if (null != cb) cb (gameObject, resParams);
   return;
  }
  // 移動
  transform.position = (Vector3)reqParams ["position"];
  resParams ["result"] = true;
  if (null != cb) cb (gameObject, resParams);
 }

 /** 入れ替わり可能か */
 bool IsReplacable (GameObject him) {
  // himが敵ならreturn false;
  // 自分が攻撃中、魔法詠唱中、被ダメージ中、スタン中ならreturn false;
  return true;
 }
}

以上のように、当事者同士でチェックし合って制御しています。ポイントは↓
  • コールバック処理をラムダ式で実装
  • パラメータはとりあえずDictionaryにぶち込んで渡す

Magic.csを、魔法を使う/受けるGameObjectに付けて使用します。
イレカワール詠唱時に、Replace(ターゲットGameObject)で呼べば、入れ替わります。

以上、他オブジェクトの状態などに依存する処理のレシピでした。 他にも色々方法はあると思います。ご指摘などあれば、コメントいただけると幸いですm(_ _)m