после добавления этого скрипта в юнити показывает ...
बनाया गया: 16 जुलाई 2026
का उपयोग करके उत्तर दिया गया GPT-5.6 Thinking द्वारा Chat01
बनाया गया: 16 जुलाई 2026
का उपयोग करके उत्तर दिया गया GPT-5.6 Thinking द्वारा Chat01
после добавления этого скрипта в юнити показывает 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; } }
}
С высокой вероятностью это каскадные ошибки из-за старой версии C# в Unity. В исходнике используются конструкции =>, $"..." и ?.Invoke(...). Старые версии Unity могут не понимать их и после первой синтаксической ошибки показывать ещё множество последующих. Версия поддерживаемого C# зависит от версии Unity и выбранного scripting runtime. (Unity Documentation)
Также файл должен называться AutoSaveManager.cs.
Ниже версия без новых конструкций C#, которая должна лучше работать в старых проектах Unity:
csharpusing 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)
После замены проверьте:
AutoSaveManager.cs.AutoSaveManager или AutoSaveData.