【Unity2D 入門】横スクロールアクションゲームを作ってみたい -敵のAIの作成

raharu(仮名)(プログラマー)
これがダイバージェンス1%の先の世界か。。。

※非常にニュアンスだけのざっくりとしたソースに出来上がり非常に不本意ですが、
やりたい事はこんな感じです

  1. 敵はジャンプ、歩く、攻撃をランダムに選択
  2. ランダムに選択されたモーションをプレイヤーに対して行なう
  3. 方向も変わればオブジェクトの向きも変える

こんな物を書いてみました。

mob_AI

using UnityEngine;
using System.Collections;
public class mob_AI : MonoBehaviour {
public GameObject firePrefab;
private int move_type = 0;
private Vector3 forward;
private bool isIdle = true;
private bool isAttack = false;
private bool isWalk = false;
private bool isJump = false;
// JumpParams
private float jumpPowor;
public float jumpPoworConst = 0.8f;
public float jumpGrvity = 0.05f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//アイドル状態
if(isIdle){
// ランダムでモーション種類基準となる番号を取得
move_type = Random.Range(0, 4);
// 歩くフラグが立っていたら
}else if(isWalk){
//playerオブジェクトをを取得して向きを決定
GameObject player2 = GameObject.Find("player");
Vector3 forward = player2.transform.position - transform.position;
// 向きに対してモーションを行なう&向きも変える
if(forward.x > 0){
transform.Translate(Vector3.right * 0.1f);
transform.localScale = new Vector3(-2, 2, 2);
}else{
transform.Translate(Vector3.left * 0.1f);
transform.localScale = new Vector3(2, 2, 2);
}
return;
// ジャンプフラグが立っていたら
}else if(isJump){
//ジャンプ力を計算
jumpPowor = jumpPowor - jumpGrvity;
transform.Translate(Vector3.up * jumpPowor);
//地面に着地したら処理処理終了
if(jumpPowor < 0 && transform.position.y <= 1){
isIdle = true;
isJump = false;
}
return;
}else{
return;
}
//Attack
if(move_type == 1){
isIdle = false;
isAttack = true;
//攻撃オブジェクトを生成
GameObject fire = Instantiate(firePrefab, new Vector3(transform.position.x, transform.position.y - 0.5f, 1), Quaternion.identity) as GameObject;
// 攻撃オブジェクトのタグを変える
fire.gameObject.tag = "mob";
// 攻撃向きと飛ばす方向を決める
GameObject player2 = GameObject.Find("player");
Vector3 forward = player2.transform.position - transform.position;
if(forward.x > 0){
fire.gameObject.SendMessage("setDirection", true);
transform.localScale = new Vector3(-2, 2, 2);
}else{
fire.gameObject.SendMessage("setDirection", false);
transform.localScale = new Vector3(2, 2, 2);
}
//スリープ
StartCoroutine("WaitFotAttack");
}
// Walk
if(move_type == 2){
isIdle = false;
isWalk = true;
StartCoroutine("WaitFotWalk");
}
// Jump
if(move_type == 3){
isIdle = false;
isJump = true;
jumpPowor = jumpPoworConst;
}
}
IEnumerator WaitFotAttack()
{
yield return new WaitForSeconds(2.0f);
isIdle = true;
isAttack = false;
}
IEnumerator WaitFotWalk()
{
yield return new WaitForSeconds(0.5f);
isIdle = true;
isWalk = false;
}
}

こんなかんじですが、、、
非 常 に 雑 か つ 汎 用 性 の 無 い ソ ー ス !!

認めます。これじゃ正直今後の拡張には一切耐えられないでしょう。

ソースの問題点

モーションの処理を使い回せない

この敵の動きって正直playerと同じなんですよね、この処理をコピーしてるなんてダサすぎです

モーションが増える度にupdate内にソース行が増えていく

今はアイドル状態、攻撃、ジャンプ、歩くの4つの動きなのでまだ良いですけど。
こんなもんをいちいち持っていられません。

playerの向きを取得するのに毎回Findが走る
最初はplayerオブジェクトはメンバにセットされていたのですが、
実際に動かしてみると、最初にソースが読み込まれた時のplayerの位置情報をキャッシュしてしまい、
playerが動いても敵はずっと同じ方向にplayerがいるという認識をしました。

これをなんとかしたかったのですが、方法が見つからず非常に不本意ながらFindしてみました。

次回へ向けての課題

モーションを実行するソースは個別に作る
ただジャンプするというtransformを変更するスクリプトを作り
それを対象のオブジェクトにアタッチするのが普通だと思います。

オブジェクトの可変データに対するアプローチ方法の確立
public GameObject player;
で宣言したデータが可変する場合に毎フレーム毎に最新の情報を取得するのはこれしかできないのか?
をもう少し深く掘り下げたい

f:id:raharu0425:20140120185832p:plain