正确设置Unity SerializedProperty值
我正在使用IronPython在Unity3d项目中执行(仅编辑器)清理工作。除了一个恼人的陷阱之外,这个工作很好。正确设置Unity SerializedProperty值
我有一个Python包装类,隐藏使用SerializedProperties的C#冗长:
class PropertyProxy(object):
PROPTYPES = {
SerializedPropertyType.Integer:"intValue",
SerializedPropertyType.Boolean:"boolValue",
SerializedPropertyType.Float:"floatValue",
SerializedPropertyType.String:"stringValue",
SerializedPropertyType.Color:"colorValue",
SerializedPropertyType.ObjectReference:"objectReferenceValue",
SerializedPropertyType.LayerMask:"objectReferenceValue",
SerializedPropertyType.Enum:"enumValueIndex",
SerializedPropertyType.Vector2:"vector2Value",
SerializedPropertyType.Vector3:"vector3Value",
SerializedPropertyType.Vector4:"vector4DValue",
SerializedPropertyType.Rect:"rectValue",
SerializedPropertyType.ArraySize:"arraySize",
SerializedPropertyType.Character:"objectReferenceValue",
SerializedPropertyType.AnimationCurve:"animationCurveValue",
SerializedPropertyType.Bounds:"boundsValue",
SerializedPropertyType.Gradient:"objectReferenceValue",
SerializedPropertyType.Generic:"objectReferenceValue"
}
def __init__(self, owner):
self.owner = owner
self.prop_path = self.PROPTYPES[owner.propertyType]
def __repr__(self):
return self.owner.serializedObject.targetObject.name +"." + self.owner.propertyPath
@property
def value(self):
if self.owner.isArray:
return []
else:
return getattr(self.owner, self.prop_path)
@value.setter
def set_value(self, val):
setattr(self.owner, self.prop_path, val)
self.owner.serializedObject.ApplyModifiedProperties()
的get
功能工作正常,并返回正确的价值观。然而,二传手抱怨道。如果您尝试设置PropertyProxy
的值,我会收到一条错误消息,声称我正试图设置只读属性。没有问题
myPropertyProxy.owner.floatValue = 2.0
,但是当设置器试图做
setattr (myPropertyProxy.owner, 'floatValue', 2.0)
我得到的错误: - 这不是完全正确的,我可以做到这一点。
我认为这是IronPython无法获得Unity侧属性的正确setter的某种问题,但我只是猜测。有人有更多的信息在这里发生了什么?
更新
直接发行
setattr(myProp.owner, 'floatValue', 2.0)
myProp.owner.serializedObject.ApplyModifiedProperties()
- 这是外类 - 工程。哎呀。
更新2 如果你叫他们没有财产装饰:(
原来的问题原来是准红鲱鱼;上面贴的代码工作,如果你转换
@property
def value(self):
if self.owner.isArray:
return []
else:
return getattr(self.owner, self.prop_path)
@value.setter
def set_value(self, val):
setattr(self.owner, self.prop_path, val)
self.owner.serializedObject.ApplyModifiedProperties()
到比较老套:
def _value(self):
if self.owner.isArray:
return []
else:
return getattr(self.owner, self.prop_path)
def _set_value(self, val):
setattr(self.owner, self.prop_path, val)
self.owner.serializedObject.ApplyModifiedProperties()
value = property(fget = _value, fset = _set_value)
我认为这代表其执行@property装饰的CPython的和IronPython之间的分歧,因为在普通的CPython两者是可以互换的。
我不能肯定完全明白你正在尝试做的,反正谈到SerializedProperty的value
和set_value
职能的工作。
当你想设置的SerializedProperty
(通常编写自定义代码检查员)的值,你有几种方法:
- 使用PropertyField自动默认风格通过
SerializedProperty
显示它 - 访问现场和反序列化回SerializedObject(比如你的方法)使用EditorGUI.[Begin|End]Property
- 直接接入序列化领域
- 裹SerializedProperty访问。
现在,每种方法都取决于特定的用例,并最终带来其缺点。要记住的主要原因是[de]序列化过程由不同的线程处理,需要知道在反序列化之前哪个SerializedProperty
已被修改。
所以你的情况(如果我理解正确的话),你需要至少2个函数调用,以使它在任何情况下工作:
- 调用(视情况而定或UpdateIfDirtyOrScript)Update在修改任何财产之前。这确保您指的是一致的
SerializedObject
状态。 - 修改
SerializedProperty
(就像你正在做)(在你的更新等) - 呼叫
serializedObject.ApplyModifiedProperties
我认为这是某种形式的问题与IronPython的是不能 得到正确的二传手在Unity方面属性,但我只是 猜测。有人有更多的信息在这里发生了什么?
我不知道很多关于Python的,所以我没有一个明确的答案,但也许这是关系到一个事实,即二传手的floatValue和referes外部函数(可能在发动机的C++侧):
public extern float floatValue
{
[WrapperlessIcall]
[MethodImpl(MethodImplOptions.InternalCall)]
get;
[WrapperlessIcall]
[MethodImpl(MethodImplOptions.InternalCall)]
set;
}
感谢您的回复!这里的总体目标是允许我自己对大量游戏数据(主要是ScriptableObjects)进行批量编辑 - 诸如“找到所有精灵的生命值为5并将其设置为6'。 我一直在解决即时问题,将我的属性装饰器转换为常规方法调用;我认为这必须是某种IronPython cPython delta,我以前没有见过。然而'UpdateIfDirtyOrScript'事是我之前从未见过的,这可能解释了我在其他情况下遇到的一些问题。 – theodox 2014-10-09 16:37:00
一个相关的问题:对于磁盘上的资产,是否有可能只使用传统的C#反射并根本不更改SerializedProperty系统的值? – theodox 2014-10-09 16:38:03
对于磁盘上的资产,您可以简单地编辑文件(如果以文本形式存储),元文件(例如用于预制件)以及最终用于预制覆盖属性的场景文件。我认为这将是单调乏味的,因为您需要解析yaml通过你自己,并尽量保持资产交叉引用consistents。 – Heisenbug 2014-10-09 17:02:28