Unity skill system (III)
Demo presentation
6, Buff system
Buffs are divided into gain and loss buff s, which should be distinguished;
Originally, it was planned to use and or not to record buffs. A skill may have multiple buffs, but it is the same as using list to store buffs;
A skill can only have two buff icons, one gain buff for itself and one decrease buff for the enemy;
A skill's gain and loss buff may have multiple effects;
For example: skill lightning - causes deceleration + sensing + repulsion + increases rage (abnormal skill);
However, it is more troublesome to write, so it is not so subdivided. One effect and one icon are timed separately;
The requirements are complex. Rewrite them according to the needs;
/// <summary> ///Buff type, stackable /// </summary> public enum BuffType { None, Burn = 2, //light Slow = 4, //Slow down Light = 8, //Induced electricity Stun = 16, //vertigo Poison = 32, //poisoning BeatBack = 64, //repel BeatUp = 128, //Strike fly Pull = 256, //pull AddDefence = 512, RecoverHp = 1024, }
1.BuffRun
Mount it on the object with buff and calculate the buff effect, such as damage reduction, blood loss, deceleration, etc;
At the same time, it is responsible for buff timing and provides a buff timing refresh interface for repeated buffIcon calls (you can also stack buff layers as required);
Static method initialization and static linked list are used to store the information of buff effect, which is used to dynamically load the preform of buff effect;
public class BuffRun : MonoBehaviour { private float durationTime; public BuffType bufftype; private float value; //Damage or bonus private float interval; private float attackTimer; private float curTime; private CharacterStatus target; //Initialize buffrun when adding buff public void InitBuff(BuffType buffType,float duration,float value,float interval) { bufftype = buffType; if (buffType == BuffType.BeatBack || buffType == BuffType.BeatUp || buffType == BuffType.Pull) duration = 2f; durationTime = duration; this.value = value; this.interval = interval; curTime = 0; } //Reset buff time public void Reset() { attackTimer = 0; curTime = 0; } void Start() { curTime = 0; target = GetComponent<CharacterStatus>(); StartCoroutine(ExcuteDamage()); } private void Update() { curTime += Time.deltaTime; if(curTime > durationTime) Destroy(this); } //Execute buff effect and support multi segment influence private IEnumerator ExcuteDamage() { attackTimer = 0; //Duration of attack do { //Impact on the enemy TargetImpact(); yield return new WaitForSeconds(interval); attackTimer += interval; //Calculate the damage value } while (durationTime > attackTimer); Destroy(this); } private void TargetImpact() { //Buff special effect mount point. Some buff mounts are not in HitFxPos, so they are written on it Transform fxPosTf = target.HitFxPos; //Make corresponding effect response according to different buff s if (bufftype == BuffType.Burn || bufftype == BuffType.Poison || bufftype == BuffType.Light) target.OnDamage(value, gameObject, true); else if (bufftype == BuffType.Slow)//Slow down fxPosTf = target.transform; else if (bufftype == BuffType.BeatBack) { Vector3 dir = -target.transform.position + GameObject.FindGameObjectWithTag("Player").transform.position; dir.y = 0; target.transform.DOMove(target.transform.position - dir.normalized * value,0.5f); durationTime = 2f; } else if (bufftype == BuffType.BeatUp) { target.transform.DOMove(target.transform.position - Vector3.up * value,0.5f); durationTime = 2f; } else if (bufftype == BuffType.AddDefence) { fxPosTf = target.transform; target.defence += value; } else if (bufftype == BuffType.RecoverHp) { target.OnDamage(-value, gameObject, true); } //Mount buff effect if (buffFx.ContainsKey(bufftype)) { GameObject go = Resources.Load<GameObject>($"Skill/{buffFx[bufftype]}"); GameObject buffGo = GameObjectPool.I.CreateObject(buffFx[bufftype], go, fxPosTf.position, fxPosTf.rotation); buffGo.transform.SetParent(fxPosTf); GameObjectPool.I.Destory(buffGo, interval); } } //Store buff effect name and corresponding buff type private static Dictionary<BuffType, string> buffFx = new Dictionary<BuffType, string>(); //Initialize buff effect information public static void InitAllBuff() { buffFx.Add(BuffType.Burn,"Skill_32_R_Fly_100"); buffFx.Add(BuffType.Light,"Skill_75_Cast"); buffFx.Add(BuffType.Slow,"Skill_21_R_Fly_100"); buffFx.Add(BuffType.Poison,"Skill_12_R_Fly_100"); buffFx.Add(BuffType.AddDefence,"FX_CHAR_Aura"); buffFx.Add(BuffType.RecoverHp,"FX_Heal_Light_Cast"); } //Get buff remaining time interface public float GetRemainTime() { return durationTime - curTime; } //buff end recovery target attribute private void OnDisable() { if (bufftype == BuffType.Slow) ; else if (bufftype == BuffType.AddDefence) target.defence -= value; } }
2.BuffIcon
buff icon class, display countdown digital display;
It's not very well written here. You should load buffrun and bufficon at the same time. You don't need separate timing in bufficon;
It cannot be changed temporarily = - =;
Add buffrun field to bufficon, and assign buffrun value while adding bufficon;
Obtain the buff type and remaining countdown through buffrun;
This also stores the information of the traffic in a static way for dynamic loading, which can be stored by importing data externally;
public static Dictionary<BuffType, string> buffIconName = new Dictionary<BuffType, string>(); public static void InitBuffIconName() { buffIconName.Add(BuffType.Burn,"Buff_13"); buffIconName.Add(BuffType.Slow,"Buff_15"); buffIconName.Add(BuffType.Stun,"Buff_12"); buffIconName.Add(BuffType.Poison,"Buff_14"); buffIconName.Add(BuffType.BeatBack,"Buff_5"); buffIconName.Add(BuffType.BeatUp,"Buff_4"); buffIconName.Add(BuffType.Pull,"Buff_6"); buffIconName.Add(BuffType.AddDefence,"Buff_3"); buffIconName.Add(BuffType.RecoverHp,"Buff_7"); buffIconName.Add(BuffType.Light,"Buff_8"); }
What is written here is not very good. Please refer to it;
public class BuffIcon : MonoBehaviour { public Text textCD; public Image imgIcon; private float durationTime; private float curTime; public BuffType buffType; public void LoadIcon(BuffType buffType, float duration) { durationTime = duration; this.buffType = buffType; Sprite[] temp = Resources.LoadAll<Sprite>("BuffIcon/Buff"); if (temp != null) { foreach (var sp in temp) { if (sp.name == SkillDeployer.buffIconName[buffType]) { imgIcon.sprite = Instantiate(sp); } } } } private void OnEnable() { curTime = 0; } void Update() { curTime += Time.deltaTime; textCD.text = (durationTime - curTime).ToString("F0"); if (curTime > durationTime) { gameObject.SetActive(false); curTime = 0; } } public void Refresh() { //Debug.Log("existing buff refresh duration"); curTime = 0; } }
3. Pit point
1. The UI of the enemy uiportal should try not to use the delay setting Active to control the display and hiding. When Active is false, the bufficon will no longer run. When uiportal is displayed next time, the buff icon will display an error;
2. Adjust the uiPortrait of the current target to the display position by causing damage each time, and the uiPortrait adjustment position of all other enemies exceeds the display area;
Therefore, a single instance is needed to store all uiportals; Just write it in monster Mgr. Anyway, it is also used to manage the enemy. By the way, there is nothing wrong with managing the enemy's Avatar;
Three methods are provided: add uiportlet, delete uiportlet, and hide uiportlet (remove the display area);
private List<UIPortrait> allEnemyPortraits = new List<UIPortrait>(); public void AddEnemyPortraits(UIPortrait uiPortrait) { allEnemyPortraits.Add(uiPortrait); } public void RemoveEnemyPortraits(UIPortrait uiPortrait) { allEnemyPortraits.Remove(uiPortrait); } public void HideAllEnemyPortraits() { foreach (var it in allEnemyPortraits) { it.GetComponent<RectTransform>().anchoredPosition = hidePos; } }
4. Sector countdown
The UIbuff icon places two layers of image component objects, and the parent node sets the transparency;
The sub object image component is set according to the following figure, filling mode, filling percentage, and clockwise and counterclockwise;
Code dynamically sets the percentage of fillAmount;
//An example of skill countdown is written in Update float cd = csm.skills[i].coolRemain; skillImgs[i].fillAmount = 1 - cd / csm.skills[i].skill.coolTime; skillTexts[i].text = cd.ToString("F0"); if (skillTexts[i].text == "0") skillTexts[i].text = "";
effect: