为什么门的颜色标记始终为true / false,并且始终在true和false之间变化?

时间:2019-11-02 18:13:44

标签: c# unity3d

此脚本附在门上:

即使在编辑器中将变量doorLockState设置为true且启用true,并且门应为红色,门也将使用断点为绿色,一旦状态为true,则ColorDoors内部的状态变量将在红色和绿色之间切换,然后不停止这是错误的,但在编辑器中始终将其检查为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;
        }
    }
}

层次结构中的门构造器和检查器中的脚本的屏幕截图:

Door Constructor

对象Horizo​​ntal_Doors_Kit标记设置为Door。

这是应该让我控制门的编辑器脚本,但是这里也存在问题,因为在编辑器中,它没有列出所有门:

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();
    }
}

编辑器脚本检查器的屏幕截图:

Doors Editor

它显示了两个变量Global Lock State,但它也应该列出12个门。

  • 门的状态的第一个问题是一直解锁的绿色。

  • 第二个问题是为什么它没有列出所有门,所以我可以在编辑器或运行时中控制每个/所有门?

还有脚本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>();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

当前,Doors列表仅在Awake()中被调用DoorsLockManager时才被更新(并且不能从检查器中访问),这意味着该列表在运行时之外始终为空。更改此设置应允许在编辑时将列表显示在检查器中。

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>();
    }
}

并在 DoorsLockManagerEditor.cs 中的OnInspectorGUI()方法的顶部添加以下内容:

if (GUILayout.Button("Update Door List"))
{
    ((DoorsLockManager)target).UpdateDoors();
}

应该通过提供一个在需要时更新列表的按钮来实现这一目标。

个人和全局锁定状态现在应该可以正常工作,但是两个Global Lock State切换中只有一个可以正常工作,可以通过从base.OnInspectorGUI();方法中删除OnInspectorGUI()来解决此问题。 DoorsLockManagerEditor.cs ,或在 DoorsLockManager.cs 中的[HideInInspector]之前添加[SerializeField] private bool _globalLockState;

当前 HoriDoorManager.cs 仅在运行时更新其各自的门,因为仅在ColorDoorsAwake()中调用了Update()方法。相反,只要更改doorLockState属性即可更改GetLockState布尔值,就可以使其更新:

public bool GetLockState
{
    get { return doorLockState; }
    set
    {
        doorLockState = value;
        ColorDoors(Color.red, Color.green, doorLockState);
    }
}

并分配给该属性,而不是 DoorsLockManager.cs GlobalLockState属性中的后备变量(将行28:door.doorLockState = _globalLockState;替换为door.GetLockState = _globalLockState;)。


编辑: 这是一个快速的技巧,但是将以下内容添加到 DoorsLockManager.cs

public void UpdateColors()
{
    foreach (var door in Doors)
    {
        door.GetLockState = door.GetLockState;
    }
}

,然后在另一个按钮下的 DoorsLockManagerEditor.cs OnInspectorGUI()中进行以下操作:

    if (GUILayout.Button("Update Door Colors"))
    {
        ((DoorsLockManager)target).UpdateColors();
    }

应该允许您从检查员那里告诉门手动更新其颜色。