【Unity2D 入門】横スクロールアクションゲームを作ってみたい -攻撃アクションを作る2回目

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

さてさて、長い道のりでかなり苦戦しましたが2回目です。

前回で別々の挙動として
・プレイヤーが口を開ける
・炎が横に飛ぶ
という所までできたのですが、これを連結したいのです。

処理フローは以下の通り

  1. 攻撃時口を開ける(これは前回までにつくりました)
  2. 口元に炎のオブジェクトを生成
  3. キャラクターの方向から飛ばす方向を決める
  4. 敵にぶつかったら炎は消えて、敵はダメージを受ける

というかんじです。

攻撃時口元に炎オブジェクトを生成する

playermove.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class playermove : MonoBehaviour {

+   public GameObject firePrefab;

----------------------------

    void FixedUpdate ()
    {
        //  Attack
        if(Input.GetKeyDown("return")){
            isAttack = true;
            StartCoroutine("WaitForAttack");

+           // 炎オブジェクトを生成して方向フラグをsend
+           GameObject fire = Instantiate(firePrefab, new Vector3(transform.position.x, transform.position.y - 0.5f, 1), Quaternion.identity) as GameObject
+           fire.gameObject.SendMessage("setDirection", isRight);
        }

差分で+が付いている所が追加行何ですけどわかりにくかったらすいません
だんだんスクリプトが巨大になってきて全文貼付けるのが億劫になってきたのです!ww

public GameObject firePrefabにはまだ何もアタッチされていませんのでfirePrefabをアタッチしておきましょう

f:id:raharu0425:20140115183523p:plain

これで生成できるのですが、プレハブ側にsetDirectionメソッドが存在しないので、まだエラーになると思います。

moveattack.cs

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
using UnityEngine;
using System.Collections;

public class moveattack : MonoBehaviour {

    public float spd = 0.3f;
    public bool is_right_local = true;

    // Update is called once per frame
    void Update() {

        //受け取った方向を元に炎を飛ばす方向を決定
        if(is_right_local){
            transform.Translate(Vector3.right * spd);
        }else{
            transform.Translate(Vector3.left * spd);
            //炎オブジェクトを反転させる
            transform.localScale = new Vector3(-2, 2, 0);
        }
        Destroy(gameObject, 1.0f);
    }

    //方向を受け取る
    void setDirection(bool isRight = true)
    {
        is_right_local = isRight;
    }
}

なんかちょっとスマートじゃないスクリプトができあがりました。
updateに直接SendMessageができないのでsetDirection経由でupdateに渡しています。

これで大体いいでしょう、エミュレートしてみましょう

f:id:raharu0425:20140115184834p:plain

いいよいいよー!炎くちからでてるよー!

でもまだ敵に当たってもすり抜けると思います。
firePrefabにColliderが入ってないからですね。追加します。

f:id:raharu0425:20140115185135p:plain

さぁこれで敵にぶつかるようになりましたか?

 な ら な い !

しかも、、、
プレイヤーが攻撃した瞬間に飛びやがった!!まだジャンプは実装してないのにおかしいですね。

f:id:raharu0425:20140115185622p:plain

おそらく生成した瞬間にplayobjectとぶつかってplayrが移動してしまっている!?の?だれか偉い人教えてください。

ただこのままではいけないので炎オブジェクトはplayerとぶつかっても当たり判定を無視するようにしないと行けません。
色々調べたらなるほどisTriggerでなんとかできそうです。

playerオブジェクトとfireオブジェクトのCircleCollider 2DコンポーネントのisTriggerにチェックを入れます。

f:id:raharu0425:20140115190034p:plain

これで飛ばなくなったハズ!!!

よしよし、いいかんじです。ただまだmobにぶつからないですり抜けて行きますね。
mobにはRigidBodyが無いのでplayerとは反対に不本意にすり抜けている見たいです。

敵とぶつかったら炎を消す

fire.csにこれを追加します

1
2
3
4
5
6
    void OnTriggerEnter2D(Collider2D col)
    {
        if(col.gameObject.tag == "mob"){
            Destroy(gameObject);
        }
    }

これで敵にぶつかったらfireオブジェクトが消えるようになりました

敵とぶつかったら敵がダメージをくらいHPが0になったら敵が消える

mob_damage.csを作成して
(それにしてもPHPのネーミングルールとUnityのネーミングルールがごっちゃになってきた。。どこかで統一したい所ですね(汗))
playerとのダメージ処理を改造してmob用のダメージ処理をつくってみました。

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
using UnityEngine;
using System.Collections;

public class mob_damage : MonoBehaviour {

    public float hp = 30;
    public bool on_damage = false;
    private SpriteRenderer renderer;

    // Use this for initialization
    void Start () {
        renderer = gameObject.GetComponent<SpriteRenderer>();
    }

    // Update is called once per frame
    void Update () {
        if(on_damage){
            float level = Mathf.Abs(Mathf.Sin(Time.time * 10));
            renderer.color = new Color(1f,1f,1f,level);
        }
    }

    void OnDamageEffect(int damage)
    {
        if(!on_damage){
            // gotDamage
            hp = hp - damage;

            if(hp <= 0){
                Destroy(gameObject);
            }else{
                //changeFlg
                on_damage = true;
                StartCoroutine("WaitForDamage");
            }
        }
    }


    IEnumerator WaitForDamage()
    {
        yield return new WaitForSeconds(0.5f);

        on_damage = false;
        renderer.color = new Color(1f,1f,1f,1f);
    }
}

これをmobプレハブにアタッチします。
さぁ!エミュレートだ!!

スクショをとるのが大変かんじですがとれました!

f:id:raharu0425:20140115192551p:plain

いいですね!とりあえず3発当たると敵が消えるようにしておきました。てきが点滅してるあいだ0.5秒は無敵にしています。
今回で攻撃アクションを作るという目的は果たされたと思います。ながかった。。

感想

ここまでつくって来て大分Unity2Dの作成になれてきました。
入門編が終わり、そろそろ初級編と行ったところでしょうか?
次回は鬼門!?ジャンプ処理を作りたいと思います。重力操作があるから前にやったときは挫折したんですよね(汗)

参考記事

http://www.geocities.jp/gamekaisetsu/unity/company4.html