Reputation: 11319
This script is attached to a door :
Even if the variable doorLockState is set to true enabled true in the editor and the door should be color in red the door is green using a breakpoint the state variable inside ColorDoors is change between red and green non stop once state is true next it's false but in the editor it's all the time checked as true :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
[ExecuteAlways]
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 Update()
{
ColorDoors(Color.red, Color.green, doorLockState);
}
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.sharedMaterial.shader = Shader.Find("Unlit/ShieldFX");
if (state == true)
{
renderer.sharedMaterial.SetColor("_MainColor", red);
LockState(true);
}
else
{
renderer.sharedMaterial.SetColor("_MainColor", green);
LockState(false);
}
}
}
}
public bool GetLockState
{
get { return doorLockState; }
set { doorLockState = value; }
}
private void LockState(bool state)
{
var collider = gameObject.GetComponent<BoxCollider>();
if (state == false)
{
collider.size = new Vector3(2.3f, 2.736307f, 2.5f);
collider.center = new Vector3(0, 1.378154f, 0);
collider.transform.localPosition = new Vector3(-1.57f, 0, -2.98f);
collider.isTrigger = true;
}
else
{
collider.size = new Vector3(2.3f, 2.736307f, 3);
collider.center = new Vector3(0, 1.378154f, 0);
collider.transform.localPosition = new Vector3(-1.57f, 0, -2.98f);
collider.isTrigger = false;
}
}
}
Screenshot of a door constructor in the Hierarchy and the script in the Inspector:
The object Horizontal_Doors_Kit tag is set to Door.
And this is the editor script that should let me control the doors but there is also a problem here too since in the editor it's not listing all the doors :
using UnityEditor;
using UnityEngine;
[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();
}
}
Screenshot of the editor script inspector :
It's showing the two variables Global Lock State but it should also list the 12 doors.
The first problem the state of the door/s is all the time unlocked green color.
The second problem is why it's not listing all the doors so I can control each/all the doors either in editor or runtime ?
And the script DoorsLockManager :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
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
{
_globalLockState = 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 = _globalLockState;
}
}
}
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>();
}
}
}
Upvotes: 0
Views: 106
Reputation: 385
Currently your Doors
list is only being updated when Awake()
is called in your DoorsLockManager
(and not accessible from the inspector), which means the list is always empty outside of runtime. Changing this should allow the list to be displayed in the inspector while editing.
Making the following minor changes to DoorsLockManager.cs:
private void Awake()
{
UpdateDoors();
}
public void UpdateDoors()
{
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>();
}
}
and adding the following to the top of the OnInspectorGUI()
method in DoorsLockManagerEditor.cs:
if (GUILayout.Button("Update Door List"))
{
((DoorsLockManager)target).UpdateDoors();
}
should achieve this by providing a button to update the list when needed.
Individual and global lock states should now be functional, however only one of the two Global Lock State
toggles is properly functional, this can be fixed by either removing base.OnInspectorGUI();
from the OnInspectorGUI()
method in DoorsLockManagerEditor.cs or by adding [HideInInspector]
before [SerializeField] private bool _globalLockState;
in DoorsLockManager.cs.
Currently HoriDoorManager.cs will only update their respective doors at runtime as the ColorDoors
method is called only in Awake()
and Update()
. This can instead be made to update whenever the doorLockState
bool is changed by modifying your GetLockState
property as so:
public bool GetLockState
{
get { return doorLockState; }
set
{
doorLockState = value;
ColorDoors(Color.red, Color.green, doorLockState);
}
}
and assigning to this property instead of the backing variable in the GlobalLockState
property of DoorsLockManager.cs (replacing line 28: door.doorLockState = _globalLockState;
with door.GetLockState = _globalLockState;
).
Edit: This is a bit of a quick hack but adding the following to DoorsLockManager.cs:
public void UpdateColors()
{
foreach (var door in Doors)
{
door.GetLockState = door.GetLockState;
}
}
and the following to OnInspectorGUI()
in DoorsLockManagerEditor.cs beneath the other button:
if (GUILayout.Button("Update Door Colors"))
{
((DoorsLockManager)target).UpdateColors();
}
should allow you to tell the doors to update their colours from the inspector manually.
Upvotes: 1