You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
842 lines
23 KiB
842 lines
23 KiB
using Spine.Unity; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using UnityEngine; |
|
using UnityEngine.Events; |
|
using UnityEngine.Serialization; |
|
|
|
public enum IFF { Our, Enemy } |
|
public enum DamageType { None, Fixed, Rate, RateHP, Bomb } |
|
|
|
public class Character : MonoBehaviour |
|
{ |
|
public enum State { HP_Change, AH_Change, Mana_Change, Inventory, EquipItem, Status, ActiveItem } |
|
public EventConnect ec = new EventConnect(); |
|
|
|
[HideInInspector] |
|
public MapManager map; |
|
|
|
public string NAME = ""; |
|
CharacterData data; |
|
[Space(10)] |
|
public IFF iff = IFF.Our; |
|
public bool ALL_HIT = false; |
|
public Collider hitBox; |
|
|
|
[HideInInspector] |
|
public int layerEnemy = 0; |
|
private void Awake() |
|
{ |
|
map = (MapManager)FindObjectOfType(typeof(MapManager)); |
|
|
|
skill = GetComponent<Skill>(); |
|
motion = GetComponent<Motion>(); |
|
statusEffect = GetComponent<StatusEffect>(); |
|
} |
|
private void Start() |
|
{ |
|
tag = $"{iff}"; |
|
//gameObject.layer = LayerMask.NameToLayer($"{(iff)}"); |
|
|
|
layerEnemy = ALL_HIT ? LayerMask.NameToLayer($"HitAll") : LayerMask.NameToLayer($"Hit{(iff == IFF.Our ? IFF.Enemy : IFF.Our)}"); |
|
hitBox.gameObject.layer = LayerMask.NameToLayer($"{(iff)}"); |
|
gameObject.tag = $"{(iff)}"; |
|
|
|
if (matHP30Down != null) |
|
{ |
|
matHP30Down_Copy = new Material(matHP30Down); |
|
matHP30Down_Copy.SetTexture("_MainTex", mainTexture); |
|
scvHP30Down.Init(matHP30Down_Copy); |
|
} |
|
|
|
matHit_Copy = new Material(matHit); |
|
matHit_Copy.SetTexture("_MainTex", mainTexture); |
|
|
|
if (matHitResist != null) |
|
{ |
|
matHitResist_Copy = new Material(matHitResist); |
|
matHitResist_Copy.SetTexture("_MainTex", mainTexture); |
|
} |
|
|
|
matHide_Copy = new Material(matHide); |
|
matHide_Copy.SetTexture("_MainTex", mainTexture); |
|
scvHide.Init(matHide_Copy); |
|
} |
|
|
|
Collider col; |
|
void OnCollider(bool ON) |
|
{ |
|
if (col == null) |
|
col = GetComponent<Collider>(); |
|
|
|
col.enabled = ON; |
|
} |
|
/// <summary> |
|
/// 캐릭터의 초기화를 진행합니다 |
|
/// </summary> |
|
/// <param name="HP"></param> |
|
/// <param name="HP_Max"></param> |
|
public void OnInitialized(int HP, int HP_Max) |
|
{ |
|
if(HP == 0) |
|
{ |
|
if (data == null) |
|
data = DataManager.Instance.dataMonster.DataGet(NAME); |
|
|
|
HP = HP_Max = data.HP; |
|
|
|
ATK = data.ATK; |
|
DLAATK = data.DLA_ATK; |
|
|
|
SPDMOVE = data.SPD_MOVE; |
|
motion.RunMotionTimeScaleChanged(data.MOVE_TIME_SCALE); |
|
} |
|
|
|
statusEffect.OnInitialized();//생성했을때 상태이상 초기화 |
|
|
|
this.HP_Max = HP_Max; |
|
ec.Invoke((int)State.HP_Change, this.HP = HP); |
|
|
|
OnCollider(true); |
|
Material_Restore(); |
|
|
|
OnDefense = null; |
|
hitBox.gameObject.SetActive(true); |
|
|
|
Show_Start(); |
|
} |
|
|
|
//public void ProjectileCreate(Projectile projectile, Vector3 dir) |
|
//{ |
|
// if (projectile != null) |
|
// { |
|
// projectile.spdMovePer = SPDATK_PER; |
|
// projectile.OnInitialized(this, layerEnemy, dir, RANGE); |
|
// } |
|
//} |
|
|
|
[Space(10)] |
|
public int ATK = 1; |
|
/// <summary> |
|
/// 캐릭터의 공격력이 변경 되어 이를 적용합니다. |
|
/// </summary> |
|
/// <param name="value"></param> |
|
/// <param name="ADD"></param> |
|
public void ATKChanged(int value, bool ADD = true) |
|
{ |
|
if (ADD) |
|
ATK += value; |
|
else |
|
ATK = value; |
|
|
|
ec.Invoke((int)Character.State.Status, null); |
|
} |
|
public float ATK_PER = 1f; |
|
/// <summary> |
|
/// 캐릭터의 공경력 % 가 변경 되어 이를 적용합니다. |
|
/// </summary> |
|
/// <param name="value"></param> |
|
/// <param name="ADD"></param> |
|
public void ATKRateChanged(float value, bool ADD = true) |
|
{ |
|
if (ADD) |
|
ATK_PER += value; |
|
else |
|
ATK_PER = value; |
|
|
|
ec.Invoke((int)Character.State.Status, null); |
|
} |
|
/// <summary> |
|
/// 현재 데미지를 계산합니다. |
|
/// </summary> |
|
/// <returns></returns> |
|
public int CalculateATK() |
|
{ |
|
return (int)(ATK * ATK_PER); |
|
} |
|
|
|
[Space(10)] |
|
public float SPDATK_PER = 1f; |
|
[System.Serializable] |
|
public class SpeedAttackEvent : UnityEvent<float> { } |
|
[FormerlySerializedAs("onSpeedAttacked")] |
|
[SerializeField] |
|
[Space(10)] |
|
private SpeedAttackEvent onSpeedAttacked = new SpeedAttackEvent(); |
|
/// <summary> |
|
/// 공격 모션의 속도가 변경 되어 이를 적용합니다. |
|
/// </summary> |
|
/// <param name="value"></param> |
|
/// <param name="ADD"></param> |
|
public void SpeedAttackChanged(float value, bool ADD = true) |
|
{ |
|
if (ADD) |
|
SPDATK_PER += value; |
|
else |
|
SPDATK_PER = value; |
|
|
|
onSpeedAttacked.Invoke(SPDATK_PER); |
|
|
|
ec.Invoke((int)Character.State.Status, null); |
|
} |
|
|
|
[Space(10)] |
|
public float DLAATK = 0; |
|
public float DLAATK_PER = 1f; |
|
public float DLAATK_MIN = 0.2f; |
|
//[System.Serializable] |
|
//public class DelayAttackEvent : UnityEvent<float, bool> { } |
|
//[FormerlySerializedAs("onDelayAttacked")] |
|
//[SerializeField] |
|
//[Space(10)] |
|
//private DelayAttackEvent onDelayAttacked = new DelayAttackEvent(); |
|
/// <summary> |
|
/// 공격 후 딜레이가 변경되어 이를 적용합니다. |
|
/// </summary> |
|
/// <param name="add"></param> |
|
/// <param name="RATE"></param> |
|
public void DelayAttackChanged(float add, bool RATE = true) |
|
{ |
|
if (RATE) |
|
{ |
|
DLAATK_PER += add; |
|
//onDelayAttacked.Invoke(DLAATK_PER, RATE); |
|
} |
|
else |
|
{ |
|
DLAATK = add; |
|
//onDelayAttacked.Invoke(DLAATK, RATE); |
|
} |
|
|
|
//ec.Invoke((int)Character.State.Status, null); |
|
} |
|
/// <summary> |
|
/// 현재 후 딜레이를 계산합니다. |
|
/// </summary> |
|
/// <returns></returns> |
|
public float CalculateAttackDelay() |
|
{ |
|
float apply = DLAATK * DLAATK_PER; |
|
apply = apply < DLAATK_MIN ? DLAATK_MIN : apply; |
|
return apply; |
|
} |
|
|
|
[Space(10)] |
|
public float RANGE = 0; |
|
//[System.Serializable] |
|
//public class RangeEvent : UnityEvent<float, bool> { } |
|
//[FormerlySerializedAs("onRangeed")] |
|
//[SerializeField] |
|
//[Space(10)] |
|
//private RangeEvent onRangeed = new RangeEvent(); |
|
/// <summary> |
|
/// 사거리가 변경 되어 이를 적용합니다. |
|
/// </summary> |
|
/// <param name="add"></param> |
|
/// <param name="RATE"></param> |
|
public void RangeChanged(float add, bool RATE) |
|
{ |
|
if (RATE) |
|
{ |
|
RANGE += add; |
|
//onRangeed.Invoke(DLAATK_PER, RATE); |
|
} |
|
else |
|
{ |
|
RANGE = add; |
|
//onRangeed.Invoke(DLAATK, RATE); |
|
} |
|
|
|
//ec.Invoke((int)Character.State.Status, null); |
|
} |
|
|
|
[Space(10)] |
|
public float SPDMOVE = 40;//기본 이동 속도, 캐릭터 마다 다름 |
|
public float SPDMOVE_PER = 1f; |
|
[System.Serializable] |
|
public class SpeedMoveEvent : UnityEvent<float> { } |
|
[FormerlySerializedAs("onSpeedMoveed")] |
|
[SerializeField] |
|
[Space(10)] |
|
private SpeedMoveEvent onSpeedMoveed = new SpeedMoveEvent(); |
|
/// <summary> |
|
/// 이동 속도가 변경되어 이를 적용합니다. |
|
/// </summary> |
|
/// <param name="add"></param> |
|
public void SpeedMoveChanged(float add) |
|
{ |
|
SPDMOVE_PER += add; |
|
onSpeedMoveed.Invoke(SPDMOVE_PER); |
|
|
|
ec.Invoke((int)Character.State.Status, null); |
|
} |
|
/// <summary> |
|
/// 현재 이동속도를 계산합니다. |
|
/// </summary> |
|
/// <returns></returns> |
|
public float CalculateMoveSpeed() |
|
{ |
|
float spdMoveApply = SPDMOVE * SPDMOVE_PER; |
|
return spdMoveApply < 60 ? spdMoveApply : 60; |
|
} |
|
|
|
int LIFE_MAX = 20; |
|
public bool LifeMaxCheck() |
|
{ |
|
return HP_Max + AH <= LIFE_MAX; |
|
} |
|
[Space(10)] |
|
public int HP = 3; |
|
public bool DieCheck() |
|
{ |
|
return HP < 1; |
|
} |
|
public int HP_Max = 4; |
|
/// <summary> |
|
/// HP 에 데미지를 적용합니다. |
|
/// </summary> |
|
/// <param name="Damage"></param> |
|
public void CalculateHP(int Damage) |
|
{ |
|
if (0 < AH) |
|
{ |
|
AH -= Damage; |
|
Damage = AH < 0 ? -AH : 0; |
|
} |
|
|
|
HP -= Damage; |
|
} |
|
/// <summary> |
|
/// HP 가 회복 가능한 상태인지 확인합니다. |
|
/// </summary> |
|
/// <param name="value"></param> |
|
/// <returns></returns> |
|
public bool RestoreCheck(int value) |
|
{ |
|
return HP < HP_Max; |
|
} |
|
/// <summary> |
|
/// HP 를 회복합니다. |
|
/// </summary> |
|
/// <param name="value"></param> |
|
/// <returns></returns> |
|
public bool Restore(int value) |
|
{ |
|
if (HP < HP_Max) |
|
{ |
|
HP += value; |
|
HP = HP_Max < HP ? HP_Max : HP; |
|
|
|
ec.Invoke((int)State.HP_Change, HP); |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
/// <summary> |
|
/// HP 를 최대 HP 의 % 로 회복합니다. |
|
/// </summary> |
|
/// <param name="value"></param> |
|
/// <returns></returns> |
|
public bool Restore_MaxRate(float value) |
|
{ |
|
HP += (int)(HP_Max * value); |
|
HP = HP_Max < HP ? HP_Max : HP; |
|
|
|
Material_Restore(); |
|
|
|
ec.Invoke((int)State.HP_Change, HP); |
|
|
|
return true; |
|
} |
|
|
|
private void OnDisable() |
|
{ |
|
//scvHide.isPlay = false; |
|
scvHide.Stop(); |
|
} |
|
|
|
public int AH = 0; |
|
/// <summary> |
|
/// 아머하트가 변경되어 이를 적용합니다. |
|
/// </summary> |
|
/// <param name="value"></param> |
|
public void OnChanged_ArmorHeart(int value) |
|
{ |
|
AH = value; |
|
|
|
ec.Invoke((int)State.HP_Change, 0); |
|
} |
|
/// <summary> |
|
/// 아머하트가 회복 가능한지 확인합니다. |
|
/// </summary> |
|
/// <param name="add"></param> |
|
/// <returns></returns> |
|
public bool ArmorHeartCheck(int add) |
|
{ |
|
int MAX = LIFE_MAX - HP_Max; |
|
return AH + add <= MAX; |
|
} |
|
/// <summary> |
|
/// 아머하트를 회복합니다. |
|
/// </summary> |
|
/// <param name="add"></param> |
|
/// <returns></returns> |
|
public bool OnAdded_ArmorHeart(int add) |
|
{ |
|
int MAX = LIFE_MAX - HP_Max; |
|
if (AH + add <= MAX) |
|
{ |
|
AH = AH + add; |
|
ec.Invoke((int)State.HP_Change, HP); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public int MANA = 0; |
|
public int MANA_MAX = 0; |
|
/// <summary> |
|
/// 마나 회복 가능한지 확인합니다. |
|
/// </summary> |
|
/// <returns></returns> |
|
public bool ManaCheck() |
|
{ |
|
return MANA < MANA_MAX; |
|
} |
|
/// <summary> |
|
/// 마나를 회복 혹은 사용 합니다. |
|
/// </summary> |
|
/// <param name="add"></param> |
|
/// <returns></returns> |
|
public bool OnAdded_Mana(int add) |
|
{ |
|
if (MANA + add <= MANA_MAX) |
|
{ |
|
MANA += add; |
|
MANA = MANA_MAX < MANA ? MANA_MAX : MANA; |
|
ec.Invoke((int)State.Mana_Change, MANA); |
|
|
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public System.Action<Character, Vector3> OnDie;//Character -> 때린 캐릭터 |
|
public System.Action<Character, Vector3, float, bool, System.Action> OnHit;//Character -> 죽은 캐릭터 |
|
public System.Action<Character> OnDefense; |
|
public System.Action<Character> OnResurrection; |
|
/// <summary> |
|
/// 공격을 받았으며 이를 처리합니다. |
|
/// HitBox.cs -> OnDamaged 에서 호출 |
|
/// </summary> |
|
/// <param name="data"></param> |
|
public void Damaged(object data) |
|
{ |
|
if (NO_DAMAGE) |
|
return; |
|
|
|
HitCheck hitCheck = (HitCheck)data; |
|
//if (hitCheck.owner == this && hitCheck.damageType != DamageType.Bomb) |
|
// return; |
|
|
|
if (OnDefense != null) |
|
{ |
|
Debug.LogWarning($"{name} 가 {((HitCheck)data).owner.name} 의 공격을 방어"); |
|
|
|
System.Action<Character> OnDefenseTmp = OnDefense; |
|
OnDefense = null; |
|
|
|
OnDefenseTmp(((HitCheck)data).owner); |
|
|
|
return; |
|
} |
|
|
|
//회피 스킬이 있는 경우, 회피율 확인 |
|
if (skill.Active("Hit", "Flee") != null) |
|
{ |
|
Debug.LogWarning($"{name} 가 {hitCheck.owner.name} 의 공격을 회피"); |
|
} |
|
else |
|
{ |
|
Damaged_Process(hitCheck); |
|
} |
|
} |
|
[Space(10)] |
|
public SoundPlayer spHit; |
|
public SoundPlayer spDie; |
|
/// <summary> |
|
/// 캐릭터가 받은 데미지를 적용합니다. |
|
/// </summary> |
|
/// <param name="attacker">공격한 캐릭터</param> |
|
void Damaged_Process(HitCheck attacker) |
|
{ |
|
if (spHit != null) |
|
SoundManager.Instance.EffectPlay(spHit.gameObject); |
|
|
|
Character owner = attacker.owner; |
|
|
|
int damage = 0; |
|
switch(attacker.damageType) |
|
{ |
|
case DamageType.None: |
|
damage = owner.CalculateATK(); |
|
break; |
|
case DamageType.Fixed://고정 데미지 |
|
damage = (int)attacker.damageValue; |
|
break; |
|
case DamageType.Rate://배율 데미지 |
|
damage = (int)(owner.CalculateATK() * attacker.damageValue); |
|
break; |
|
case DamageType.RateHP://HP 비율 |
|
{ |
|
if (iff == IFF.Enemy) |
|
damage = (int)(HP * attacker.damageValue); |
|
else if (iff == IFF.Our) |
|
damage = 1;//플레이어는 HP 방식이 다름 |
|
} |
|
break; |
|
case DamageType.Bomb://폭탄 데미지 |
|
{ |
|
if (iff == IFF.Enemy) |
|
damage = (int)attacker.damageValue; |
|
else if (iff == IFF.Our) |
|
damage = 1;//플레이어는 HP 방식이 다름 |
|
} |
|
break; |
|
} |
|
|
|
Damage_Added(ref damage); |
|
|
|
//if (iff == owner.iff) |
|
//{ |
|
// if (iff == IFF.Enemy) |
|
// damage = 150; |
|
// else if (iff == IFF.Our) |
|
// damage = 1;//플레이어는 HP 방식이 다름 |
|
//} |
|
|
|
Vector3 dir = -(attacker.transform.position - transform.position).normalized; |
|
|
|
Damage_Apply(damage, owner, dir, 0, false, () => |
|
{ |
|
List<SkillData> list = owner.skill.SkillList_Trigger("HitEnd"); |
|
|
|
for (int i = 0; i < list.Count; i++) |
|
{ |
|
if (list[i].Activate("HitEnd")) |
|
{ |
|
switch (list[i].work) |
|
{ |
|
case "StatusEffect": |
|
{ |
|
statusEffect.Add(list[i]); |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
}); |
|
} |
|
void Damage_Added(ref int damage) |
|
{ |
|
float mag = 1; |
|
|
|
StatusEffect.Data data = statusEffect.Check("Freeze");//상태이상:빙결 효과 걸린 상태에서 맞게되면 추가 데미지 |
|
if (data != null) |
|
mag += data.skill.value; |
|
|
|
//Debug.LogWarning($"추가데미지 : {damage} * {mag}"); |
|
|
|
damage = (int)(damage * mag); |
|
|
|
//Debug.LogWarning($"최종데미지 : {damage}"); |
|
} |
|
public void Damage_Apply(int damage, Character attacker, Vector3 knockBackDir, float knockBackAddRate, bool MOTION_FORCE, System.Action OnEnd) |
|
{ |
|
CalculateHP(damage);//데미지 적용 |
|
ec.Invoke((int)State.HP_Change, 0); |
|
|
|
if (DieCheck()) |
|
{ |
|
NO_DAMAGE = true; |
|
hitBox.gameObject.SetActive(false); |
|
OnLocked(true);//죽었음 행동 정지 |
|
statusEffect.OnInitialized();//죽었을 경우, 상태이상 초기화 |
|
|
|
bool SKILL = skill.Active("Die", null, active => |
|
{ |
|
switch (active.work) |
|
{ |
|
case "Resurrection"://몬스터 부활 |
|
{ |
|
motion.isSkill = true; |
|
Restore_MaxRate(active.value); |
|
|
|
motion.typeBefore = Motion.Type.AttackEnd; |
|
motion.Play_Force(active.motion2, () => |
|
{ |
|
OnCollider(true); |
|
|
|
motion.Play(Motion.Type.Idle, true); |
|
Invoke("Resurrection", 0.5f); |
|
}); |
|
} |
|
break; |
|
} |
|
}); |
|
|
|
//캐릭터 죽음 |
|
if (OnDie != null && !SKILL) |
|
{ |
|
if (spDie != null) |
|
SoundManager.Instance.EffectPlay(spDie.gameObject); |
|
|
|
OnCollider(false); |
|
OnDie(this, Vector3.zero); |
|
} |
|
} |
|
else |
|
{ |
|
Hit_Start(durationHit);//히트 이팩트 실행 |
|
if (OnHit != null) |
|
OnHit(attacker, knockBackDir, knockBackAddRate, false, () => |
|
{ |
|
if (OnEnd != null) |
|
OnEnd(); |
|
}); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 스킬 등에 의해 부활했을 경우 초기화를 진행합니다 |
|
/// </summary> |
|
public void Resurrection() |
|
{ |
|
NO_DAMAGE = false; |
|
motion.isSkill = false; |
|
|
|
OnDefense = null; |
|
hitBox.gameObject.SetActive(true); |
|
|
|
gameObject.SetActive(true); |
|
|
|
OnLocked(false); |
|
|
|
OnResurrection(this); |
|
} |
|
|
|
[Space(10)] |
|
public Motion motion; |
|
[Space(10)] |
|
public Skill skill; |
|
[Space(10)] |
|
public StatusEffect statusEffect; |
|
[Space(5)] |
|
public bool STUN = false; |
|
|
|
[Space(10)] |
|
public List<DropItemData> drops; |
|
void DropInitialized() |
|
{ |
|
for (int i = 0; i < drops.Count; i++) |
|
drops[i].Get(); |
|
} |
|
|
|
[System.Serializable] |
|
public class LockEvent : UnityEvent<bool> { } |
|
[FormerlySerializedAs("onLocked")] |
|
[SerializeField] |
|
[Space(10)] |
|
private LockEvent onLocked = new LockEvent(); |
|
/// <summary> |
|
/// 캐릭터의 행동을 제한 합니다. |
|
/// </summary> |
|
/// <param name="LOCK"></param> |
|
public void OnLocked(bool LOCK) |
|
{ |
|
onLocked.Invoke(LOCK); |
|
} |
|
|
|
[System.Serializable] |
|
public class WarpEvent : UnityEvent<Vector3> { } |
|
[FormerlySerializedAs("onWarp")] |
|
[SerializeField] |
|
[Space(10)] |
|
private WarpEvent onWarp = new WarpEvent(); |
|
/// <summary> |
|
/// 캐릭터를 해당 위치로 이동시킵니다. |
|
/// </summary> |
|
/// <param name="pos"></param> |
|
public void OnWarp(Vector3 pos) |
|
{ |
|
onWarp.Invoke(pos); |
|
} |
|
|
|
/// <summary> |
|
/// 아이템을 습득했으므로 습득모션을 재생합니다. |
|
/// </summary> |
|
/// <param name="dropItem"></param> |
|
/// <param name="OnEvent"></param> |
|
public void OnGain(GameObject dropItem, System.Action OnEvent) |
|
{ |
|
OnLocked(NO_DAMAGE = true); |
|
|
|
motion.Play(Motion.Type.AttackEnd); |
|
motion.Play(Motion.Type.Get, true, () => |
|
{ |
|
OnLocked(NO_DAMAGE = false); |
|
}, ev => |
|
{ |
|
OnEvent(); |
|
}, true); |
|
} |
|
|
|
[Space(10)] |
|
public SkeletonAnimation skeletonAnimation; |
|
public Texture mainTexture; |
|
public Material matOrigin; |
|
|
|
[Space(5)] |
|
public bool USE_HP30DOWN = true; |
|
public float hpDownRate = 0.2f; |
|
public ShaderControlValue scvHP30Down; |
|
public Material matHP30Down; |
|
Material matHP30Down_Copy; |
|
/// <summary> |
|
/// HP 의 % 에 따라 다른 효과를 적용합니다. |
|
/// </summary> |
|
public void Material_Restore() |
|
{ |
|
if (USE_HP30DOWN && matHP30Down_Copy != null && HP < HP_Max * hpDownRate) |
|
{ |
|
skeletonAnimation.CustomMaterialOverride[matOrigin] = matHP30Down_Copy; |
|
scvHP30Down.Play(true, true, null); |
|
} |
|
else |
|
{ |
|
skeletonAnimation.CustomMaterialOverride.Remove(matOrigin); |
|
scvHP30Down.Play(false, false, null); |
|
} |
|
} |
|
[Space(5)] |
|
public Material matHit; |
|
Material matHit_Copy; |
|
public float durationHit = 0f; |
|
[System.Serializable] |
|
public class HitSyncEvent : UnityEvent<float> { } |
|
[FormerlySerializedAs("onHitSynced")] |
|
[SerializeField] |
|
private HitSyncEvent onHitSynced = new HitSyncEvent(); |
|
|
|
[Space(5)] |
|
public Material matHitResist; |
|
Material matHitResist_Copy; |
|
public bool HIT_RESIST = false; |
|
public float durationHitResist = 0f; |
|
public bool NO_DAMAGE = false; |
|
[System.Serializable] |
|
public class ResistSyncEvent : UnityEvent<float> { } |
|
[FormerlySerializedAs("onResistSynced")] |
|
[SerializeField] |
|
private ResistSyncEvent onResistSynced = new ResistSyncEvent(); |
|
|
|
/// <summary> |
|
/// 히트 이팩트를 시작합니다. |
|
/// </summary> |
|
/// <param name="duration"></param> |
|
public void Hit_Start(float duration) |
|
{ |
|
if (duration == 0) |
|
return; |
|
|
|
CancelInvoke("Hit_End"); |
|
|
|
skeletonAnimation.CustomMaterialOverride[matOrigin] = matHit_Copy; |
|
|
|
if (HIT_RESIST) |
|
NO_DAMAGE = true; |
|
|
|
Invoke("Hit_End", duration);//히트 이팩트 종료 |
|
|
|
onHitSynced.Invoke(duration);//스파인, 어태치먼트의 경우 따로 적용해야함 |
|
} |
|
/// <summary> |
|
/// 히트 이팩트를 종료하고 원상태로 되돌립니다 |
|
/// </summary> |
|
void Hit_End() |
|
{ |
|
//skeletonAnimation.CustomMaterialOverride.Remove(matOrigin); |
|
Material_Restore(); |
|
|
|
//무적상태 적용 |
|
if (HIT_RESIST) |
|
{ |
|
skeletonAnimation.CustomMaterialOverride[matOrigin] = matHitResist_Copy; |
|
Invoke("HitResist_End", durationHitResist); |
|
|
|
onResistSynced.Invoke(durationHitResist); |
|
} |
|
} |
|
/// <summary> |
|
/// 무적상태를 종료합니다. |
|
/// </summary> |
|
void HitResist_End() |
|
{ |
|
//skeletonAnimation.CustomMaterialOverride.Remove(matOrigin); |
|
Material_Restore(); |
|
|
|
NO_DAMAGE = false; |
|
} |
|
|
|
[Space(10)] |
|
public ShaderControlValue scvHide; |
|
public Material matHide; |
|
Material matHide_Copy; |
|
/// <summary> |
|
/// 캐릭터가 죽었으므로 숨김이팩트를 시작합니다. |
|
/// </summary> |
|
public void Hide_Start() |
|
{ |
|
skeletonAnimation.CustomMaterialOverride[matOrigin] = matHide_Copy; |
|
scvHide.Play(); |
|
} |
|
public void Hide_End() |
|
{ |
|
Debug.LogWarning($"Hide_End"); |
|
//skeletonAnimation.CustomMaterialOverride.Remove(matOrigin); |
|
Material_Restore(); |
|
|
|
gameObject.SetActive(false); |
|
} |
|
|
|
[Space(10)] |
|
public ShaderControlValue scvShow; |
|
public Material matShow; |
|
Material matShow_Copy; |
|
/// <summary> |
|
/// 캐릭터가 초기화 됐으면 맵에 나타나게 합니다. |
|
/// </summary> |
|
public void Show_Start() |
|
{ |
|
return; |
|
|
|
if (scvShow != null) |
|
{ |
|
if (matShow != null) |
|
{ |
|
if (matShow_Copy == null) |
|
{ |
|
matShow_Copy = new Material(matShow); |
|
matShow_Copy.SetTexture("_MainTex", mainTexture); |
|
scvShow.Init(matShow_Copy); |
|
} |
|
|
|
skeletonAnimation.CustomMaterialOverride[matOrigin] = matShow_Copy; |
|
scvShow.Play(); |
|
} |
|
} |
|
} |
|
}
|
|
|