Unity turn-based combat system (intermediate level) - health bar and damage value

I found the project file. The old version of the script reported an error. I solved the error under the new version 2019.4.21f1c1, and the battle scene can run normally.

 

Students who need it can click the address below to download (just follow it, no points are required). I wish everyone will succeed in learning as soon as possible.

Project package download

————————————————————————​​​​​​​

I didn’t do much today. I just added the display and animation of combat damage values ​​based on yesterday. Because it also involves the previous scripts related to UI control, I optimized this part by the way. Please see the Gif for the effect.

Next is the main content of this article: focusing on the implementation and script of health bars and damage values.

1. health bar

The first step is to make a health bar prefab, which consists of a base map, a health bar picture and text. The text is used to display the unit name, as shown below, in which the Image Type of the health bar picture is set to Filled.

Previously, a BattleUIManager was used to complete all operations of the health bar. The content was relatively messy. However, it has been optimized here. It is only used to instantiate the script and set the "owner" for the script. The subsequent health bar status is determined by its own The BloodUpdate function updates based on the master's status.

The new BattleUIManager is as follows:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class BattleUIManager : MonoBehaviour {

    //把做好的预制体赋给这个变量
    public GameObject bloodBar;

    //玩家和怪物的数组
    private GameObject[] playerUnits;
    private GameObject[] enemyUnits;

    //统一调整血条的偏移量
    public float bloodXOffeset;
    public float bloodYOffeset;
    public float bloodZOffeset;

    void Start ()
    {
        //搜索所有参战的玩家对象,逐个创建血条
        playerUnits = GameObject.FindGameObjectsWithTag("PlayerUnit");
        foreach (GameObject playerUnit in playerUnits)
        {
            GameObject playerBloodBar = Instantiate(bloodBar) as GameObject;
            //实例化后设置到正确的画布分组里,便于管理也保证能正常显示
            playerBloodBar.transform.SetParent(GameObject.Find("BloodBarGroup").transform, false);

            //设置血条的主人,BloodUpdate将根据这个主人的状态来更新血条
            playerBloodBar.GetComponent<BloodUpdate>().owner = playerUnit;
        }

        //搜索所有参战的怪物对象,逐个创建血条
        enemyUnits = GameObject.FindGameObjectsWithTag("EnemyUnit");
        foreach (GameObject enemyUnit in enemyUnits)
        {
            GameObject enemyBloodBar = Instantiate(bloodBar) as GameObject;
            enemyBloodBar.transform.SetParent(GameObject.Find("BloodBarGroup").transform, false);

            //设置血条的主人,BloodUpdate将根据这个主人的状态来更新血条
            enemyBloodBar.GetComponent<BloodUpdate>().owner = enemyUnit;
        }
    }

    //供按钮调用的函数,此处可忽略
    public void GoToScene(string name)
    {
        SceneManager.LoadScene(name);
    }

}


The BloodUpdate script attached to the health bar prefab is as follows:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class BloodUpdate : MonoBehaviour {

    //血条的主人,在创建时会通过BattleUIManager赋值
    public GameObject owner;

    //血条的长度数值,1为满格
    private Image ownerBloodFill;

    //获取UI控制脚本的引用,要从它那里获取统一的偏移量
    private BattleUIManager uiManager;

    //主人的3D空间位置
    private Vector3 playerBlood3DPosition;
    //将主人的3D位置映射到屏幕之后的2D位置
    private Vector2 playerBlood2DPosition;

    void Start()
    {
        //显示血条主人的名字
        Text ownerText = gameObject.transform.Find("OwnerName").GetComponent<Text>();
        ownerText.text = owner.name;
        
        //获取UI控制脚本的引用
        uiManager = GameObject.Find("BattleUIManager").GetComponent<BattleUIManager>();
    }

    void Update()
    {
        if (owner.tag=="PlayerUnit" || owner.tag == "EnemyUnit")
        {
            //更新血条长度
            ownerBloodFill = gameObject.transform.Find("BloodFill").GetComponent<Image>();
            ownerBloodFill.fillAmount = owner.GetComponent<UnitStats>().bloodPercent;           //bloodPercent在每个单位的UnitStats脚本中存储

            //更新血条位置
            //获取当前主人的空间位置,然后转换为2D屏幕位置
            playerBlood3DPosition = owner.transform.position + new Vector3(uiManager.bloodXOffeset, uiManager.bloodYOffeset, uiManager.bloodZOffeset);
            playerBlood2DPosition = Camera.main.WorldToScreenPoint(playerBlood3DPosition);
            gameObject.GetComponent<RectTransform>().position = playerBlood2DPosition;
        }

        //如果主人死了,则设置为未激活状态
        if (owner.GetComponent<UnitStats>().IsDead())
        {
            gameObject.SetActive(false);
        }
    }

}

In this way, the generation, following and updating of the blood bar are all realized.

2. Damage value

The implementation of the damage value is similar to the health bar. The prefab is also completed first, and then I create a process animation for the damage text to enlarge, appear, and gradually disappear. The movement of the font is realized through scripts.

The generation of damage value is directly placed in the turn control script, and is generated immediately after executing ReceiveDamage;

//被攻击者承受伤害
        currentActUnitTarget.GetComponent<UnitStats>().ReceiveDamage(attackData);

        //实例化伤害字体并设置到画布上(字体位置和内容的控制放在它自身的脚本中)
        GameObject thisText = Instantiate(bloodText) as GameObject;
        thisText.transform.SetParent(GameObject.Find("BloodTextGroup").transform, false);

It is still managed in the same way as the health bar, and is set to the correct canvas group immediately after generation;

Here is the DamageFloatUp script hanging on the damage value prefab:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DamageFloatUp : MonoBehaviour {
    
    private BattleTurnSystem turnScript;            //回合控脚本的引用

    //受到伤害单位的位置
    private Vector3 takeDamageUnit3DPosition;
    private Vector2 takeDamageUnit2DPosition;

    void Start ()
    {
        turnScript = GameObject.Find("BattleManager").GetComponent<BattleTurnSystem>();         //查找引用

        //计算伤害者的3D位置并转化为屏幕2D位置
        takeDamageUnit3DPosition = turnScript.currentActUnitTarget.transform.position + new Vector3(0,1,0);         //适当上移修正位置
        takeDamageUnit2DPosition = Camera.main.WorldToScreenPoint(takeDamageUnit3DPosition);
        gameObject.GetComponent<RectTransform>().position = takeDamageUnit2DPosition;

        //设置数字内容
        gameObject.GetComponent<Text>().text = "-"+ turnScript.attackData;

        //延迟销毁自身
        StartCoroutine("WaitAndDestory");
    }

	void Update () {
        //向上漂浮控制
        gameObject.GetComponent<RectTransform>().anchoredPosition = gameObject.GetComponent<RectTransform>().anchoredPosition + new Vector2(0, 1);
    }

    //延迟销毁
    IEnumerator WaitAndDestory()
    {
        yield return new WaitForSeconds(1.5f);
        Destroy(gameObject);
    }
}

that's all

Guess you like

Origin blog.csdn.net/c252270036/article/details/77203557