とあるプログラマの備忘録

都内某所に住むプログラマが自分用に備忘録を残すという趣旨のブログです。はてなダイアリーから移動しました!

Unity2D入門 スクロールアクションゲームを作る 敵のAIを作成してみる

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

  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