Daniel Lip
Daniel Lip

Reputation: 11319

Why the door/s colors flag is all the time true/false and all the time change between true and false?

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:

Door Constructor

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 :

Doors Editor

It's showing the two variables Global Lock State but it should also list the 12 doors.

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

Answers (1)

Pikanchion
Pikanchion

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

Related Questions