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

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

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

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

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

mob_AI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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