Проблема с сохранением времени

В чём суть: мне нужно подсчитывать общее время прохождения игры каждым игроком и изменять соответственно состояние переменной у этого игрока, которая хранит время, путём прибавления времени проведенного на уровне к общему времени в игре. Я делаю это в 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 шт):

Автор решения: Alemkhan Utepkaliev

Отслеживайте не каждый кадр, а разницу между двумя значениями, начальными и конечными, я предлагаю использовать класс 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() вообще

→ Ссылка
Автор решения: Yaroslav

Познакомтесь с 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);
→ Ссылка