using DG.Tweening; 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); private static readonly float F_AddYCharDam = 3.4f; [SerializeField] protected Spine.Skeleton skeleton; [SerializeField] private AudioSource asNormalAttack; [SerializeField] private Transform colObj; [SerializeField] ParticleSystem[] attackEffects; private BoxCollider col; protected MeshRenderer mrendAnim; protected MaterialPropertyBlock mpbAnim; private int attackState = 0; protected override void Start() { base.Start(); skeleton = skAnim.Skeleton; mrendAnim = skAnim.GetComponent(); mpbAnim = new MaterialPropertyBlock(); mpbAnim.SetTexture(GlobalShaderProperty._mainTexPropertyID, mrendAnim.sharedMaterial.mainTexture); col = colObj.GetChild(0).GetComponent(); 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); BattleMgr.Instance.RefreshCharCloth(); 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); Vector2 pos = transform.position; pos.y += F_AddYCharDam; indicator.Show(pos); } 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(Texture2D tx2d) { if (tx2d == null) return; mpbAnim.SetTexture(GlobalShaderProperty._mainTexPropertyID, tx2d); for (int i = 0; i < mrendAnim.sharedMaterials.Length; i++) { if (mrendAnim.sharedMaterials[i] == GameProperty.Instance.PlayerCharacterMaterial) { mrendAnim.SetPropertyBlock(mpbAnim, i); break; } } } public void SetWeapon(Spine.Skin skincustom) { if (skincustom == null) return; skeleton.SetSkin(skincustom); skeleton.SetSlotsToSetupPose(); skAnim.Update(0f); } public Spine.Skeleton GetSkeleton() { return skeleton; } #endregion Costume & color }