見出し画像

【Unity】3Dローグライクゲームの作り方〜Step9&10-19〜

前回の記事はこちら
前回は満腹度とそれの回復、投げた時のアイテム効果を実装しました。

アイテムが当たった時のエフェクト

まず、アイテムが当たった時のエフェクトをアセットストアから探してきます。筆者は以下を使用することにしました。

スクリーンショット 2020-05-19 17.22.02

「Cartoon FX Free」で検索すると出てきます。
インポートしたら、空のオブジェクトを作成、名前を「HitItemEffect」にします。その子オブジェクトとして、エフェクトを追加して下さい。
ループのチェックは外しておきましょう。
調節などをしてからHitItemEffectをプレハブ化します。
それではItemMovementスクリプトを開きましょう。このように変更します。

// スクリプトの最初に以下を追加
using UnityEngine;

// 以下のパラメーターを追加
private GameObject effect = null;

// 以下のメソッドを変更
private void HitActor(ActorParamsController tParam, GameObject actor)
{
   Item param = GetComponent<ItemParamsController>().parameter;
   if (actor == null) Message.Add(15, param.name);
   else
   {
       if (param.dmg > 0)
       {
           GameObject effectObj = Resources.Load<GameObject>("Prefabs/HitItemEffect");
           effect = Instantiate(effectObj, actor.transform);
           int str = tParam.parameter.str + param.dmg;
           actor.GetComponent<ActorParamsController>().Damaged(str);
       }
       else if (param.hp > 0)
       {
           GameObject effectObj = Resources.Load<GameObject>("Prefabs/RecoveryEffect");
           effect = Instantiate(effectObj, actor.transform);
           actor.GetComponent<ActorParamsController>().RecoveryHp(param.hp);
       }
       Message.Add(14, param.name);
   }
}

public bool Throwing(EDir d, ActorParamsController tParam)
{
   if (!isThrowing && effect == null)
   {
       SetThrowPosition(d);
       isThrowing = true;
   }
   if (!isThrowing && effect != null)
   {
       if (effect.GetComponentInChildren<ParticleSystem>().isStopped)
       {
           Destroy(effect);
           Destroy(gameObject);
           return true;
       }
       return false;
   }
   if (Moving() == EAct.MoveEnd)
   {
       Field field = GetComponentInParent<Field>();
       HitActor(tParam, field.GetExistActor(grid.x, grid.z));
       if (!gameObject.Equals(field.GetExistItem(grid.x, grid.z)))
           Destroy(gameObject);
       isThrowing = false;
       if (effect == null) return true;
   }
       
   return false;
}

テストしてみます。以下のように投げた時にエフェクトが表示されたら0Kです。

アイテムエフェクト2

エフェクト管理用クラスの作成

今はまだいいですが、これから先エフェクトが増えたら管理が大変になりそうです。なので、別に単発のエフェクト管理用のクラスを作成しようと思います。
という訳でEffectManagerスクリプトを作成しましょう。

using UnityEngine;

public class EffectManager : MonoBehaviour
{
   public enum EType
   {
       Recovery,
       HitItem
   };
   public GameObject recovery;
   public GameObject hitItem;

   private GameObject playingEffect;

   /**
   * 再生中かどうか
   */
   public bool IsPlaying()
   {
       if (playingEffect == null) return false;
       if (playingEffect.GetComponentInChildren<ParticleSystem>().isStopped)
       {
           Destroy(playingEffect);
           playingEffect = null;
           return false;
       }
       return true;
   }

   /**
   * 指定したエフェクトを再生する
   */
   public void Play(EType type, GameObject target)
   {
       if (playingEffect != null) return;
       switch (type)
       {
           case EType.Recovery:
               playingEffect = Instantiate<GameObject>(recovery, target.transform);
               break;
           case EType.HitItem:
               playingEffect = Instantiate<GameObject>(hitItem, target.transform);
               break;
       }
   }
}

それに伴い、ActorUseItemsクラスを修正します。

// 以下のパラメーターを削除
private GameObject effect = null;

// 以下のパラメーターを追加
private EffectManager effect;
private bool isActive = false;

// 以下のメソッドを追加
void Start()
{
   effect = GetComponentInParent<EffectManager>();
}

// 以下のメソッドを変更
private void Recovery(Item it)
{
   if (it.hp == 0 && it.food == 0)
   {
       Message.Add(18);
       return;
   }
   effect.Play(EffectManager.EType.Recovery, gameObject);
   if (it.hp > 0) param.RecoveryHp(it.hp);
   if (it.food > 0) param.RecoveryFood(it.food);
}

private bool UseEffect(Item it)
{
   if (isActive && !effect.IsPlaying())
   {
       isActive = false;
       return true;
   }
   if (isActive) return false;
   switch (it.type)
   {
       case EItemType.Food:
           Message.Add(5, param.actorName, it.name);
           Recovery(it);
           break;
       case EItemType.Portion:
           Message.Add(16, param.actorName, it.name);
           Recovery(it);
           break;
   }
   isActive = true;
   return false;
}

public bool Use(Item it)
{
   if (!isActive) inventory.Remove(it);
   return UseEffect(it);
}

public bool PickUpUse(Item it)
{
   if (!isActive)
   {
       GameObject item = GetComponentInParent<Field>().GetExistItem(move.grid.x, move.grid.z);
       if (item != null) Destroy(item);
   }
   return UseEffect(it);
}

後、ItemMovementクラスも変更します。

// 以下のパラメーターを削除
private GameObject effect = null;

// 以下のパラメーターを追加
private EffectManager effect;
private bool isPlayingEffect = false;

// 以下のメソッドを変更
private void HitActor(ActorParamsController tParam, GameObject actor)
{
   Item param = GetComponent<ItemParamsController>().parameter;
   if (actor == null) Message.Add(15, param.name);
   else
   {
       if (param.dmg > 0)
       {
           effect.Play(EffectManager.EType.HitItem, actor);
           int str = tParam.parameter.str + param.dmg;
           actor.GetComponent<ActorParamsController>().Damaged(str);
       }
       else if (param.hp > 0)
       {
           effect.Play(EffectManager.EType.Recovery, actor);
           actor.GetComponent<ActorParamsController>().RecoveryHp(param.hp);
       }
       Message.Add(14, param.name);
   }
}

public bool Throwing(EDir d, ActorParamsController tParam)
{
   if (effect == null) effect = GetComponentInParent<EffectManager>();
   if (!isThrowing && !effect.IsPlaying())
   {
       SetThrowPosition(d);
       isThrowing = true;
   }
   if (isPlayingEffect && !effect.IsPlaying())
   {
       Destroy(gameObject);
       isPlayingEffect = false;
       return true;
   }
   if (!effect.IsPlaying() && Moving() == EAct.MoveEnd)
   {
       Field field = GetComponentInParent<Field>();
       HitActor(tParam, field.GetExistActor(grid.x, grid.z));
       if (!gameObject.Equals(field.GetExistItem(grid.x, grid.z)))
           Destroy(gameObject);
       isThrowing = false;
       if (!(isPlayingEffect = effect.IsPlaying())) return true;
   }
   return false;
}

あまり見栄え的に変わった感じはありませんが、今後に期待しましょう!
FieldにEffectManagerスクリプトをアタッチして下さい。
あとはパラメーターの設定を忘れずに行っておきましょう。
テストしてみて、今まで通りちゃんとエフェクトが表示されたらOKです。

今回はいつにも増してぐだぐだ感がありましたが、長くなってしまったのでここまでということで。
次回は装備アイテムを投げて、当たった時の実装をしていきたいと思います。

この記事が気に入ったらサポートをしてみませんか?