前回に引き続きキャラクターに関する記事ですが。今回はスクリプトについて見ていきたいと思います。
コンテンツ
登場している敵について
キャラ紹介は以下をご覧ください
今回は挙動ベースで紹介します。
- Walker
- 普段は直進している
- 接近したらこちらに突撃
- Wing
- 普段は直進している
- 接近したらこちらに突撃(こちらは3次元的に移動する)
- Gunner
- 接近するまで何もしない
- 接近してきたらこちらに向けて球を発射する
- Tank
- 接近するまで何もしない
- 接近してきたらこちらに向けてレーザーを発射する
- 死亡時の爆発エフェクトが特別
設計について
5年前のスクリプトを見ると各自で独立した処理をしていましたが今回はしっかり継承を生かして
設計していきたいと思います。
クラス図を簡単に書くとこうなります。
最低限の敵としての定義と挙動を持ったスクリプト「Enemy」を実装しそれを継承して各々の処理を実装していくことで似たような処理を省きつつ様々な挙動を実現することができます。
例えば、新しく敵「暗黒騎士」を実装するときは「Enemy」を継承することで、共通処理の実装を省き各々の処理の実装に専念できるようになります。
実際の実装
設計を実現させた「Enemy」は以下のようになります。
using UnityEngine;
using System.Collections;
using System;
public abstract class Enemy : MonoBehaviour
{
// ----------------------------------------------
// 設定項目
[SerializeField]
private Status m_status = null;
[SerializeField]
private GameObject m_hitEffect;
// ----------------------------------------------
// 内部メンバ変数
// プレイヤー
private Player m_player = null;
// 死んだとき
private Action m_onDestroyAction = null;
// ----------------------------------------------
// アクセサ
public Status Status
{
get
{
return m_status;
}
}
public GameObject HitEffect
{
get
{
return m_hitEffect;
}
}
// ----------------------------------------------
// 各自で実装してください
/// <summary>初期化</summary>
protected abstract void DoInit();
/// <summary>更新</summary>
protected abstract void DoUpdate();
/// <summary>何かオブジェクトにヒットした</summary>
/// <param name="collision">ヒットしたオブジェクト</param>
protected abstract void DoOnCollisionEnter(Collision collision);
/// <summary>
/// 初期化
/// </summary>
/// <param name="player">プレイヤー</param>
/// <param name="onDestroyAction">死亡時に呼ぶ</param>
public void Init(Player player, Action onDestroyAction)
{
m_player = player;
m_onDestroyAction = onDestroyAction;
DoInit();
}
// Update is called once per frame
void Update()
{
if(m_status.HP <= 0)
{
Destroy(gameObject, 0);
Debug.Log(gameObject.name + " is destroy");
GameObject obj = Instantiate(m_hitEffect, transform.position, Quaternion.identity);
m_onDestroyAction?.Invoke();
GameMainScore.NowScore += m_status.Point;
}
if(transform.position.z > 8)
{
Destroy(gameObject, 0f);
}
DoUpdate();
}
void OnCollisionEnter(Collision collision)
{
DoOnCollisionEnter(collision);
}
}
こうすることで
新しく仮に「暗黒騎士」を実装するとして
以下の3つ処理を実装することで最低限実現可能になります。
public override class DarkKnight: Enemy
{
/// <summary>初期化</summary>
protected override void DoInit()
{
}
/// <summary>更新</summary>
protected abstract void DoUpdate()
{
}
/// <summary>何かオブジェクトにヒットした</summary>
/// <param name="collision">ヒットしたオブジェクト</param>
protected abstract void DoOnCollisionEnter(Collision collision)
{
}
}
まとめ
キャラクターのスクリプトはキャラクターの追加にかかわる非常な重要なものですが、
実装時間と実装自体の短縮もクオリティに影響してくるので非常に重要な設計となります。
設計自体が非常に時間のかかる作業ですが後の作業にかかわることなので設計図は書かなくてもよいですが、想像はできるようにしておきたいです。
コメントを残す