Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by JonS · Oct 30, 2014 at 08:28 PM · arraynguipropertydrawer

How do PropertyAttribute instances work in an array of structs?

So I've been wrestling with this problem pretty much all day to no avail. I'm trying to make a spritename PropertyDrawer for NGUI sprites so I don't have to write them in by hand and it's almost working fully now except in this one instance.

The PropertyDrawer and PropertyAttribute are as follows:

 public class SpriteNameAttribute : PropertyAttribute {
     public UIAtlas atlas;
 }

and

 [CustomPropertyDrawer(typeof(SpriteNameAttribute))]
 public class SpriteNamePropertyDrawer : PropertyDrawer {
     private SpriteNameAttribute _attributeValue = null;
     private SpriteNameAttribute attributeValue {
         get {
             if (_attributeValue == null) {
                 _attributeValue = (SpriteNameAttribute) attribute;
             }
             return _attributeValue;
         }
     }
 
     public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
     {
         // Double the default height if we're showing the error box. Annoyingly can't figure out how to calculate an exact height that accounts for word wrapping in the HelpBox
         if(property.propertyType != SerializedPropertyType.String) {
             return 32;
         } else {
             return base.GetPropertyHeight (property, label);
         }
     }
 
     public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) {
         // Show the prefix label
         label = EditorGUI.BeginProperty(position, label, prop);
         Rect contentPosition = EditorGUI.PrefixLabel(position, label);
 
         // Leave if we're not dealing with a string
         if(prop.propertyType != SerializedPropertyType.String) {
             EditorGUI.HelpBox(contentPosition, "[SpriteNameAttribute] may only be used on string values", MessageType.Error);
             return;
         }
 
         contentPosition.width = (contentPosition.width - 10) * 0.5f;    // Divide the content width in half for the two buttons minus a 10px spacer
         EditorGUI.indentLevel = 0;
 
         // Show atlas selector button. Name it according to whatever's currently selected
         if (GUI.Button(contentPosition, (attributeValue.atlas != null) ? attributeValue.atlas.name : "<select atlas>")) {
             // Show the componenet selector. Use a Lambda expression for the callback that calls SetDirty so the inspector is redrawn as soon as an atlas is selected.
             ComponentSelector.Show<UIAtlas>(x => { 
                                                 attributeValue.atlas = (UIAtlas)x; 
                                                 EditorUtility.SetDirty(prop.serializedObject.targetObject); 
                                                });
         }
 
         // Shift the content position forward by the button width + 10px spacer
         contentPosition.x += contentPosition.width + 10;
 
         // Only show this button if an atlas is selected or there's already a sprite name set
         if(attributeValue.atlas != null || !prop.stringValue.Equals("")) {
             if(GUI.Button(contentPosition, (!prop.stringValue.Equals("")) ? prop.stringValue : "<select sprite>")) {
                 // Set NGUI's static variables so the proper sprite is selected in the SpriteSelector when it's shown
                 NGUISettings.atlas = attributeValue.atlas;
                 NGUISettings.selectedSprite = prop.stringValue;
 
                 // Have to use a Lambda expression here since the property value is only visible in this method. Saving it to a member variable and changing that in a callback function DOESN'T WORK.
                 SpriteSelector.Show(x => { 
                                         prop.stringValue = x; 
                                         prop.serializedObject.ApplyModifiedProperties(); 
                                     });
             }
         }
 
         EditorGUI.EndProperty();
     }
 }

That works perfectly fine for simple public string members and arrays of strings, however I'm now trying this:

 public Breakable[] breakables;
 
 [System.Serializable]
 public struct Breakable {
     [SpriteNameAttribute]
     public string wholeSprite;
     [SpriteNameAttribute]
     public string topSprite;
     [SpriteNameAttribute]
     public string bottomSprite;
 }

And I'm seeing something bizzarre. Everything draws fine, but when I select an atlas for one of the members ALL instances of that member in the array get set to that value.
E.G. Selecting Game08ReferenceAtlas for the wholeSprite in the first Breakable object sets every wholeSprite's atlas in the entire array to Game08ReferenceAtlas like the picture below.

alt text

So my question is this: How are the PropertyAttribute objects instantiated for an array like this? You would think that each property to be drawn would create its own instance of the SpriteNameAttribute to reference the atlas from, but it appears that every instance of Breakable in the array is sharing the same three instances of SpriteNameAttribute for the three members.

Am I missing something simple here or is it just a case of trying to use a PropertyDrawer for more than it was meant to do? It's not an essential fix since I usually want to use all the same atlas anyway but it's driving me crazy trying to figure out why this is happening and would be useful if I want to mix sprites from my game and ui atlases.

screen shot 2014-10-30 at 3.07.30 pm.png (56.8 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by burtonposey · Sep 24, 2016 at 12:18 AM

I know this is way late, but I just fixed this bug in my own code.

I don't understand why this is, but I believe the problem is that every element in your array is using the same private variables in your property drawer. I based my code off of some I inherited and when I made an array of the objects that utilized the property drawer, they all started getting the same values.

The solution is to find a way to manage the state without storing anything inside of the PropertyDrawer class. Once you stop doing that, you should find that you no longer are seeing a replication of values for all members in your collection.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

SerializedProperty isn't being detected as an array? 1 Answer

How to prevent overlap when using nested arrays in CustomPropertyDrawers? 1 Answer

EditorGUI.IntField always 0 after GameStart 0 Answers

Custom Editor/Custom Property Drawer combo, breaks Enable button 1 Answer

Custom PropertyDrawer for attributes on array members 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges