Проблема с сохранением времени
В чём суть: мне нужно подсчитывать общее время прохождения игры каждым игроком и изменять соответственно состояние переменной у этого игрока, которая хранит время, путём прибавления времени проведенного на уровне к общему времени в игре. Я делаю это в Update() с помощью Time.deltatime. И вот тут проблема: Update() вызывается 50,60 раз в секунду и соответственно получаю некорректное время, как это можно исправить? Ниже код, который относится к проигрышу игрока. Код:
private void Update()
{
timePass += Time.deltaTime;
if (HeroTakeHurt.isGODestroy == true) { // Если игровой объект персонажа уничтожен, то игрок проиграл и отображается соответствующее меню
foreach (var elem in MainMenuController.Players) // Проходим по всей коллекции профилей игроков
{
if (elem.Name == MainMenuController.currentPlayer)
{
elem.defeats += 1;
elem.passTime += timePass; //Вот здесь изменяю общее время прохождения, которое из-за Update() является не корректным
}
}
XmlSerializer xmlSerialiser = new XmlSerializer(typeof(List<MainMenuController.Player>));
using (TextWriter textWriter = new StreamWriter(@"D:\Unity Projects\myProject\Saves\Player.xml"))
{
xmlSerialiser.Serialize(textWriter, MainMenuController.Players);
}
}
код HeroTakeHurt:
public class HeroTakeHurt : MonoBehaviour
{
public HealthBar healthBar;
public static bool isGODestroy;
public static bool isDead;
private float timeStart;
public Animator animator;
[SerializeField]
private int maxHealth = 300;
public int currHealth;
private void Start()
{
animator = GetComponent<Animator>();
currHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
isGODestroy = false;
isDead = false;
}
public void TakeDamage(int damage)
{
currHealth -= damage;
healthBar.SetHealth(currHealth);
animator.SetTrigger("Hurt");
if(currHealth <= 0)
{
this.gameObject.layer = LayerMask.NameToLayer("Hero dead"); // Изменяем слой персонажа, чтобы с ним нельзя было взаимодействовать
animator.SetTrigger("IsDead");
timeStart = Time.time;
isDead = true;
}
}
public void Die() // Нужна, чтобы уничтожить игровой объект персонажа через промежуток времени, после проигрывания анимации
{ if(Time.time >= timeStart + 1.0f && isDead)
{
Debug.Log(timeStart);
isGODestroy = true;
Destroy(gameObject);
}
}
}
Ответы (2 шт):
Отслеживайте не каждый кадр, а разницу между двумя значениями, начальными и конечными, я предлагаю использовать класс DateTime
У Вас соответственно есть начало игры (предположим это метод Start()), и конец (условно это уничтожение персонажа).
Во первых данный класс (Session), будем использовать как хранилище данных о сессии
Session.cs
private class Session : MonoBehavior
{
private DateTime _sessionStartDateTime = new DateTime(); // Создаем поле для стартовой даты
private DateTime _sessionEndDateTime = new DateTime(); // Создаем поле для конечной даты
private float _sessionDurationTime; // Создаем поле для хранения разницы секунд между двумя датами
private void Start()
{
SessionStart();
}
public void SessionStart()
{
_sessionStartDateTime = DateTime.Now; // Присваиваем стартовой дате текущее значение времени в момент начала
}
public void SessionEnd()
{
_sessionEndDateTime = DateTime.Now // После поражения присваиваем конечной дате текущее время в момент поражения
// Далее отнимаем кол-во секунд конечной даты от стартовой и получаем длительность сессии
_sessionDurationTime = (float)(sessionEndDateTime.TimeOfDay.TotalSeconds - sessionStartDateTime.TimeOfDay.TotalSeconds);
// Далее можно выполнять необходимые действия после получения длительности сессии
}
}
Далее корректируем HeroTakeHurt
HeroTakeHurt.cs
public class HeroTakeHurt : MonoBehaviour
{
public HealthBar healthBar;
// public static bool isGODestroy; // Более не требуется
public static bool isDead;
private float timeStart;
public Animator animator;
[SerializeField]
private int maxHealth = 300;
public int currHealth;
[SerializeField] private Session _session; // Перетащить в инспектор данный обьект с компонентом
...
public void Die() // Нужна, чтобы уничтожить игровой объект персонажа через промежуток времени, после проигрывания анимации
{
if(Time.time >= timeStart + 1.0f && isDead)
{
Debug.Log(timeStart);
_session.SessionEnd(); // После смерти закрываем сессию
Destroy(gameObject);
}
}
}
Теперь класс хранит в себе переменную с длительностью сессии без использования проверки в Update() вообще
Познакомтесь с DateTime (момент времени) и TimeSpan (разница времени) библиотеки System.
DateTime sessionStart = DateTime.Now; // при старте
// ...
DateTime sessionEnd = DateTime.Now; // в конце
TimeSpan session = sessionEnd-sessionStart;
Debug.Log(session.TotalSeconds);
DateTime не сериализуется, их нужно конвертировать в long.
long saveTime = sessionStart.ToFileTimeUtc();
DateTime sessionStart = DateTime.FromFileTimeUtc(saveTime);