2014-10-08 924 views
1

我正在使用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 如果你叫他們沒有財產裝飾:(

回答

0

原來的問題原來是準紅鯡魚;上面貼的代碼工作,如果你轉換

@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兩者是可以互換的。

2

我不能肯定完全明白你正在嘗試做的,反正談到SerializedPropertyvalueset_value職能的工作。

當你想設置的SerializedProperty(通常編寫自定義代碼檢查員)的值,你有幾種方法:

  • 使用PropertyField自動默認風格通過SerializedProperty顯示它
  • 訪問現場和反序列化回SerializedObject(比如你的方法)使用EditorGUI.[Begin|End]Property
  • 直接接入序列化領域
  • 裹SerializedProperty訪問。

現在,每種方法都取決於特定的用例,並最終帶來其缺點。要記住的主要原因是[de]序列化過程由不同的線程處理,需要知道在反序列化之前哪個SerializedProperty已被修改。

所以你的情況(如果我理解正確的話),你需要至少2個函數調用,以使它在任何情況下工作:

  1. 調用(視情況而定或UpdateIfDirtyOrScriptUpdate在修改任何財產之前。這確保您指的是一致的SerializedObject狀態。
  2. 修改SerializedProperty(就像你正在做)(在你的更新等)
  3. 呼叫serializedObject.ApplyModifiedProperties

我認爲這是某種形式的問題與IronPython的是不能 得到正確的二傳手在Unity方面屬性,但我只是 猜測。有人有更多的信息在這裏發生了什麼?

我不知道很多關於Python的,所以我沒有一個明確的答案,但也許這是關係到一個事實,即二傳手的floatValue和referes外部函數(可能在發動機的C++側):

public extern float floatValue 
{ 
    [WrapperlessIcall] 
    [MethodImpl(MethodImplOptions.InternalCall)] 
    get; 
    [WrapperlessIcall] 
    [MethodImpl(MethodImplOptions.InternalCall)] 
    set; 
} 
+0

感謝您的回覆!這裏的總體目標是允許我自己對大量遊戲數據(主要是ScriptableObjects)進行批量編輯 - 諸如「找到所有精靈的生命值爲5並將其設置爲6'。 我一直在解決即時問題,將我的屬性裝飾器轉換爲常規方法調用;我認爲這必須是某種IronPython <> cPython delta,我以前沒有見過。然而'UpdateIfDirtyOrScript'事是我之前從未見過的,這可能解釋了我在其他情況下遇到的一些問題。 – theodox 2014-10-09 16:37:00

+0

一個相關的問題:對於磁盤上的資產,是否有可能只使用傳統的C#反射並根本不更改SerializedProperty系統的值? – theodox 2014-10-09 16:38:03

+0

對於磁盤上的資產,您可以簡單地編輯文件(如果以文本形式存儲),元文件(例如用於預製件)以及最終用於預製覆蓋屬性的場景文件。我認爲這將是單調乏味的,因爲您需要解析yaml通過你自己,並儘量保持資產交叉引用consistents。 – Heisenbug 2014-10-09 17:02:28