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.
325 lines
8.9 KiB
325 lines
8.9 KiB
using DG.Tweening;
|
|
using Spine;
|
|
using Spine.Unity.AttachmentTools;
|
|
using UnityEngine;
|
|
|
|
public class IVCharacter : CreatureBase
|
|
{
|
|
private static readonly float F_DamNormal = 24f;
|
|
private static readonly Color CLR_CharDam = new Color(0.8f, 0.8f, 0.8f);
|
|
|
|
[SerializeField] protected Skeleton skeleton;
|
|
[SerializeField] private AudioSource asNormalAttack;
|
|
[SerializeField] private Transform colObj;
|
|
[SerializeField] ParticleSystem[] attackEffects;
|
|
[SerializeField] Transform damageIndicatorPos;
|
|
|
|
BoxCollider col;
|
|
Material mainMaterial;
|
|
|
|
int attackState = 0;
|
|
|
|
int currentCostumeID = -1;
|
|
int currentWeaponID = -1;
|
|
|
|
protected override void Start()
|
|
{
|
|
base.Start();
|
|
skeleton = skAnim.Skeleton;
|
|
|
|
var renderer = skAnim.GetComponent<MeshRenderer>();
|
|
mainMaterial = renderer.sharedMaterial;
|
|
|
|
col = colObj.GetChild(0).GetComponent<BoxCollider>();
|
|
|
|
bFriendly = true;
|
|
}
|
|
|
|
protected override void InitTween()
|
|
{
|
|
twcSummon = transform.DOScale(Global.V3_1, 1.1f).SetEase(Ease.OutQuad).OnComplete(SummonEnd).SetAutoKill(false).Pause();
|
|
twcUnsummon = transform.DOScale(Global.V3_1, 1.1f).SetEase(Ease.InQuad).OnComplete(UnsummonEnd).SetAutoKill(false).Pause();
|
|
}
|
|
|
|
protected override void OnDie()
|
|
{
|
|
base.OnDie();
|
|
|
|
if (bFriendly)
|
|
battleMgr.DieFriendly();
|
|
else
|
|
battleMgr.DieEnemy(eCreatureClass.charEnemy, 0);
|
|
}
|
|
|
|
protected override void SearchTarget()
|
|
{
|
|
if (!IsBattleAvail())
|
|
{
|
|
if (battleMgr.BattlePause)
|
|
ChangeState(eState.idle);
|
|
|
|
return;
|
|
}
|
|
|
|
fSearchTick = 0f;
|
|
if (!TargetFinder.TryFindNearest(transform.position, TargetFilter, out target))
|
|
{
|
|
ChangeState(eState.idle);
|
|
}
|
|
else
|
|
{
|
|
if (stackSkillAvail.Count > 0 && stackSkillAvail.Peek() == -1)
|
|
{
|
|
ChangeState(eState.move);
|
|
stackSkillAvail.Pop();
|
|
}
|
|
else
|
|
{
|
|
useSkillRange = stackSkillAvail.Count > 0 ? battleMgr.GetSkillRange(stackSkillAvail.Peek()) : 0;
|
|
}
|
|
|
|
if (sqrtDistToTarget <= useSkillRange * useSkillRange)
|
|
{
|
|
ChangeState(eState.skill);
|
|
CheckSkill();
|
|
}
|
|
|
|
if(animState == eState.rush)
|
|
{
|
|
if (!isdash)
|
|
CheckAttack();
|
|
return;
|
|
}
|
|
|
|
if (sqrtDistToTarget <= attackRange * attackRange)
|
|
{
|
|
CheckAttack();
|
|
}
|
|
else
|
|
{
|
|
ChangeState(eState.move);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Summon(Vector3 v3pos, bool bfrontright)
|
|
{
|
|
base.Summon(v3pos, bfrontright);
|
|
BattleMgr.SSetPetFront(bFriendly, IsLookRight);
|
|
BattleMgr.SSetGuardianFront(bFriendly, IsLookRight);
|
|
}
|
|
|
|
public override void Summon()
|
|
{
|
|
if (bLoading)
|
|
{
|
|
bSummonNeed = true;
|
|
return;
|
|
}
|
|
|
|
bDead = false;
|
|
bSummon = true;
|
|
bAttackable = false;
|
|
fAttackTick = 0f;
|
|
target = null;
|
|
|
|
gameObject.SetActive(true);
|
|
ChangeStateForce(eState.warp_in);
|
|
twcSummon.Restart();
|
|
|
|
if (bInitNeed)
|
|
{
|
|
bInitNeed = false;
|
|
anState = skAnim.AnimationState;
|
|
}
|
|
|
|
BattleMgr.SSetPetFront(bFriendly, IsLookRight);
|
|
BattleMgr.SSetGuardianFront(bFriendly, IsLookRight);
|
|
}
|
|
|
|
public override void Unsummon()
|
|
{
|
|
bSummon = true;
|
|
bAttackable = false;
|
|
ChangeStateForce(eState.warp_out);
|
|
}
|
|
|
|
public void MoveToDir(Vector2 moveVec)
|
|
{
|
|
switch (animState)
|
|
{
|
|
case eState.warp_in:
|
|
case eState.warp_out:
|
|
case eState.die:
|
|
case eState.rush:
|
|
return;
|
|
}
|
|
|
|
var newPos = transform.position + (Vector3)moveVec * moveSpeed * Time.deltaTime;
|
|
|
|
newPos.x = Mathf.Clamp(newPos.x, minArea.x, maxArea.x);
|
|
newPos.y = Mathf.Clamp(newPos.y, minArea.y, maxArea.y);
|
|
newPos.z = newPos.y * 2f;
|
|
|
|
transform.position = newPos;
|
|
ChangeLookDirection(moveVec);
|
|
}
|
|
|
|
protected override void MoveToTarget()
|
|
{
|
|
if (!bCoward && moveSpeed <= 0f || target is null) return;
|
|
|
|
Vector2 to = (targetPos - (Vector2)transform.position).normalized;
|
|
var newPos = transform.position + (Vector3)to * moveSpeed * Time.deltaTime;
|
|
|
|
newPos.x = Mathf.Clamp(newPos.x, minArea.x, maxArea.x);
|
|
newPos.y = Mathf.Clamp(newPos.y, minArea.y, maxArea.y);
|
|
newPos.z = newPos.y * 0.1f;
|
|
|
|
transform.position = newPos;
|
|
ChangeLookDirection(targetTransform);
|
|
}
|
|
|
|
protected override void OnDamaged(Damage damage)
|
|
{
|
|
var indicator = battleMgr.GetDamageIndicatorText(true);
|
|
if(indicator != null)
|
|
{
|
|
indicator.SetText(FormatString.BigIntString1(damage.value), F_DamNormal, CLR_CharDam);
|
|
indicator.Show(damageIndicatorPos.position);
|
|
}
|
|
|
|
if (!ptcHit.isPlaying)
|
|
ptcHit.Play();
|
|
}
|
|
|
|
public override void CheckAttack()
|
|
{
|
|
if (bStun) return;
|
|
|
|
if (bAttackable && target != null)
|
|
{
|
|
ChangeLookDirection(targetTransform);
|
|
|
|
if (SoundMgr.Instance.EfcOn)
|
|
asNormalAttack.Play();
|
|
|
|
if(attackEffects.Length > attackState && attackEffects[attackState] != null)
|
|
attackEffects[attackState].Play();
|
|
|
|
switch(attackState)
|
|
{
|
|
case 0:
|
|
ChangeState(eState.attack);
|
|
attackState = 1;
|
|
break;
|
|
case 1:
|
|
ChangeState(eState.attack2);
|
|
attackState = 2;
|
|
break;
|
|
case 2:
|
|
ChangeState(eState.attack3);
|
|
attackState = 0;
|
|
break;
|
|
}
|
|
|
|
skAnim.timeScale = 1.0f * motionSpeed;
|
|
|
|
backAllowed = 1;
|
|
}
|
|
else
|
|
{
|
|
ChangeState(eState.idle);
|
|
}
|
|
}
|
|
|
|
public override void CheckSkill()
|
|
{
|
|
if (bStun) return;
|
|
|
|
if (stackSkillAvail.Count > 0 && target != null)
|
|
{
|
|
int skillid = stackSkillAvail.Peek();
|
|
if (!battleMgr.IsOnAutoSkill && skillid != battleMgr.GetUseSkillid())
|
|
{
|
|
stackSkillAvail.Pop();
|
|
}
|
|
else
|
|
{
|
|
int skillused = battleMgr.UseSkill(bFriendly, skillid, this, target, fCrtDamCalc, iCrtRateCalc, currentAtk);
|
|
|
|
if (skillused != 0) // 스킬 사용함 or 사용할 수 없는 스킬.
|
|
stackSkillAvail.Pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RefreshStat()
|
|
{
|
|
maxAtk = BuffMgr.Instance.GetCharAtk();
|
|
currentAtk = maxAtk;
|
|
|
|
maxHp = BuffMgr.Instance.GetCharHp();
|
|
if(currentHp > maxHp)
|
|
currentHp = maxHp;
|
|
}
|
|
|
|
#region Ani Event
|
|
public override void AttackDamage()
|
|
{
|
|
if (battleMgr.BattlePause || bSummon || bDead) return;
|
|
|
|
colObj.position = targetPos;
|
|
|
|
const int maxAttackCount = 3;
|
|
var targets = TargetFinder.GetNears(Position, TargetFilter);
|
|
int attackCount = 0;
|
|
|
|
for(int i = 0; i < targets.Count; i++)
|
|
{
|
|
var target = targets[i];
|
|
|
|
if(col.bounds.Contains((target as Entity).Position))
|
|
{
|
|
target.GetDamage(currentAtk, fCrtDamCalc, iCrtRateCalc);
|
|
|
|
if(++attackCount >= maxAttackCount)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bFriendly && attackCount > 0)
|
|
IVCameraController.SShakeCamera(0.2f, 0.3f, 0);
|
|
}
|
|
#endregion Ani Event
|
|
|
|
|
|
#region Costume & Color
|
|
public void SetCostume(int costumeID) => SetSkin(costumeID, currentWeaponID);
|
|
public void SetWeapon(int weaponID) => SetSkin(currentCostumeID, weaponID);
|
|
public void SetSkin(int costumeID, int weaponID)
|
|
{
|
|
if (costumeID == currentCostumeID && weaponID == currentWeaponID) return;
|
|
|
|
currentCostumeID = costumeID;
|
|
currentWeaponID = weaponID;
|
|
|
|
var newSkin = new Skin("Custom");
|
|
newSkin.AddSkin(skeleton.Data.DefaultSkin);
|
|
|
|
if (skeleton.Data.TryGetSkin($"Costume/{currentCostumeID}", out Skin costumeSkin))
|
|
newSkin.AddSkin(costumeSkin);
|
|
|
|
if (skeleton.Data.TryGetSkin($"Weapon/{currentWeaponID}", out Skin weaponSkin))
|
|
newSkin.AddSkin(weaponSkin);
|
|
|
|
var repackedSkin = newSkin.GetRepackedSkin("Custom", mainMaterial, out var newMat, out var newTex);
|
|
|
|
skeleton.SetSkin(repackedSkin);
|
|
skeleton.SetSlotsToSetupPose();
|
|
skAnim.Update(0);
|
|
|
|
AtlasUtilities.ClearCache();
|
|
}
|
|
#endregion Costume & color
|
|
}
|