#c# #unity3d
#c# #unity-game-engine
Вопрос:
Теперь он отлично работает в редакторе и во время выполнения для каждой двери. Но я хочу добавить глобальный общедоступный флаг, который будет управлять всеми дверями одновременно в редакторе и во время выполнения. Если я изменю глобальный флаг на true, все двери будут заблокированы, и то же самое, если установлено значение false.
Скрипт DoorsLockManager:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
[ExecuteInEditMode]
public class DoorsLockManager : MonoBehaviour
{
[HideInInspector]
public List<HoriDoorManager> Doors = new List<HoriDoorManager>();
private void Awake()
{
var doors = GameObject.FindGameObjectsWithTag("Door");
Doors = new HoriDoorManager[doors.Length].ToList();
for (int i = 0; i < doors.Length; i )
{
Doors[i] = doors[i].GetComponent<HoriDoorManager>();
}
}
}
И сценарий редактора:
using UnityEditor;
using UnityEngine;
[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 only 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();
}
}
}
Ответ №1:
Ну, вы могли бы просто добавить его в DoorsLockManager
[ExecuteInEditMode]
public class DoorsLockManager : MonoBehaviour
{
[HideInInspector]
public List<HoriDoorManager> Doors = new List<HoriDoorManager>();
// The global state
[SerializeField] private bool _globalLockState;
// During runtime use a property instead
public bool GlobalLockState
{
get { return _globalLockState; }
set
{
_globalLocakState = value;
// apply it to all doors
foreach(var door in Doors)
{
// now you would need it public again
// or use the public property you had there
Door.doorLockState = _globalLocakState;
}
}
}
private void Awake()
{
var doors = GameObject.FindGameObjectsWithTag("Door");
Doors = new HoriDoorManager[doors.Length].ToList();
for (int i = 0; i < doors.Length; i )
{
Doors[i] = doors[i].GetComponent<HoriDoorManager>();
}
}
}
и в редакторе заставьте его «перезаписать» все остальные флаги, если они изменены:
[CustomEditor(typeof(DoorsLockManager))]
public class DoorsLockManagerEditor : Editor
{
private SerializedProperty _doors;
private SerializedProperty _globalLockState;
private bool shouldOverwrite;
private void OnEnable()
{
_doors = serializedObject.FindProperty("Doors");
_globalLockState = serializedObject.FindProperty("_globalLockState");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
shouldOverwrite = false;
// Begin a change check here
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(_globalLockState);
if(EditorGUI.EndChangeCheck())
{
// overwrite only once if changed
shouldOverwrite = true;
}
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;
var serializedDoor = new SerializedObject(door.objectReferenceValue);
var lockState = serializedDoor.FindProperty("doorLockState");
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;
}
// HERE OVERWRITE
if(shouldOverwrite)
{
lockState.boolValue = _globalLockState.boolValue;
}
else
{
EditorGUILayout.PropertyField(lockState, new GUIContent("Door " i " Lockstate"));
}
serializedDoor.ApplyModifiedProperties();
}
serializedObject.ApplyModifiedProperties();
}
}
Комментарии:
1. Это позволяет мне только установить все двери глобально заблокированными, но тогда глобальное состояние не проверяется и не может изменить разблокировку дверей. Я имею в виду, что либо в редакторе, либо во время выполнения, если все двери разблокированы, и я проверяю глобальное состояние, это заблокирует их, но затем глобальное состояние не проверяется, поэтому его больше нельзя изменить на разблокированный, только один за другим.
2. О да, я забыл добавить
serializedObject.Update();
иserializedObject.ApplyModifiedProperties();
снова
Ответ №2:
Вы могли бы создать статический класс с этим флагом в нем, а затем привязать к нему состояние двери «активировано». Пример:
public static class GlobalVariables()
{
public static bool DoorsLocked = true; //Doors would be locked dependent on logic
}
Затем вы просто устанавливаете состояние дверей в глобальную переменную в коде. Когда вы меняете глобальный bool, меняются двери.
GlobalVariables.DoorsLocked = false; //unlocks all doors reading the global bool
Надеюсь, это поможет!