Почему состояние блокировки дверей отменяется и устанавливается в false при запуске игры? - PullRequest
0 голосов
/ 25 марта 2019

Работает нормально, когда игра уже запущена. Я могу изменить состояние каждого дверного замка. Но перед запуском игры я устанавливаю одну или несколько дверей, которые должны быть заблокированы (установлен флажок, установите флаг в значение true), а затем, запустив игру, он меняет все двери на ложно разблокированные.

Я хочу, чтобы, если я установлю состояние блокировки дверей также перед запуском игры, он сохранит эти изменения при запуске игры.

Первый скрипт с одной строкой:

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class DoorsLockManager : MonoBehaviour
{
    public List<HoriDoorManager> Doors = new List<HoriDoorManager>();
}

Второй скрипт управления дверями:

using UnityEditor;

[CustomEditor(typeof(DoorsLockManager))]
public class DoorsLockManagerEditor : Editor
{
    DoorsLockManager _manager;

    public override void OnInspectorGUI()
    {
        _manager = (DoorsLockManager)target;

        base.OnInspectorGUI();

        if (_manager.Doors.Count <= 0)
            return;
        for (var i = 0; i < _manager.Doors.Count; i++)
        {
            if (_manager.Doors[i] == null)
                continue;

            _manager.Doors[i].GetLockState = EditorGUILayout.Toggle("Door " + i + " Lockstate", _manager.Doors[i].GetLockState);
        }
    }
}

Последний скрипт прикреплен к каждой двери:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;

public class HoriDoorManager : MonoBehaviour
{
    public List<DoorHori> doors = new List<DoorHori>(); 
    public bool doorLockState;

    private void Awake()
    {
        if (transform.parent != null)
        {
            Transform parent = transform.parent;
            var children = parent.GetComponentsInChildren<Transform>();

            if (children != null)
            {
                foreach (Transform door in children)
                {
                    if (door.name == "Door_Left" || door.name == "Door_Right")
                        doors.Add(door.GetComponent<DoorHori>());
                }
            }
            //ColorDoors(Color.red, Color.green, doorLockState);
        }
    }

    void OnTriggerEnter()
    {
        if (doorLockState == false)
        {
            if (doors != null)
            {
               for(int i =0; i < doors.Count; i++)
                {
                    doors[i].OpenDoor();
                }
            }
        }
    }

    private void ColorDoors(Color red, Color green, bool state)
    {
        List<Transform> children = new List<Transform>();

        for (int i = 0; i < doors.Count; i++)
        {
            foreach (Transform child in doors[i].GetComponentsInChildren<Transform>())
            {
                if (child == doors[i].transform)
                    continue;

                var renderer = child.GetComponent<Renderer>();
                renderer.material.shader = Shader.Find("Unlit/ShieldFX");

                if(state == true)
                {
                    renderer.material.SetColor("_MainColor", red);
                }
                else
                {
                    renderer.material.SetColor("_MainColor", green);
                }
            }
        }
    }

    public bool GetLockState
    {
        get { return doorLockState; }
        set { doorLockState = value; }
    }
}

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

свойства не сериализуемы !

те, которые вы никогда не должны изменять в скриптах редактора, поскольку они не сериализуются => никогда не сохраняются и всегда будут иметь значение по умолчанию.

будет не работать, если это свойство как

public bool GetLockState
{
    get { return doorLockState; }
    set { doorLockState = value; }
}

зачем вообще использовать это, если ваш doorLockState равен public?

Проблема в том, что измененное поле doorLockState не помечается как "грязное".

Однако вы должны не использовать EditorUtility.SetDirty, как предложено другим ответом из-за:

Начиная с версии 5.3, с введением Multi-Scene Editing, эта функция больше не должна использоваться для изменения объектов в сценах . Вместо этого вы должны использовать Undo.RecordObject до внесения изменений в объект. Это пометит Сцену объекта как dirty и предоставит запись отмены в редакторе. '


Вместо этого в скрипте редактора вы должны изменить значение doorLockState.

Если это где private, вам нужно было бы добавить [SerializeField]

[SerializeField] private bool doorLockState;

Но в вашем случае, похоже, оно равно public, поэтому оно автоматически сериализуется.

Чем всегда используйте правильные SerializedProperty и PropertyField вместо прямой манипуляции значениями в сценариях редактора!

Вначале все выглядит сложнее, но он обрабатывает такие вещи, как Undo / Redo и помечает вещи как «грязные» (таким образом, сохраняя изменения) автоматически, так что вам не нужно больше ни о чем заботиться:

[CustomEditor(typeof(DoorsLockManager))]
public class DoorsLockManagerEditor : Editor
{
    private SerializedProperty _doors;

    private void OnEnable()
    {
        _doors = serializedObject.FindProperty("Doors");
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        for (int i = 0; i < _doors.arraySize; i++)
        {
            var door = _doors.GetArrayElementAtIndex(i);

            // if door == null the script itself has an error since it can't even find the SerializedProperty
            if (door == null)
            {
                EditorGUILayout.HelpBox("There was an error in the editor script!\nPlease check the log", MessageType.Error);
                Debug.LogError("Couldn't get door property", target);
                return;
            }

            if (door.objectReferenceValue == null) continue;

            // FindPropertyRelative seems not to work for MonoBehaviour classes
            // so we have to use this hack around
            var serializedDoor = new SerializedObject(door.objectReferenceValue);

            // If it's public no worry anyway
            // If it's private still works since we made it a SerializeField
            var lockState = serializedDoor.FindProperty("doorLockState");

            // Fetch current values into the serialized "copy"
            serializedDoor.Update();

            if (lockState == null)
            {
                EditorGUILayout.HelpBox("There was an error in the editor script!\nPlease check the log", MessageType.Error);
                Debug.LogError("Couldn't get lockState property", target);
                return;
            }

            // for the PropertyField there is 
            // no return value since it automatically uses
            // the correct drawer for the according property
            // and directly changes it's value
            EditorGUILayout.PropertyField(lockState, new GUIContent("Door " + i + " Lockstate"));

            // or alternatively
            //lockState.boolValue = EditorGUILayout.Toggle("Door " + i + " Lockstate", lockState.boolValue);

            // Write back changes, mark as dirty if changed
            // and add a Undo history entry
            serializedDoor.ApplyModifiedProperties();
        }
    }
}

enter image description here

(Конечно, значение обновляется только OnInspectorGUI, поэтому, если у вас открыто несколько вкладок Инспектора, оно обновляется только при наведении)

0 голосов
/ 26 марта 2019

Вы пробовали EditorUtility.SetDirty в DoorsLockManagerEditor ?

Похоже, редактор не сохраняет начальное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...