kazumalab tech log

流行りとリラックマと嵐が大好きです。技術的ログ。

敵ロックオン機能をUnityで実装する <ゼルダの伝説シリーズ>

かずまです。

今回も引き続き、ゼル伝シリーズをやっていきます。


そういえば今回のゼルダの伝説は一応ストーリー全クリしました。
ただマップの開放とかいっぱいやることはありますね。

ネタバレっぽくなっちゃいますが、感動した!これだけ言っておきます!笑

気になる方はこちら!
ゼルダの伝説 ブレス オブ ザ ワイルド


テーマ

今回は画面内に入った敵を注目してLボタンでロックオンするところです。
ロックオンして、タイミングよくバク転か、サイドステップをするとラッシュ攻撃ができます。

これです。
ちなみに一定の範囲内に入った時に注目できるよって示すマークを出します。

考察

ロックオン(注目)で重要な点は

  • 注目できる敵の上になにか表示
  • 注目したらなにか表示(上とは違うものを)
  • 注目しているときは敵を見続ける
  • 画面外になったときは解除される

これぐらいです。

下準備

まずは重要な点でも言ったなにか表示の部分の準備です。
注目している場合の画像は、今回いいのがあったのでフリーを使います。

yajidesign.com
この末広がりのやじるしです。

[指し示すだけの三角]
f:id:kazumalab:20170402082026p:plain
白紙ですが、この上に有ります。

これをSpriteRendererで違和感のないサイズに変更し、名前を"Point"に変更し、Prefab化します。

f:id:kazumalab:20170402090702p:plain
サイズ的にはこんな感じ。

その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) {
                                // あとでEnemyAttentionメソッドを記載します
				enemy.Attention ();
			}
		}
	}

Enemyスクリプトに追記

次にEnemyは画面に入った、出た場合のタスクとして、そのEnemyManagerに自身を突っ込んでもらいます。
画面外は自分をリストから削除します。

画面に入った入ってないは

qiita.com

この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です!

結果

f:id:kazumalab:20170402181518g:plain

もっと派手なエフェクトほしいけどまた今度!
なんか雑になってきたやばい...。

追記

  • クラス図とか書こうと思う
  • オブジェクト指向プログラミング意識しよう
  • ちゃんと寝よう