c# - 为什么在运行游戏时门锁状态会覆盖并设置为 false?
问题描述
当游戏已经运行时,它工作正常。我可以改变每个门锁状态。但是在运行游戏之前,我将一扇或多扇门设置为锁定(选中将标志设置为 true ),然后运行游戏,它将所有门改回 false 解锁。
我希望如果我在运行游戏之前也设置门锁状态,它会在游戏运行时保持这种变化。
第一个脚本只有一行:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class DoorsLockManager : MonoBehaviour
{
public List<HoriDoorManager> Doors = new List<HoriDoorManager>();
}
第二个脚本控制门:
using UnityEditor;
[CustomEditor(typeof(DoorsLockManager))]
public class DoorsLockManagerEditor : Editor
{
DoorsLockManager _manager;
public override void OnInspectorGUI()
{
_manager = (DoorsLockManager)target;
base.OnInspectorGUI();
if (_manager.Doors.Count <= 0)
return;
for (var i = 0; i < _manager.Doors.Count; i++)
{
if (_manager.Doors[i] == null)
continue;
_manager.Doors[i].GetLockState = EditorGUILayout.Toggle("Door " + i + " Lockstate", _manager.Doors[i].GetLockState);
}
}
}
最后一个脚本附在每扇门上:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
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 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.material.shader = Shader.Find("Unlit/ShieldFX");
if(state == true)
{
renderer.material.SetColor("_MainColor", red);
}
else
{
renderer.material.SetColor("_MainColor", green);
}
}
}
}
public bool GetLockState
{
get { return doorLockState; }
set { doorLockState = value; }
}
}
解决方案
属性不可序列化!
那些你根本不应该在编辑器脚本中更改的,因为它们没有序列化 => 永远不会保存,并且总是具有默认值。
如果它是像这样的属性,它将不起作用
public bool GetLockState
{
get { return doorLockState; }
set { doorLockState = value; }
}
doorLockState
如果你是,为什么还要使用这个public
?
问题是这不会将更改的字段标记doorLockState
为“脏”。
但是,由于以下原因,您不应按照其他答案EditorUtility.SetDirty
的建议使用:
从 5.3 开始,随着多场景编辑的引入,该功能不再用于修改场景中的对象。相反,您应该
Undo.RecordObject
在对对象进行更改之前使用。这会将对象的场景标记为脏,并在编辑器中提供撤消条目。
相反,在您的编辑器脚本中,您必须更改doorLockState
.
如果它在private
你必须添加的地方[SerializeField]
[SerializeField] private bool doorLockState;
但在你的情况下,它似乎public
无论如何都会自动序列化。
总是使用正确的SerializedProperty和PropertyField而不是直接在编辑器脚本中操作值!
一开始它看起来更复杂,但它会自动处理 Undo/Redo 之类的东西并自动标记内容(从而保存更改),因此您无需处理其他任何事情:
[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 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();
}
}
}
(当然,该值只会更新OnInspectorGUI
,因此如果您打开了多个 Inspector 选项卡,它只会在悬停时更新)
推荐阅读
- asp.net - 问题,如何查询数据库以按流派 id 浏览专辑?
- django - /accounts/register/get_success_url() 处的 Django 注册类型错误缺少 1 个必需的位置参数:“用户”
- python - 将具有 4 个参数的函数应用于 groupby 对象
- arrays - 来自对象的数组 - Angular 8 / Ionic
- git - 合并两个版本的 bpmn (xml) 文件
- python - 如何加载和运行 TensorFlow 模型
- r - 计算 R 中数据框中具有 1 和 0 的列的行总和,想要 0 之间的连续 1 之间的总和
- amazon-web-services - AWS Mysfits - 无效的 HTTP 端点 API 网关推送
- ruby-on-rails - RecordInvalid,自定义日期验证失败
- java - 使用 Jackson (@JsonValue) 反序列化枚举