Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 CrazyPanda · Mar 24, 2016 at 01:23 PM · prefabmobilestateeditor extension

Save changes (delta) made to prefab in editor as serialized data and apply it later in runtime.

INPUT:

We need to show 100 instances of a prefab on a mobile screen. Prefab consists of (just for example, the real one is a complex UI prefab):

  • Label

  • Sprite1

  • Sprite2

  • Sprite3

Each prefab instance can have 3 base-states:

  1. Label {color: red}; Sprite1 {enabled}; Sprite2 {disabled}; Sprite3 {disabled};

  2. Label {color: blue}; Sprite1 {disabled}; Sprite2 {enabled}; Sprite3 {disabled};

  3. Label {color: green}; Sprite1 {disabled}; Sprite2 {disabled}; Sprite3 {enabled};

Also there is "sub-states" managed by Animator and AnimationClip. This states applicable to all base-states of original prefab because it only animates the process of Collapsing/Expanding of UI Prefab.

  1. Collapsed - Label Only

  2. Expanded - Lablel and Sprite

WHAT WE NEED

Because we have 3 base-states we have to create 3 pools with 100 prefab istances in each. Each pool instantiates own prefab wich represent a base-state but inside they are pretty all same. As you see there is a vast optimisation possibility. We can describe each base-state by code and apply it so we whould have only one pool of 100 prefab instances but it's not handy for production pipeline.

We need to be able to serialize current prefab state and save it in any format and then apply it in runtime. So the workflow of UI programmer and designer should be:

  1. Compose Prefab (create all elements)

  2. Add VisualStateManager component to prefabs' root game object

  3. Set color to label

  4. Hide unused sprites

  5. Leave used sprites enabled

  6. Click "Save as new state" button in a VisualStateManager inspector.

  7. Enter style name

  8. GO TO 3. repeat needed number of times.

Later at runtime programmer will just have to do something like:

 Animator animator =  GetComponent<Animator>();
 VisualStateManager VSM = GetComponent<VisualStateManager>();
 VSM.SetState("Collapsed");
 if(_currentMapZoomLevel > 0.3) {
     animator.Play("CollapsedState")
 }else {
     animator.Play("ExpandedState")
 }

WHAT WE ALREADY TRIED

We tried to create a second layer for animator and 1-frame AnimationClip which could set all needed values in a first frame but mechanim needs avatar so layer could work.. This could be a workaround if only there were a way to make layers work without avatars.

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 lassade · Mar 24, 2016 at 07:53 PM

I was trying to do the same thing by reading the prefab as yaml (Asset serialization changed to text) then cheking for changed attributes base on other template prefab. Btw is far from working ... I can post more if you are interested.

But i guess the ease way is doing a search in the prefab transform tree using:

 void Do (Transform t) 
 {
     var components = t.GetComponents<Component>(); // Gets all components
     Debug.Log (t.name + " (" + components.Length + ")");

     // Use some reflection to get all attributes foreach component
 }

 void ForAllChilds(Transform t) {
     Do(t);
     for (int i = 0; i < t.childCount; i++) {
         ForAllChilds(t.GetChild(i));
     }
 }

Then using some reflection magic to compare and save the results.


BIG EDIT i just got some thing work ! If i have this moths ago it would have saved me a lot of time...

The way this works you need to put two Objects in your scene one the m_Left is the template and the m_Rigth is the changed then run Execute from the context menu and it will give a function that changes the m_Left object into the m_Rigth. For now the generated code can be optimized a lot, and only attributes changes are allowed, like color, text and so on.

For more support add extra functions on m_SaveAs to support Vector3 and Vector2 for instance.

     using UnityEngine;

 using System.Text;
 using System.Linq;
 using System.Reflection;
 using System.Collections;
 using System.Collections.Generic;

 public class SimplerDiff : MonoBehaviour {

     public Transform m_Left;
     public Transform m_Right;

     static List<string> m_IgnoreComponents = new List<string> () {"Transform", "RectTransform", "CanvasRenderer"};
     static List<string> m_IgnorePropsNames = new List<string> () {"name", "onCullStateChanged"};

     static Dictionary<System.Type, System.Func<object, string>> m_SaveAs;

     StringBuilder code;

     static SimplerDiff()
     {
         m_SaveAs = new Dictionary<System.Type, System.Func<object, string>>();
         m_SaveAs.Add(typeof(string), (x) => "\""+x.ToString()+"\"");
         m_SaveAs.Add(typeof(int), (x) => x.ToString());
         m_SaveAs.Add(typeof(float), (x) => x.ToString() + "f");

         m_SaveAs.Add(typeof(Color),
             (x) => {
                 var c = (Color)x;
                 return string.Format("new Color({0}f, {1}f, {2}f, {3}f)", c.r, c.g, c.b, c.a);
             }
         );

         m_SaveAs.Add(typeof(Color32),
             (x) => {
                 var c = (Color32)x;
                 return string.Format("new Color32({0}, {1}, {2}, {3})", c.r, c.g, c.b, c.a);
             }
         );
     }

     [ContextMenu("Execute")]
     void Execute ()
     {
         code = new StringBuilder();
         code.AppendLine("void ChangeTo_" + m_Right.name + "(GameObject go) {");
         ForAllChilds(m_Left, Do);
         code.AppendLine("}");

         Debug.Log(code.ToString());
     }

     void Do (Transform left)
     {
         bool edit1 = false;
         var path = GetGameObjectPath(left, m_Left);
         var right = GameObject.Find(m_Right.name + path).transform;
         foreach(var lmono in left.GetComponents<Component>())
         {
             var type = lmono.GetType();

             if (m_IgnoreComponents.FindIndex(x => type.Name.Equals(x)) != -1) continue;

             var rmono = right.GetComponent(type);

             if (rmono == null)
                 continue;

             var props = type.GetProperties(BindingFlags.Instance|BindingFlags.Public)
                 .Where(x => x.CanRead && x.CanWrite).ToArray();

             bool edit2 = false;
             foreach (var prop in props)
             {
                 if (m_IgnorePropsNames.FindIndex(x => prop.Name.Equals(x)) != -1) continue;
                 
                 var lval = prop.GetValue(lmono, null);
                 var rval = prop.GetValue(rmono, null);

                 if (!lval.Equals(rval))
                 {
                     System.Func<object, string> cast;
                     if (m_SaveAs.TryGetValue(prop.PropertyType, out cast))
                     {
                         if (!edit1)
                         {
                             code.AppendLine("\t{");
                             if (string.IsNullOrEmpty(path))
                             {
                                 code.AppendLine("\t\tvar child = go.transform;");
                             }
                             else
                             {
                                 // ignore the frist / in the path
                                 code.AppendLine(string.Format("\t\tvar child = go.transform.Find(\"{0}\");", path.Substring(1)));
                             }
                             edit1 = true;
                         }
                         
                         if (!edit2)
                         {
                             code.AppendLine("\t\t{");
                             code.AppendLine(string.Format("\t\t\tvar c = child.GetComponent<{0}>();", type.Name));
                             edit2 = true;
                         }
                         
                         code.AppendLine(
                             string.Format("\t\t\tc.{0} = {1};", prop.Name, cast(rval))
                         );
                     }
                 }
             }

             if (edit2)
             {
                 code.AppendLine("\t\t}");
             }
         }

         if (edit1)
         {
             code.AppendLine("\t}");
         }
     }

     void ForAllChilds(Transform transform, System.Action<Transform> map) {
         map(transform);
         for (int i = 0; i < transform.childCount; i++) {
             ForAllChilds(transform.GetChild(i), map);
         }
     }

     private string GetGameObjectPath(Transform transform, Transform top)
     {
         string path = "";

         while (top != transform && transform.parent != null)
         {
             path = "/" + transform.name + path;
             transform = transform.parent;
         }

         return path;
     }
 }
Comment
Add comment · Show 4 · 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
avatar image CrazyPanda · Mar 24, 2016 at 11:44 PM 0
Share

Reflection is really slow on mobile devices in case of applying saved states in runtime for 100 prefabs ( Even if you do something like type chache.

avatar image lassade CrazyPanda · Mar 25, 2016 at 02:23 AM 0
Share

The reflection is just to check for differences between your gameObjects you can then generate a c# script with the difference info that sets all values if needed.

avatar image lassade CrazyPanda · Mar 25, 2016 at 03:08 AM 0
Share

I just finish a proof of concept of what i said above, im posting here.

avatar image lassade CrazyPanda · Mar 25, 2016 at 07:24 AM 0
Share

I made a nice project with a sample and improved code. Now code generation is working with a press of a button. Each diff generate a static function inside a static partial class that can be called from anyhere.

Sorry the flood of messages, I am with insomnia.

Check my repo https://github.com/lassade/Unity3D-Godiff pull requests are welcome.

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

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Created Prefab is not preserving original GameObject attributes 0 Answers

Extract a Tree layout in text of the UI Prefab 1 Answer

How to make mobile controls shoot prefab bullets 0 Answers

Editor : dynamic asset creation and prefabs, best practice ? 1 Answer

Prefab instantiated wrong scale on mobile 0 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