敵ロックオン機能をUnityで実装する <ゼルダの伝説シリーズ>
かずまです。
今回も引き続き、ゼル伝シリーズをやっていきます。
そういえば今回のゼルダの伝説は一応ストーリー全クリしました。
ただマップの開放とかいっぱいやることはありますね。
ネタバレっぽくなっちゃいますが、感動した!これだけ言っておきます!笑
テーマ
今回は画面内に入った敵を注目してLボタンでロックオンするところです。
ロックオンして、タイミングよくバク転か、サイドステップをするとラッシュ攻撃ができます。
これです。
ちなみに一定の範囲内に入った時に注目できるよって示すマークを出します。
考察
ロックオン(注目)で重要な点は
- 注目できる敵の上になにか表示
- 注目したらなにか表示(上とは違うものを)
- 注目しているときは敵を見続ける
- 画面外になったときは解除される
これぐらいです。
下準備
まずは重要な点でも言ったなにか表示の部分の準備です。
注目している場合の画像は、今回いいのがあったのでフリーを使います。
yajidesign.com
この末広がりのやじるしです。
[指し示すだけの三角]
白紙ですが、この上に有ります。
これをSpriteRendererで違和感のないサイズに変更し、名前を"Point"に変更し、Prefab化します。
サイズ的にはこんな感じ。
そのPrefabに次のスクリプトをアタッチします。
これでPrefabにくっつけます。
この時、InspectorからSpriteをセットし忘れないように...。
EnemyManagerを作る
今回Enemyが画面に入ったらリストに追加、削除していきます。
そこから最短のEnemyを取り出したりすることができます。
これを作りました。
MonoBehaviourは継承しません。継承しちゃうとインスタンス生成できなくなりますかね。
次にEnemyManagerをPlayer.cs内でインスタンス生成します。
前回のPlayer.csを使い、変数とStart関数、新規メソッドを追加します。
ついでにXbox One ControllerのLBをLTriggerとしてUnityにセットしておきます。
// 変数 public EnemyManager EnemyMGR; // Start関数でインスタンス生成、コンストラクタとしてPlayerが必要なので自分をいれる private void Start () { EnemyMGR = new EnemyManager (this); CharactorCTL = GetComponent<CharacterControl> (); CameraCTL = GameObject.Find ("Main Camera").GetComponent<CameraControl> (); } // 新規メソッド追加 public void Locked () { if (Input.GetAxis ("LTrigger") > 0.9f) { Enemy enemy = EnemyMGR.getNearEnemy (); if (enemy != null) { // あとでEnemyにAttentionメソッドを記載します enemy.Attention (); } } }
Enemyスクリプトに追記
次にEnemyは画面に入った、出た場合のタスクとして、そのEnemyManagerに自身を突っ込んでもらいます。
画面外は自分をリストから削除します。
画面に入った入ってないは
このQiitaで完結に解説されています。
// 画面外にでた private void OnBecameInvisible () { player.EnemyMGR.DeleteEnemy (this); } // 画面内に入った private void OnBecameVisible () { player.EnemyMGR.AddEnemy (this); } private void OnWillRenderObject() { // あとで記載 }
EnemyはPlayerを常に見ている状態なのでPlayerのEnemyManagerにもアクセスできることになります。
これで画面に入ったりでたりというのが確認できます。
注目しているかしていないか、Player側に持っておくのではなくEnemy側で管理します。
Enemy.csに変数とメソッドをもう少し付け加えます。
private readonly float AttentionDistance = 4f; public bool isDrawingAttention = false; public void Attention () { player.transform.LookAt (transform.position); isDrawingAttention = true; } public void UnAttention () { isDrawingAttention = false; } private void OnWillRenderObject() { // あとで記載と書いていた場所 if (getDistance () < AttentionDistance) { transform.FindChild ("Point").GetComponent<SpriteRenderer> ().enabled = true; } else { transform.FindChild ("Point").GetComponent<SpriteRenderer> ().enabled = false; } }
あとはこれでEnemyの子どもとしてPointのPrefabをセットします。
isDrawAttentionがtrueのときは注目している画像になればOKです!
結果
もっと派手なエフェクトほしいけどまた今度!
なんか雑になってきたやばい...。
追記
- クラス図とか書こうと思う
- オブジェクト指向プログラミング意識しよう
- ちゃんと寝よう