c# - 为什么门/s颜色标志一直是真/假,并且一直在真假之间变化?
问题描述
此脚本附在门上:
即使变量 doorLockState 设置为 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;
}
}
}
Hierarchy 中的门构造函数和 Inspector 中的脚本的屏幕截图:
对象 Horizontal_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();
}
}
编辑器脚本检查器的屏幕截图:
它显示了两个变量 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>();
}
}
}
解决方案
目前,您的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.csOnInspectorGUI()
方法的顶部:
if (GUILayout.Button("Update Door List"))
{
((DoorsLockManager)target).UpdateDoors();
}
应该通过提供一个按钮来在需要时更新列表来实现这一点。
单个和全局锁定状态现在应该可以正常工作,但是两个Global Lock State
切换中只有一个可以正常工作,这可以通过base.OnInspectorGUI();
从 DoorsLockManagerEditor.cs 中的OnInspectorGUI()
方法中删除或在DoorsLockManager.cs中添加[HideInInspector]
before来修复。[SerializeField] private bool _globalLockState;
目前,HoriDoorManager.cs只会在运行时更新它们各自的门,因为该ColorDoors
方法仅在Awake()
和中调用Update()
。每当doorLockState
bool 更改时,可以通过如下方式修改您的GetLockState
属性来进行更新:
public bool GetLockState
{
get { return doorLockState; }
set
{
doorLockState = value;
ColorDoors(Color.red, Color.green, doorLockState);
}
}
并分配给此属性,而不是DoorsLockManager.csGlobalLockState
属性中的支持变量(将第 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();
}
应该允许您告诉检查员手动更新它们的颜色。
推荐阅读
- c# - 使用动态生成的类型进行变量声明和赋值
- lua - Lua Table - 搜索以字母开头的项目
- nuxt.js - Nuxt Vue 3,选项 api 工作正常时无法使用组合 api
- python - 如何使用 `add_next_tick_callback` 制作面板包裹的散景图?
- javascript - 在像抽屉一样的反应原生中显示垂直文本
- python - 为调用 Keras 模型的类设置种子
- javascript - 我的 JavaScript Fade-in on-scroll 功能不起作用
- sql - 查找中的聚合数据集
- symfony - Doctrine override_url 错误 Travis CI 上没有这样的文件或目录
- react-native-sound - 运行命令以在反应本机项目中安装声音依赖项时出错