Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 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 /
  • Help Room /
avatar image
0
Question by harrymuana · Feb 18, 2016 at 11:48 AM · prefabruntimenotchangesoverwrite

How to discard changes to prefabs at runtime?

So say I have a cube prefab. GameObject A Instantiates this prefab, and later modifies it's properties at runtime, eg double it's local scale. This means that every further cube spawned will be bigger, which is great.

However, when I stop running my scene, the prefab has been overwritten! I thought that

a) the prefab was passed as a copy so if I had another gameobject B that made the prefab smaller, he could spawn his smaller copies without affecting the copies that gameobject A spawns and

b) changes during runtime do not get saved, so you can play with values during runtime as much as you want without them being overwritten.

So now both of these seem to be false... How would you get the desired results?

Comment
Add comment · Show 3
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 meat5000 ♦ · Feb 18, 2016 at 11:48 AM 2
Share

B is only true of things that exist within the hierarchy I do believe.

For example, Animator State $$anonymous$$achine files wont revert either. They dont live in the hierarchy.

Consider that changes to 'physical' files themselves can not be reverted. If you rewrite a script during playmode that wont revert either, right? Its the same logic for anything that modifies a file in that way.

avatar image harrymuana meat5000 ♦ · Feb 18, 2016 at 12:04 PM 0
Share

So is there a way to pass the prefab as a copy so multiple objects can edit their own prefab copy and instantiate a different one?

avatar image Bunny83 harrymuana · Feb 18, 2016 at 12:12 PM 1
Share

Unfortunately, no. prefabs are just like ordinary gameobject with a special "state". They simply aren't visible in the scene and don't get any callbacks from the engine. It is not possible to manually create an object with that "state" at runtime. Prefabs are an editor feature. The moment you instantiate the prefab the object get "cloned" but that special state is "removed" so the cloned object will be part of the scene. You can also use Instantiate to clone other gameobjects in the scene as well. Instantiate is just a "CreateClone" function.

As i said in my answer, it's not recommended to change anything inside prefabs as those changes can't be reverted, only by restarting the application.

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Bunny83 · Feb 18, 2016 at 12:06 PM

As meat5000 said, this is only an issue when testing in the editor. Direct changes to assets will persist. If you build the game and run the standalone version, you can still change the prefab, but the changes aren't permanent as the compiled game files can't be changed. When you restart the build game (literally quite the game and restart it) everything is back to what it was originally when you build the game.

In general changing assets at runtime is not a good solution. It's always better to use some kind of variables to control those changes and only appliy those changes to actual gameobject and not prefabs.

Example:

 float cubeSize = 1.0f;
 Transform cubePrefab;
 
 Transform CreateCube()
 {
     Transform cube = (Transform)Instantiate(cubePrefab);
     cube.localScale *= cubeSize;
     cubeSize *= 2;
     return cube;
 }

Here everytime you call "CreateCube" a new instance of your cubePrefab is created. We scale that instantiated object by the current cubeSize variable after it's instantiated and in addition we double the cubeSize variable each time.

That way you can simply set cubeSize back to "1.0f" and new cubes will restart at size 1.

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 harrymuana · Feb 18, 2016 at 08:28 PM 0
Share

Allright, thanks a lot!

avatar image Xtro · Jan 11, 2017 at 03:30 PM 0
Share

Unfortunately this is a bad answer. Applying modifications each time a prefab instantiated is very bad approach for both performance and software quality. The modification may be very complex so applying it for hundreds of instances at instantiation time may be extremely costly compared to Unity's automated serialization instantiation.

The problem which harrymuana described is very valid and very common use case.

I still don't have the solution but I will find one. That's why I ended up in this page.

avatar image Xtro Xtro · Jun 19, 2017 at 02:58 AM 0
Share

I finally had time to implement a "reset prefab changes which are applied during play mode in editor" system. See my answer below.

I would be happy if you change the accepted answer because of the reasons I posted in my earlier comment above.

Please let me know if you can't make my solution to work. There may be typo in my post.

avatar image Mazer83 · Jul 22, 2017 at 10:40 PM 0
Share

As long as you Instantiate, and make your changes to the Instance (not the prefab itself), you should be fine.

I think this answer needlessly complicates things by having a cubeSize variable, keeping track of it, resetting it, etc.. which could be confusing for other people reading this.

create your object.

 GameObject objInstance = Instantiate(prefab);

Change its scale

    objInstance.GetComponent().localScale *= 2;

that's it. (You can also do it with a Transform prefab like Bunny83 did).

avatar image
0

Answer by ddas · Jan 22, 2017 at 11:07 PM

Unity Editor should not change the prefab object properties at runtime. It is very annoying to manually revert the prefab properties that changes at runtime during testing.

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
avatar image
0

Answer by Xtro · Jun 19, 2017 at 02:54 AM

Here is how I did it:

How to use

 // Implement IExitPlaymodeHandler interface in your script (the one you will add to your prefab).
 public abstract class Widget : MonoBehaviour, IExitPlaymodeHandler
 {
     // Implement your class here as you wish.
     // ...

     // Implement ExitPlaymode method of IExitPlaymodeHandler interface
     public virtual void ExitPlaymode()
     {
         //-------->     Do your reset work here.  <-------
         // For example: if you changed the scale of prefab in play mode, reset it here.
         transform.localScale = Vector3.one;
     }
 }

  • You must register your prefab to the system in play mode so call this anywhere you want (Probably in your game's initialization)

            if (Application.isEditor) ExitPlaymodeSender.Register(MyWidgetPrefab);
    
    
  • When you stop play mode in editor, ExitPlaymode method on the prefab you registered earlier will be called and you will be able to reset your changes.


The system I implemented for it to work:

     public interface IExitPlaymodeHandler
     {
         void ExitPlaymode();
     }

     // This static class is responsible for storing the registered ExitPlaymode handlers and notify them when exited the play mode.
     public static class ExitPlaymodeSender
     {
         static readonly List<IExitPlaymodeHandler> Handlers = new List<IExitPlaymodeHandler>();
 
         public static void Register(IExitPlaymodeHandler Handler)
         {
             if (!Application.isEditor) throw new System.NotSupportedException(Strings.ExitPlaymodeSender);
 
             if (!Handlers.Contains(Handler)) Handlers.Add(Handler);
         }
 
         internal static void Send()
         {
             foreach (var Handler in Handlers)
             {
                 Handler.ExitPlaymode();
             }
 
             Handlers.Clear();
         }
         static bool RestoreScheduled;
 
    #if UNITY_EDITOR
         internal static void EditorApplication_PlaymodeStateChanged()
         {
             // If user pressed stop button.
             if (EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode) RestoreScheduled = true;
 
             if (!EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode && RestoreScheduled)
             {
                 RestoreScheduled = false;
 
                 Send();
             }
         }
     #endif
     }

     // This static class is responsible for listening to Unity's EditorApplication.playmodeStateChanged event.
     [InitializeOnLoad]
     static class Initializer
     {
         static Initializer()
         {
    #if UNITY_EDITOR
             EditorApplication.playmodeStateChanged += ExitPlaymodeSender.EditorApplication_PlaymodeStateChanged;
     #endif
         }
     }






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 Mazer83 · Jul 22, 2017 at 10:43 PM 0
Share

Why bother with all that? Why not just Instantiate your prefab, and make your changes to the instance? Don't ever make changes to a prefab directly in script.

avatar image Xtro Mazer83 · Jul 22, 2017 at 11:10 PM 0
Share

Yes, I am aware of this option but sometimes it doesn't suffice the need.

If you make changes on small number of prefabs in runtime and if those prefabs belongs to your game project, you can choose this option, yes.

If you are making changes to lots of prefabs or if you are a 3rd party asset developer who is dealing with prefabs which don't belong to the customer's game project, things get complicated very fast.

By coincidence, I was just trying to improve my implementation when you commented to it just now. I'll update my answer if I can think of a better and simple way. I'll think about instancing the prefabs even when working on a 3rd party asset project.

avatar image tessellation Xtro · Jul 26, 2017 at 05:38 PM 0
Share

If you're worried about performance of modifying hundreds of properties, it would be cleaner to instantiate a prefab to create template GameObjects that you modify and use to instantiate your final instances. Any GameObject can be instantiated, not just prefabs.

Even better would be to create a pool of objects with the correct properties and just reuse them. The performance of instantiating game objects in general is really poor and probably far outweighs the cost of modifying a few properties.

Show more comments

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

9 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

I have two Background Prefab. I want to generate and spawn them at Rutime in alternative ways..like Bg1..Bg2..Bg1..Bg2....thats way. Also in smooth manner. This will happen in canvas only... I will give my code following....Please suggest me... 0 Answers

See what changes has been made to a prefab. 0 Answers

Save gameobject from imported mesh (with imported texture) as prefab/resource at runtime. 0 Answers

Applying prefabs 0 Answers

How to detect if any prefab is instantiated in the scene from a script? 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