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 HassanKhallouf · Aug 02, 2018 at 08:46 PM · inspectorserializationserializabledesign-patterns

Serializable class with access to its Monobehaviour host

Hello everyone, I'm trying to create a Serializable class to be used in the inspector, I need to access the hosting monobehaviour for this class, but sense it's created by unity and serialized automatically you can't make use of custom constructors to pass what you want.

I will give you a simple example, I'm making a multipier system for damage and so, the multiplier is not just a number but a class that has functionality, limits, some calculations method fit for the game

 [Serializable]
 public class Multiplier
 {
     private float val = 1.0f;
     private Action<MonoBehaviour> action;
 
     public float Value
     {
         get { return val; }
         set
         {
             val = value;
             action?.Invoke(theMono);
         }
     }
 }

the multiplier can be basically used for anything and it can be put inside any monobehaviour, the multiplier has an event to announce that its value has changed but I need to send the changing monobehaviour with the event, as the value alone is useless

another example is that I'm making inventory with serializable class InventorySlot, that has custom property drawer and so, I need to invoke inventory updated event when the slot changes, but the slot doesn't have access to the inventory

is there a way to achieve this?

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

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Aug 02, 2018 at 11:01 PM

That is simply not possible. A class instance is a standalone object. It may be referenced by several variables of different objects. There is no "owner". If you actually want a two way relationship you may want to make a component out of your class.


Another option is to pass the object reference you're interested in as parameter. Of course you can't use a property in that case but have to use an explicit method.


Finally you could implement the ISerializationCallbackReceiver in the hosting class and just set a field in your Multiplier instance in OnAfterDeserialize.


Though i still don't quite understand the usage of that class. Keep in mind that custom serializable classes do not support inheritance when it comes to serialization. So what is the point of a seperate class here? Who is subscribing to your "action"? Doesn't a closure work just fine? How do you subscribe to action?

Comment
Add comment · Show 1 · 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 HassanKhallouf · Aug 02, 2018 at 11:29 PM 0
Share

thank you for your answer, I should have probably name the action to make it clear, it's supposed to be an event for "On$$anonymous$$ultiplierChanged", for example I can use it as character.$$anonymous$$eleeDamage$$anonymous$$ultiplier.On$$anonymous$$ultiplierChanged += DoSomething

the ISerializationCallbackReceiver solution seems good, I'll try it, but this will have to be on a defined type like in my inventory example, but the multiplier can be added to many other scripts

this really help, thank you very much

avatar image
1

Answer by JVene · Aug 02, 2018 at 11:09 PM

While I'm not 100% certain I fully understand all that you require, it seems you have two problems to solve.


First, since you can't create a custom constructor, you can't obtain a linkage between the owning MonoBehaviour and these classes, be it slot, multiplier or whatever. You already realize there's no way to discover an instance automatically (how could one know what instance to find), you have to break this deadlock by using an initialization in Awake or Start of the MonoBehaviour, where you can perform what I'll call post construction - that which you would have performed by using a custom constructor for Multiplier, but must do so when MonoBehaviour can do that for you. You could only perform some form of lazy initialization of the connection between multiplier and the owning class is if it were a singleton, and could be discovered from a static value lazily initialized.


Since that's not an option, you have to use Awake or Start, or some other lazy initialization means discovered from the MonoBehaviour that owns these objects.


That said, I'll turn to the function call from within the multiplier, slot or whatever class must "callback".


You could pass "this" from MonoBehaviour to multiplier, which would give it an instance upon which to call any member of the MonoBehaviour derivative. That assumes the function is always the same, but the generic nature of multiplier suggests this function is different for each use. For that you should consider a delegate. A delegate combines the notion of an instance and the member function to be called. It appears like a member variable you set, but calls like a function. Google provides.

Comment
Add comment · Show 3 · 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 HassanKhallouf · Aug 02, 2018 at 11:38 PM 0
Share

thank you for your answer, I thought about the tantalizer already, but the problem is the size of the inventory is dynamic, it grow or shrink in the game, also I could add more slots for at run-time for testing and I can drop items in in it from the inspector, so if I increased the array size at run-time the start function won't help here.

Also in the multiplier case it can be hosted in different scripts, so probably the delegate is fine, but I'm trying to be more generic in the solution,but as you can see they are 2 different problems, delegates might work for one but not for the other

for example, when I drop an item in an inventory slot it's added correctly but the inventoryUpdated event won't be fired, because it was passed to the slot directly not through the inventory class (usually inventory.AddItem() should fire the event)

this was really helpful, thanks

avatar image JVene HassanKhallouf · Aug 03, 2018 at 01:07 AM 0
Share

I have no idea what a tantalizer is ;)

You should be aware that we can only answer based on the information in the question, and the notion of a callback via delegate requires some design with respect to placement. Indeed, most of object oriented development is about decided what does something, where that code belongs. If, for example, you're creating inventory items in code at runtime, that is rather obviously the moment in which a delegate could be paired, since it isn't co$$anonymous$$g from strea$$anonymous$$g during initialization. However, since the inventory may be a large number of items, it may be more appropriate for the operating container to control the notification by insisting that such updates go through the container manager which then provides the callback, rather than make the callback come from the inventory item. That is to say, the notion that something should be passed to the slot directly is questionable design, because it allows a bypass of control. Where the multiplier refers to different classes (the word scripts is not known in C# program$$anonymous$$g, a script is just a text file, the class is the key concept), you may want to make the multiplier class a generic so it can automatically adapt to any class and any relevant function in that class.

avatar image HassanKhallouf JVene · Aug 03, 2018 at 10:12 AM 1
Share

I meant Initializer not tantalizer

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

93 People are following this question.

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

Related Questions

Error when trying to Serialize a field that is in a class 0 Answers

Public fields not showing in inspector 2 Answers

Help with editor serialization 1 Answer

Custom Editor: Weird reset when clicking Play 1 Answer

How do I make child classes in a list editable from the Inspector? 1 Answer


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