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.
 
 
 
 
 
 

174 lines
4.5 KiB

using System.Collections.Generic;
using UnityEngine;
using Spine.Unity;
using Skill_V2;
using System.Numerics;
using System;
public struct Damage
{
public BigInteger value;
public bool isCritical;
}
public class Character : Entity, IBattleEntity
{
[SerializeField] SkeletonAnimation skeletonAnimation;
[SerializeField] StateHandler<Character> stateHandler;
StatData hpStat;
LayerMask layerMask;
Skill[] skills = new Skill[0];
public CharacterData Data { get; private set; }
public SkeletonAnimation SkeletonAnimation => skeletonAnimation;
public StateHandler<Character> StateHandler => stateHandler;
public Bitset32.Mask TargetTags { get; private set; }
public IReadOnlyList<Skill> Skills => skills;
public BigInteger CurrentHp { get; private set; }
public bool IsDead => CurrentHp <= 0;
public bool IsBattleReady { get; set; }
public event Action<Character> OnSpawned;
public event Action<Character> OnDisposed;
public event Action<Character, Damage> OnDamaged;
private void Awake()
{
if (skeletonAnimation == null)
skeletonAnimation = GetComponent<SkeletonAnimation>();
if (stateHandler == null)
stateHandler = GetComponent<StateHandler<Character>>();
AddTags(EntityTag.Character);
}
private void Update()
{
for(int i = 0; i < skills.Length; i++)
skills[i].UpdateSkillCoolTime();
}
private void OnDestroy()
{
for (int i = 0; i < skills.Length; i++)
{
var skill = skills[i];
if (skill != null) continue;
skill.Stop();
if(skill.gameObject != null)
Destroy(skill.gameObject);
}
}
public void SetData(CharacterData charData)
{
Debug.Assert(charData != null, Logger.LogMessage(LogType.Assert, nameof(SetData), " data is null"));
Debug.Assert(Data == null, Logger.LogMessage(LogType.Assert, nameof(SetData), " data is already set"));
Data = charData;
if (Data.Skills != null)
{
skills = new Skill[Data.Skills.Count];
int i = 0;
foreach (var skillData in Data.Skills)
{
skills[i] = Instantiate(skillData.Prefab);
skills[i].SetSkillData(skillData);
skills[i].Stop();
i++;
}
}
stateHandler.Initialize(this);
foreach (var component in GetComponents<IOwnedComponent<Character>>())
{
component.Initialize(this);
}
}
public void SetTargetTags(LayerMask mask, params EntityTag[] tags)
{
layerMask = mask;
TargetTags = Bitset32.GetMask(Array.ConvertAll(tags, (t) => (Enum)t));
foreach (var skill in skills)
{
skill.SetTargetTags(layerMask, tags);
}
}
public void Spawn(UnityEngine.Vector2 spawnPos)
{
Debug.Assert(stateHandler != null, "StateHandler is null");
Debug.Assert(skeletonAnimation != null, "SkeletonAnimation is null");
transform.position = spawnPos;
if (Data.TryGetStat(StatID.Hp, out hpStat))
{
CurrentHp = hpStat.Value;
hpStat.OnValueChanged += OnHpChanged;
}
OnSpawned?.Invoke(this);
}
public void Dispose()
{
if (hpStat != null)
hpStat.OnValueChanged -= OnHpChanged;
for (int i = 0; i < skills.Length; i++)
{
skills[i].Stop();
}
OnDisposed?.Invoke(this);
}
private void OnHpChanged()
{
if (CurrentHp >= (BigInteger)hpStat.Value)
CurrentHp = hpStat.Value;
}
public bool IsBattleAvail() => IsBattleReady;
public void GetDamage(BigInteger atk, float critDmgRate, int critRate, int dnum = -1)
{
if(CurrentHp <= 0) return;
bool isCritical = CreatureBase.CheckCritical(critRate);
if(isCritical)
atk = CreatureBase.GetCriticalDamage(atk, critDmgRate, critRate);
Damage dmg = new Damage {
value = atk,
isCritical = isCritical
};
CurrentHp = BigInteger.Max(0, CurrentHp - dmg.value);
OnDamaged?.Invoke(this, dmg);
}
private void OnValidate()
{
if (skeletonAnimation == null)
skeletonAnimation = GetComponent<SkeletonAnimation>();
if (stateHandler == null)
stateHandler = GetComponent<StateHandler<Character>>();
}
}