第5回 Unity開発記録 敵の移動方法を見直す

f:id:moshi1121:20170306144202p:plain

以前に敵の動きをAnimationを使用して作成しましたが、いろいろと不都合があるのでは?と思ったので、見直して作り直すことにしました。

不都合一覧

  • 弾を発射するタイミングが計りにくい
  • 移動場所の指定がしにくい

などです。特に問題なのが、移動場所の指定がしにくいということ。敵ごとに移動場所を指定してあげたいので、一つ一つAnimationをいじるのはちょっと面倒かなと。

そこで、コルーチンを使用することにしました。

参考にしたサイトさまはこちら

izmiz.hateblo.jp

tsubakit1.hateblo.jp

コルーチンは、時間によって挙動を変えることができます。2秒経過したら弾を撃つなどです。

 

今回したいのは、

①開始位置から中継位置まで移動

②中継位置で弾の発射

③弾を発射したら目的地まで移動

以上の動きを実装してみます。

 

最初に、敵キャラクターの動きを制御するクラスを作っておきます。

private IEnumerator move1(Vector3 first_pos,Vector3 second_pos,Vector3 last_pos) {

 

    }
}

 コルーチンを使用するためには、戻り値にIEnumeratorを指定します。

引数には、first_pos=開始位置 second_pos=中継位置 last_pos=目的地としました。

開始位置から中継位置まで移動し、中継位置に到達したら弾を発射させます。つまり、中継位置に到達したかを判断しなければなりません。下のコードを追加しました。

float progress_rate = 0f;

while(Vector3.Distance(transform.position,second_pos) > 0.1f)

{
transform.position = Vector3.Lerp(first_pos, second_pos, progress_rate += Time.deltaTime);
yield return null;
}

 ちょっと見にくくて申し訳ないです。

移動にはVector3.Lerpを使用しました。第1引数から第2引数まで移動を、第3引数の0~1までの移動量で制御してくれます。

第1引数の位置が0%、第2引数の位置が100%で、2点を結んだ移動の割合を第3引数で指定してあげる。と言ったほうがわかりやすいでしょうか?

 

この第三引数は徐々に値を大きくしてあげなくてはいけないので、float progress_rate = 0f;で値を格納しておいて、Time.deltaTimeで徐々に値を増やしていくことにしました。

 

yield return null;は、次のフレームまで動くな。という指示です。

 

肝心の、中継位置に到達したかの判断は、while(Vector3.Distance(transform.position,second_pos) > 0.1f)で行っています。

Vector3.Distanceは第1引数と第2引数の距離を返してくれます。

第一引数には現在位置を、第2引数には中継点を指定します。すると、中継点までの残距離が出ます。

中継点までの残距離が0.1以上の間はループ。という処理を行います。

 

上記を部分のまとめると、

①現在位置と中継位置の距離を評価。距離が0.1以上ならループへ

②位置をLerpでTime.deltaTimeの分接近させる

③yield return nullで次のフレームまで待つ

④次のフレームが来たら①へ戻る

現在位置と中継位置の距離が0.1未満ならループを脱出

 

という流れになります。このつぎには

yield return new WaitForSeconds(0.3f);
StartCoroutine(GenerateBulletLoop(1));

 というコードを追加しました。WaitForSeconds(t)はt秒待て。という処理になります。

GenerateBulletLoop(1)は自作関数(?)です。弾を撃たせています。

移動が終わって、0.3秒待ったら弾を撃てという処理です。

 

progress_rate = 0;
while(Vector3.Distance(transform.position,last_pos) > 0.1f)

{
transform.position = Vector3.Lerp(second_pos, last_pos, progress_rate += Time.deltaTime);
yield return null;
}

その次に、progress_rate = 0;で移動量を初期化してから先ほどと同じ処理をしました。

同じ処理=関数にできそうですね。今後の検討材料です。

 

とりあえずここで終了です。最後に、実際の動きを確認したいと思います。

 


敵の移動方法の修正

弾が撃ちっぱなしですが、悪くないのではないでしょうか。シューティングゲームの欠片が見えた気がします。