Индикатор здоровья + сохранение [UI]

Полоску жизни персонажа или может энергии, можно сделать разными способами, чаще всего используется стандартный слайдер в Unity, после некоторых настроек и манипуляций, его можно приспособить под эту задачу. Однако, мы хотим предложить несколько иной способ, напишем свой класс, который лишь частично будет напоминать слайдер и будет заточен для отображения различных индикаторов. Для управления индикаторами так же предусмотрен отдельный класс, он же у нас отвечает за сохранение и загрузку. У индикатора будет два режима работы, горизонтальный и вертикальный, плюс, возможность управлять цветом.

Настроить наш индикатор еще проще, чем слайдер. Добавляем в свой Canvas, пустой RectTransform, и вешаем на него следующий скрипт:

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

[RequireComponent(typeof(RectTransform))]

public class GameBar : MonoBehaviour {

	private enum Mode {Horizontal, Vertical}
	[SerializeField] private float maxValue = 100;
	[SerializeField] private Color minColor = Color.red;
	[SerializeField] private Color middleColor = Color.yellow;
	[SerializeField] private Color maxColor = Color.green;
	[SerializeField] private Image image; // дочерний Image
	[SerializeField] private Mode direction;
	private Color color_min, color_middle, color_max;
	private RectTransform curRect;
	private float delta;
	public float percent { get; private set; }
	public float current { get; private set; }
	public float max { get; private set; }

	public void ResetBarColors()
	{
		color_max = maxColor;
		color_middle = middleColor;
		color_min = minColor;
		SetTargetColor();
	}

	public void Initialize()
	{
		color_max = maxColor;
		color_middle = middleColor;
		color_min = minColor;
		max = maxValue;
		current = maxValue;
		curRect = GetComponent<RectTransform>();
		if(direction == Mode.Horizontal) delta = curRect.sizeDelta.x;
		else delta = curRect.sizeDelta.y;
		image.raycastTarget = false;
		percent = 1;
		SetTargetColor();
		SetTargetRect();
	}

	void OnValidate()
	{
		RectTransform t = GetComponent<RectTransform>();
		float x = t.sizeDelta.x, y = t.sizeDelta.y;
		if(direction == Mode.Horizontal && y > x || direction == Mode.Vertical && x > y) t.sizeDelta = new Vector2(y, x);

		if(image != null)
		{
			image.rectTransform.anchorMin = Vector2.zero;
			image.rectTransform.anchorMax = Vector2.one;
			image.rectTransform.offsetMax = Vector2.zero;
			image.rectTransform.offsetMin = Vector2.zero;
		}
	}

	public void BarSetup(float currentValue, float maxValue)
	{
		current = currentValue;
		max = maxValue;
		percent = Round(currentValue/maxValue);
		SetTargetColor();
		SetTargetRect();
	}

	public void BarSetup(Color colorMax, Color colorMiddle, Color colorMin)
	{
		color_max = colorMax;
		color_middle = colorMiddle;
		color_min = colorMin;
		SetTargetColor();
	}

	public void BarSetup(float currentValue, float maxValue, Color colorMax, Color colorMiddle, Color colorMin)
	{
		color_max = colorMax;
		color_middle = colorMiddle;
		color_min = colorMin;
		current = currentValue;
		max = maxValue;
		percent = Round(currentValue/maxValue);
		SetTargetColor();
		SetTargetRect();
	}

	void SetTargetColor()
	{
		Color color = color_max;

		if(percent < .3f) color = color_min;
		else if(percent < .7f) color = color_middle;

		image.color = color;
	}

	void SetTargetRect()
	{
		float offset = -(delta - (delta * percent));
		if(offset > 0) offset = 0;
		if(direction == Mode.Horizontal) image.rectTransform.offsetMax = new Vector2(offset, 0);
		else image.rectTransform.offsetMax = new Vector2(0, offset);
		image.rectTransform.offsetMin = Vector2.zero;
	}

	public void Adjust(float value)
	{
		current += value;
		if(current < 0) current = 0;
		if(current > max) current = max;
		percent = Round(current/max);
		SetTargetColor();
		SetTargetRect();
	}

	float Round(float f)
	{
		return ((int)(f * 100f)) / 100f;
	}
}

Далее, в этом пустом трансфоме создаем дочерний Image, после чего указываем его в переменной скрипта. Теперь можно настроить размеры индикатора, изменяя ширину и высоту родителя.

Например, у нас три бара персонажа: здоровье, энергия и опыт. Мы даем им соответствующие названия и чтобы не взаимодействовать с каждым по отдельности, сделаем специальный класс:

using System.Collections;
using UnityEngine;
using System.IO;

public class GameBarManager : MonoBehaviour {

	[SerializeField] private GameBar[] bars;
	[SerializeField] private string fileName = "GameBars.dat";
	private static GameBarManager _int;

	void Awake()
	{
		_int = this;

		for(int i = 0; i < bars.Length; i++)
		{
			bars[i].Initialize();
		}

		if(File.Exists(GetPath())) Load();
	}

	string Crypt(string text)
	{
		string result = string.Empty;
		foreach (char j in text) result += (char)((int)j ^ 38);
		return result;
	}

	string GetPath()
	{
		return Application.persistentDataPath + "/" + fileName;
	}

	float Parse(string val)
	{
		float value;
		if(float.TryParse(val, out value)) return value;
		return 0;
	}

	void Load()
	{
		StreamReader reader = new StreamReader(GetPath());

		while(!reader.EndOfStream)
		{
			string[] val = Crypt(reader.ReadLine()).Split(new char[]{'|'});

			BarSetup_int(val[0], Parse(val[1]), Parse(val[2]));
		}

		reader.Close();

		Debug.Log(this + " --> Загрузка файла: " + GetPath());
	}

	public static void Save()
	{
		_int.Save_int();
	}

	void Save_int()
	{
		if(bars.Length == 0) return;

		StreamWriter writer = new StreamWriter(GetPath());

		for(int i = 0; i < bars.Length; i++)
		{
			writer.WriteLine(Crypt(bars[i].name + "|" + bars[i].current + "|" + bars[i].max));
		}

		writer.Close();

		Debug.Log(this + " --> Сохранение файла: " + GetPath());
	}

	public static void Adjust(string barName, float value)
	{
		_int.Adjust_int(barName, value);
	}

	void Adjust_int(string barName, float value)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) bars[i].Adjust(value);
		}
	}

	public static void BarSetup(string barName, float currentValue, float maxValue)
	{
		_int.BarSetup_int(barName, Mathf.Abs(currentValue), Mathf.Abs(maxValue));
	}

	void BarSetup_int(string barName, float currentValue, float maxValue)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) bars[i].BarSetup(currentValue, maxValue);
		}
	}

	public static void BarSetup(string barName, Color colorMax, Color colorMiddle, Color colorMin)
	{
		_int.BarSetup_int(barName, colorMax, colorMiddle, colorMin);
	}

	void BarSetup_int(string barName, Color colorMax, Color colorMiddle, Color colorMin)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) bars[i].BarSetup(colorMax, colorMiddle, colorMin);
		}
	}

	public static void BarSetup(string barName, float currentValue, float maxValue, Color colorMax, Color colorMiddle, Color colorMin)
	{
		_int.BarSetup_int(barName, Mathf.Abs(currentValue), Mathf.Abs(maxValue), colorMax, colorMiddle, colorMin);
	}

	void BarSetup_int(string barName, float currentValue, float maxValue, Color colorMax, Color colorMiddle, Color colorMin)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) bars[i].BarSetup(currentValue, maxValue, colorMax, colorMiddle, colorMin);
		}
	}

	public static void ResetBarColors(string barName)
	{
		_int.ResetBarColors_int(barName);
	}

	void ResetBarColors_int(string barName)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) bars[i].ResetBarColors();
		}
	}

	public static float CurrentValue(string barName)
	{
		return _int.CurrentValue_int(barName);
	}

	float CurrentValue_int(string barName)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) return bars[i].current;
		}

		return 0;
	}

	public static float MaxValue(string barName)
	{
		return _int.MaxValue_int(barName);
	}

	float MaxValue_int(string barName)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) return bars[i].max;
		}

		return 0;
	}

	public static float Percent(string barName)
	{
		return _int.Percent_int(barName);
	}

	float Percent_int(string barName)
	{
		for(int i = 0; i < bars.Length; i++)
		{
			if(bars[i].name.CompareTo(barName) == 0) return bars[i].percent * 100f;
		}

		return 0;
	}
}

Все бары персонажа указываем в массиве класса. Это же скрипт отвечает за сохранение.

Примеры использования:

GameBarManager.BarSetup("name", 100, 100); // установить только текущее значение и максимальное

GameBarManager.BarSetup("name", Color.green, Color.yellow, Color.red); // установить только цвета бара

GameBarManager.BarSetup("name", 100, 100, Color.green, Color.yellow, Color.red); // установить и цвета и значения бара

GameBarManager.ResetBarColors("name"); // установить цвета бара по умолчанию

GameBarManager.CurrentValue("name"); // получить текущее значение

GameBarManager.MaxValue("name"); // получить максимальное значение

GameBarManager.Percent("name"); // получить значение бара в процентах 0...100

GameBarManager.Adjust("name", 5); // добавить указанное число

GameBarManager.Adjust("name", -5); // убавить на указанное число

GameBarManager.Save(); // сохранить максимальное и текущее значение для всех баров

Как видно из примера, мы сделали возможность менять цвета бара, данная функция будет полезна, если допустим на персонажа было какое-то воздействие на его здоровье, типа магический эффект, что можно отобразить в цвете.

Скачать демо:

У вас нет доступа!
Тестировалось на: Unity 5.6.2
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика