|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|