Related Posts Plugin for WordPress, Blogger...

3-24 Finishing The AOE And Self Heal Particle Effect

本章要來做最後的技能效果美化啦,將會有絢麗的粒子特效跟技能音效,同時也會跟大家介紹下載位置跟匯入方式。首先先貼上下載的位址吧,若是有看過舊文章的人應該已經下載過了:

Unity Particle Pack
https://www.assetstore.unity3d.com/en/#!/content/73777

Fantasy SFX for Particle Distort Texture Effect Library
https://www.assetstore.unity3d.com/en/#!/content/42146

如果不懂技能系統的話,大家可以從本網誌的標籤觀看一系列相關的文章唷!
https://rpgcorecombat.blogspot.tw/search/label/Unity%20%E7%AF%84%E5%9C%8D%E6%94%BB%E6%93%8A%E6%8A%80%E8%83%BD

OK!接下來進入正題吧。首先,我先從Unity Particle Pack中選擇了BigExplosionEffect,拉入場景中調整一下大小跟位置,先看看這個效果是不是我想要的。

設定完成後,拉進Project視窗內變成Prefab,並取名為Power Attack L1 VFX。

點選Power Attack L1的設定,將Power Attack L1 VFX拉進Particle Prefab的參數中,Audio Clip我挑選了msfx_explosion_1_explode。

執行遊戲試玩看看吧!哇,煙硝瀰漫、塵土飛揚,這個爆炸效果做得真好。

火焰都從煙霧中彈射出來了,很漂亮的效果。另外,因為我調整了Power Attack的Script,讓粒子系統可以綁定在Enemy身上,使得效果更炫也更合理,最下面會再提供修改後的完整程式碼給大家。

再來是治癒技能要使用的效果,由於在Unity Particle Pack挑選不到我喜歡的特效,所以我上網找了個教學自行製作,大概只要花20分鐘左右就可以做好。
Unity 5 - Game Effects VFX - Healing Spell
https://www.youtube.com/watch?v=O8Qm8DQZv5A

滿推薦這個作者的教學,效果很炫,製作時間也不長。

製作好以後存成Prefab,我取名為Self Heal L1 VFX,然後Audio Clip選擇sfx_shield。

再來簡單介紹一下播放技能音效的部分有更改,改成AddComponent的方式,新增AudioSource播放音效,等音效播放完以後再刪除。原先舊的寫法會導致前一個音效還沒播放完畢,玩家施放下一個技能時音效立即就被蓋過去了。

完成,接下來補齊三個技能的完整程式碼,以及為了讓粒子系統綁定到Enemy身上,也稍稍修改了AbilityParams:
AreaEffectBehaviour.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Core;

namespace RPG.Character{
 public class AreaEffectBehaviour : MonoBehaviour, ISpecialAbility {

  AreaEffectConfig config;

  public void SetConfig(AreaEffectConfig config){
   this.config = config;
  }

  public void Use(AbilityParams useParams){
   DealRadiaDamage (useParams);
   PlayParticleEffect ();
   PlayEffectAudio ();
  }

  private void PlayEffectAudio(){
   // 生成新的音效Component
   AudioSource myAudioSource = gameObject.AddComponent();
   // 從config取得技能音效
   myAudioSource.clip = config.GetAudioClip ();
   // 播放技能音效
   myAudioSource.Play ();
   // 銷毀音效物件
   Destroy (myAudioSource, myAudioSource.clip.length);
  }

  private void PlayParticleEffect(){
   // 初始化粒子系統,綁定到Player身上
   GameObject particlePrefab = Instantiate(config.GetParticlePrefab(),transform.position ,Quaternion.identity,transform);
   // 取得粒子系統物件
   ParticleSystem myParticle = particlePrefab.GetComponent();
   // 啟動粒子系統
   myParticle.Play();
   // 播放完後自我銷毀
   Destroy(particlePrefab, myParticle.main.duration);
  }

  private void DealRadiaDamage(AbilityParams useParams){
   RaycastHit[] hits = Physics.SphereCastAll (
    transform.position,  // 以Player為中心點
    config.GetRadius (), // 掃描的球體半徑範圍
    Vector3.up,    // 掃描的方向不重要,因為我們發動的是Player為原點的範圍技
    config.GetRadius ()  // 掃描距離設定成跟掃描半徑一樣即可
   );

   foreach (RaycastHit hit in hits) {
    Enemy enemy = hit.collider.gameObject.GetComponent ();
    if (enemy != null) {
     float damageToDeal = useParams.baseDamage + config.GetDamageToEachTarget ();
     enemy.TakeDamage (damageToDeal);
    }
   }
  }

 }
}

PowerAttackBehaviour.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RPG.Character{
 public class PowerAttackBehaviour : MonoBehaviour, ISpecialAbility {

  PowerAttackConfig config;

  public void SetConfig(PowerAttackConfig config){
   this.config = config;
  }

  public void Use(AbilityParams useParams){
   DealDamage (useParams);
   PlayParticleEffect (useParams);
   PlayEffectAudio ();
  }

  private void PlayEffectAudio(){
   // 生成新的音效Component
   AudioSource myAudioSource = gameObject.AddComponent();
   // 從config取得技能音效
   myAudioSource.clip = config.GetAudioClip ();
   // 播放技能音效
   myAudioSource.Play ();
   // 銷毀音效物件
   Destroy (myAudioSource, myAudioSource.clip.length);
  }

  private void PlayParticleEffect(AbilityParams useParams){
   // 初始化粒子系統,綁定到Enemy身上
   GameObject particlePrefab = Instantiate(config.GetParticlePrefab(),
    useParams.target.transform.position,
    Quaternion.identity,
    useParams.target.transform);
   // 取得粒子系統物件
   ParticleSystem myParticle = particlePrefab.GetComponent();
   // 啟動粒子系統
   myParticle.Play();
   // 播放完後自我銷毀
   Destroy(particlePrefab, myParticle.main.duration);
  }

  private void DealDamage(AbilityParams useParams){
   float damageToDeal = config.GetExtraDamage () + useParams.baseDamage;
   useParams.target.TakeDamage (damageToDeal);
  }

 }
}

SelfHealBehaviour.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Core;

namespace RPG.Character{
 public class SelfHealBehaviour : MonoBehaviour, ISpecialAbility {

  SelfHealConfig config;
  Player player;

  void Start(){
   player = GetComponent ();
  }

  public void SetConfig(SelfHealConfig config){
   this.config = config;
  }

  public void Use(AbilityParams useParams){
   player.Heal (config.GetExtraHealth ());
   PlayParticleEffect ();
   PlayEffectAudio ();
  }

  private void PlayEffectAudio(){
   // 生成新的音效Component
   AudioSource myAudioSource = gameObject.AddComponent();
   // 從config取得技能音效
   myAudioSource.clip = config.GetAudioClip ();
   // 播放技能音效
   myAudioSource.Play ();
   // 銷毀音效物件
   Destroy (myAudioSource, myAudioSource.clip.length);
  }

  private void PlayParticleEffect(){
   // 初始化粒子系統,綁定到Player身上
   GameObject particlePrefab = Instantiate(config.GetParticlePrefab(),transform.position ,Quaternion.identity,transform);
   // 取得粒子系統物件
   ParticleSystem myParticle = particlePrefab.GetComponent();
   // 啟動粒子系統
   myParticle.Play();
   // 播放完後自我銷毀
   Destroy(particlePrefab, myParticle.main.duration);
  }
 }
}


SpecialAbilityConfig.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Core;

namespace RPG.Character{
 public struct AbilityParams{
  public Enemy target;
  public float baseDamage;

  public AbilityParams(Enemy target, float baseDamage){
   this.target = target;
   this.baseDamage = baseDamage;
  }
 }

 public abstract class SpecialAbilityConfig : ScriptableObject {
  [Header("Special Ability General")]
  [SerializeField] float energyCost = 10f;
  [SerializeField] GameObject particlePrefab = null;
  [SerializeField] AudioClip audioClip = null;

  abstract public ISpecialAbility AddComponent (GameObject gameObjectAttachTo);

  public float GetEnergyCost(){
   return energyCost;
  }

  public GameObject GetParticlePrefab(){
   return particlePrefab;
  }

  public AudioClip GetAudioClip(){
   return audioClip;
  }
 }
}


留言