после добавления этого скрипта в юнити показывает ...

Erstellt am: 16. Juli 2026

Beantwortet mit GPT-5.6 Thinking von Chat01

Frage

после добавления этого скрипта в юнити показывает 17 ошибок
using System;
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;

[Serializable]
public class AutoSaveData
{
// Сцена
public string sceneName;

text
// Позиция и поворот игрока public bool hasPlayer; public float positionX; public float positionY; public float positionZ; public float rotationX; public float rotationY; public float rotationZ; public float rotationW; // Примеры игровых параметров public int health; public int coins; // Время создания сохранения public string savedAtUtc;

}

public class AutoSaveManager : MonoBehaviour
{
public static AutoSaveManager Instance { get; private set; }

text
[Header("Настройки автосохранения")] [Tooltip("Включить автоматическое сохранение по таймеру")] [SerializeField] private bool autoSaveEnabled = true; [Tooltip("Интервал между сохранениями в секундах")] [Min(1f)] [SerializeField] private float autoSaveInterval = 30f; [Tooltip("Автоматически загрузить сохранение при запуске")] [SerializeField] private bool loadOnStart = false; [Tooltip("Сохранять игру при сворачивании приложения")] [SerializeField] private bool saveOnPause = true; [Tooltip("Сохранять игру при выходе")] [SerializeField] private bool saveOnQuit = true; [Header("Игрок")] [Tooltip("Можно перетащить объект игрока сюда. Если поле пустое, игрок будет найден по тегу")] [SerializeField] private Transform player; [Tooltip("Тег объекта игрока")] [SerializeField] private string playerTag = "Player"; [Header("Пример игровых данных")] [SerializeField] private int health = 100; [SerializeField] private int coins = 0; private string savePath; private AutoSaveData pendingLoadData; /// <summary> /// Вызывается после загрузки игровых параметров. /// Первый параметр — здоровье, второй — монеты. /// </summary> public event Action<int, int> GameDataLoaded; public int Health { get => health; set => health = value; } public int Coins { get => coins; set => coins = value; } public string SavePath => savePath; private void Awake() { // Не позволяем создать несколько менеджеров сохранения. if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; // Объект не уничтожается при переходе между сценами. DontDestroyOnLoad(gameObject); savePath = Path.Combine( Application.persistentDataPath, "autosave.json" ); SceneManager.sceneLoaded += OnSceneLoaded; Debug.Log($"Путь к сохранению: {savePath}"); } private IEnumerator Start() { FindPlayer(); // Ждем один кадр, чтобы остальные объекты успели запуститься. yield return null; if (loadOnStart) { LoadGame(); } StartCoroutine(AutoSaveRoutine()); } private IEnumerator AutoSaveRoutine() { while (true) { // Используется реальное время, поэтому сохранение работает // даже при Time.timeScale = 0. yield return new WaitForSecondsRealtime(autoSaveInterval); if (autoSaveEnabled) { SaveNow(); } } } /// <summary> /// Немедленно сохраняет игру. /// Метод можно подключить к UI-кнопке. /// </summary> [ContextMenu("Сохранить сейчас")] public void SaveNow() { try { FindPlayer(); AutoSaveData data = new AutoSaveData { sceneName = SceneManager.GetActiveScene().name, health = health, coins = coins, savedAtUtc = DateTime.UtcNow.ToString("O") }; if (player != null) { data.hasPlayer = true; Vector3 position = player.position; Quaternion rotation = player.rotation; data.positionX = position.x; data.positionY = position.y; data.positionZ = position.z; data.rotationX = rotation.x; data.rotationY = rotation.y; data.rotationZ = rotation.z; data.rotationW = rotation.w; } else { data.hasPlayer = false; Debug.LogWarning( "Игрок не найден. Игровые параметры сохранены, " + "но позиция игрока не записана." ); } string json = JsonUtility.ToJson(data, true); // Сначала записываем временный файл. // Это уменьшает вероятность повреждения сохранения. string temporaryPath = savePath + ".tmp"; File.WriteAllText(temporaryPath, json); if (File.Exists(savePath)) { File.Delete(savePath); } File.Move(temporaryPath, savePath); Debug.Log( $"Игра сохранена. " + $"Здоровье: {health}, монеты: {coins}" ); } catch (Exception exception) { Debug.LogError( $"Не удалось сохранить игру:\n{exception}" ); } } /// <summary> /// Загружает последнее сохранение. /// Метод можно подключить к UI-кнопке. /// </summary> [ContextMenu("Загрузить сохранение")] public void LoadGame() { if (!File.Exists(savePath)) { Debug.LogWarning("Файл сохранения еще не создан."); return; } try { string json = File.ReadAllText(savePath); AutoSaveData data = JsonUtility.FromJson<AutoSaveData>(json); if (data == null) { Debug.LogError("Не удалось прочитать данные сохранения."); return; } string currentScene = SceneManager.GetActiveScene().name; // Если игра была сохранена в другой сцене, // сначала загружаем нужную сцену. if (!string.IsNullOrEmpty(data.sceneName) && data.sceneName != currentScene) { if (!Application.CanStreamedLevelBeLoaded(data.sceneName)) { Debug.LogError( $"Сцена \"{data.sceneName}\" не добавлена " + "в Build Settings или Build Profiles." ); return; } pendingLoadData = data; SceneManager.LoadScene(data.sceneName); return; } StartCoroutine(ApplyDataNextFrame(data)); } catch (Exception exception) { Debug.LogError( $"Не удалось загрузить игру:\n{exception}" ); } } /// <summary> /// Удаляет файл сохранения. /// </summary> [ContextMenu("Удалить сохранение")] public void DeleteSave() { try { if (File.Exists(savePath)) { File.Delete(savePath); } string temporaryPath = savePath + ".tmp"; if (File.Exists(temporaryPath)) { File.Delete(temporaryPath); } Debug.Log("Сохранение удалено."); } catch (Exception exception) { Debug.LogError( $"Не удалось удалить сохранение:\n{exception}" ); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // Старый объект игрока уничтожается при смене сцены, // поэтому ищем нового. player = null; FindPlayer(); if (pendingLoadData != null) { AutoSaveData data = pendingLoadData; pendingLoadData = null; StartCoroutine(ApplyDataNextFrame(data)); } } private IEnumerator ApplyDataNextFrame(AutoSaveData data) { // Ждем, пока игрок и остальные скрипты сцены создадутся. yield return null; FindPlayer(); ApplyData(data); } private void ApplyData(AutoSaveData data) { health = data.health; coins = data.coins; if (data.hasPlayer) { if (player != null) { Vector3 position = new Vector3( data.positionX, data.positionY, data.positionZ ); Quaternion rotation = new Quaternion( data.rotationX, data.rotationY, data.rotationZ, data.rotationW ); player.SetPositionAndRotation(position, rotation); } else { Debug.LogWarning( "Позиция не восстановлена: игрок не найден." ); } } // Сообщаем другим скриптам, что данные загружены. GameDataLoaded?.Invoke(health, coins); Debug.Log( $"Игра загружена. " + $"Здоровье: {health}, монеты: {coins}" ); } private void FindPlayer() { if (player != null) { return; } if (string.IsNullOrEmpty(playerTag)) { return; } try { GameObject playerObject = GameObject.FindGameObjectWithTag(playerTag); if (playerObject != null) { player = playerObject.transform; } } catch (UnityException exception) { Debug.LogWarning( $"Не удалось найти объект с тегом \"{playerTag}\". " + $"Проверьте тег игрока.\n{exception.Message}" ); } } private void OnApplicationPause(bool pauseStatus) { if (pauseStatus && saveOnPause) { SaveNow(); } } private void OnApplicationQuit() { if (saveOnQuit) { SaveNow(); } } private void OnDestroy() { if (Instance == this) { SceneManager.sceneLoaded -= OnSceneLoaded; Instance = null; } }

}

Gedanke

undefined

Gedanke

Providing solution to Unity errors and file naming details

It looks like I’m going to explain the likely cause of the user's errors and suggest a compatible script. I’ll note that the file name should be AutoSaveManager.cs to avoid duplicate definition errors. I'll also clarify that the script must be placed under Assets, not in the Editor folder, and that certain Unicode characters in comments could be causing issues. Additionally, I’ll mention the limitation in Unity 2017 and older regarding expression-bodied accessors.

Thought for 18s

Antwort

С высокой вероятностью это каскадные ошибки из-за старой версии C# в Unity. В исходнике используются конструкции =>, $"..." и ?.Invoke(...). Старые версии Unity могут не понимать их и после первой синтаксической ошибки показывать ещё множество последующих. Версия поддерживаемого C# зависит от версии Unity и выбранного scripting runtime. (Unity Documentation)

Также файл должен называться AutoSaveManager.cs.

Ниже версия без новых конструкций C#, которая должна лучше работать в старых проектах Unity:

csharp
using System; using System.Collections; using System.IO; using UnityEngine; using UnityEngine.SceneManagement; [Serializable] public class AutoSaveData { public string sceneName; public bool hasPlayer; public float positionX; public float positionY; public float positionZ; public float rotationX; public float rotationY; public float rotationZ; public float rotationW; public int health; public int coins; public string savedAtUtc; } public class AutoSaveManager : MonoBehaviour { public static AutoSaveManager Instance { get; private set; } [Header("Настройки автосохранения")] [Tooltip("Включить автоматическое сохранение по таймеру")] [SerializeField] private bool autoSaveEnabled = true; [Tooltip("Интервал между сохранениями в секундах")] [SerializeField] private float autoSaveInterval = 30f; [Tooltip("Автоматически загрузить сохранение при запуске")] [SerializeField] private bool loadOnStart = false; [Tooltip("Сохранять игру при сворачивании приложения")] [SerializeField] private bool saveOnPause = true; [Tooltip("Сохранять игру при выходе")] [SerializeField] private bool saveOnQuit = true; [Header("Игрок")] [Tooltip("Можно перетащить объект игрока сюда")] [SerializeField] private Transform player; [Tooltip("Тег объекта игрока")] [SerializeField] private string playerTag = "Player"; [Header("Пример игровых данных")] [SerializeField] private int health = 100; [SerializeField] private int coins = 0; private string savePath; private AutoSaveData pendingLoadData; public event Action<int, int> GameDataLoaded; public int Health { get { return health; } set { health = value; } } public int Coins { get { return coins; } set { coins = value; } } public string SavePath { get { return savePath; } } private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); savePath = Path.Combine( Application.persistentDataPath, "autosave.json" ); SceneManager.sceneLoaded += OnSceneLoaded; Debug.Log("Путь к сохранению: " + savePath); } private IEnumerator Start() { FindPlayer(); yield return null; if (loadOnStart) { LoadGame(); } StartCoroutine(AutoSaveRoutine()); } private IEnumerator AutoSaveRoutine() { while (true) { if (autoSaveInterval < 1f) { autoSaveInterval = 1f; } yield return new WaitForSecondsRealtime(autoSaveInterval); if (autoSaveEnabled) { SaveNow(); } } } [ContextMenu("Сохранить сейчас")] public void SaveNow() { try { FindPlayer(); AutoSaveData data = new AutoSaveData(); data.sceneName = SceneManager.GetActiveScene().name; data.health = health; data.coins = coins; data.savedAtUtc = DateTime.UtcNow.ToString("O"); if (player != null) { data.hasPlayer = true; Vector3 position = player.position; Quaternion rotation = player.rotation; data.positionX = position.x; data.positionY = position.y; data.positionZ = position.z; data.rotationX = rotation.x; data.rotationY = rotation.y; data.rotationZ = rotation.z; data.rotationW = rotation.w; } else { data.hasPlayer = false; Debug.LogWarning( "Игрок не найден. Позиция игрока не сохранена." ); } string json = JsonUtility.ToJson(data, true); string temporaryPath = savePath + ".tmp"; File.WriteAllText(temporaryPath, json); if (File.Exists(savePath)) { File.Delete(savePath); } File.Move(temporaryPath, savePath); Debug.Log( "Игра сохранена. Здоровье: " + health + ", монеты: " + coins ); } catch (Exception exception) { Debug.LogError( "Не удалось сохранить игру:\n" + exception ); } } [ContextMenu("Загрузить сохранение")] public void LoadGame() { if (!File.Exists(savePath)) { Debug.LogWarning("Файл сохранения еще не создан."); return; } try { string json = File.ReadAllText(savePath); AutoSaveData data = JsonUtility.FromJson<AutoSaveData>(json); if (data == null) { Debug.LogError( "Не удалось прочитать данные сохранения." ); return; } string currentScene = SceneManager.GetActiveScene().name; if (!string.IsNullOrEmpty(data.sceneName) && data.sceneName != currentScene) { if (!Application.CanStreamedLevelBeLoaded( data.sceneName )) { Debug.LogError( "Сцена \"" + data.sceneName + "\" не добавлена в Build Settings." ); return; } pendingLoadData = data; SceneManager.LoadScene(data.sceneName); return; } StartCoroutine(ApplyDataNextFrame(data)); } catch (Exception exception) { Debug.LogError( "Не удалось загрузить игру:\n" + exception ); } } [ContextMenu("Удалить сохранение")] public void DeleteSave() { try { if (File.Exists(savePath)) { File.Delete(savePath); } string temporaryPath = savePath + ".tmp"; if (File.Exists(temporaryPath)) { File.Delete(temporaryPath); } Debug.Log("Сохранение удалено."); } catch (Exception exception) { Debug.LogError( "Не удалось удалить сохранение:\n" + exception ); } } private void OnSceneLoaded( Scene scene, LoadSceneMode mode ) { player = null; FindPlayer(); if (pendingLoadData != null) { AutoSaveData data = pendingLoadData; pendingLoadData = null; StartCoroutine(ApplyDataNextFrame(data)); } } private IEnumerator ApplyDataNextFrame( AutoSaveData data ) { yield return null; FindPlayer(); ApplyData(data); } private void ApplyData(AutoSaveData data) { health = data.health; coins = data.coins; if (data.hasPlayer) { if (player != null) { Vector3 position = new Vector3( data.positionX, data.positionY, data.positionZ ); Quaternion rotation = new Quaternion( data.rotationX, data.rotationY, data.rotationZ, data.rotationW ); // Совместимо со старыми версиями Unity. player.position = position; player.rotation = rotation; } else { Debug.LogWarning( "Позиция не восстановлена: игрок не найден." ); } } if (GameDataLoaded != null) { GameDataLoaded(health, coins); } Debug.Log( "Игра загружена. Здоровье: " + health + ", монеты: " + coins ); } private void FindPlayer() { if (player != null) { return; } if (string.IsNullOrEmpty(playerTag)) { return; } try { GameObject playerObject = GameObject.FindGameObjectWithTag(playerTag); if (playerObject != null) { player = playerObject.transform; } } catch (UnityException exception) { Debug.LogWarning( "Не удалось найти объект с тегом \"" + playerTag + "\". Проверьте тег игрока.\n" + exception.Message ); } } private void OnApplicationPause(bool pauseStatus) { if (pauseStatus && saveOnPause) { SaveNow(); } } private void OnApplicationQuit() { if (saveOnQuit) { SaveNow(); } } private void OnDestroy() { if (Instance == this) { SceneManager.sceneLoaded -= OnSceneLoaded; Instance = null; } } }

JsonUtility действительно предназначен для сериализации обычных классов с поддерживаемыми полями, поэтому структура AutoSaveData подходит для него. (Unity Documentation)

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

  1. Файл называется AutoSaveManager.cs.
  2. В проекте нет второго класса с именем AutoSaveManager или AutoSaveData.
  3. В Unity создан тег Player и он назначен объекту игрока.
  4. Сцены добавлены в File → Build Settings.
  5. Посмотрите именно первую красную ошибку в Console — остальные 16 могут быть её последствиями.

Diesen Q&A teilen