Search Unity

[Open Source] VFW (135): Drawers. Save System and full exposure

Discussion in 'Assets and Asset Store' started by vexe, Sep 2, 2014.

  1. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @Lerzpftz yes what you said is correct. I'll check out those attributes, sounds interesting to say the least. And thanks.
     
  2. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Well, another day another serializer :D - BinaryX 2.0 in the hizhouse. A binary reflection-based serializer I just wrote yesterday. The genius part is that we totally skip 1.0 lol. I'll be toying around with it alone before releasing it, not even sure about the name but it sounds fun, looks promising though:



    (@Lerzpftz you can see the lag I was talking about...) The idea is to stay flexible with types, support most common types out of the box, don't be rigid (request types upfront) but still let the user add his own strongly-typed serializers, which is very useful if you're dealing with a complex structure that has value-types involved (which means boxing/unboxing) - In my case I had a Item[], an item is a Dictionary<string, GameProperty>, GameProperty is a struct that holds a float, enum and string. So I configure the serializer to add a strongly-typed dictionary serializer specifically to handle Dictionary<string, GameProperty> - the read/write methods for key/value are injected when adding the serializer like you see in the video. Still can't beat FastSerializer speed-wise tho, daym! I'm pretty sure I can go faster with this new one, there's still many room for optimizations, just gotta be correct first.
     
    Last edited: Jun 6, 2015
  3. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    1.3.3 Is here, with a decent number of fixes/improvements.

    Last time I've been flip-flopping about serialization, using different serializers, wasn't sure what direction to settle in. I've decided that the best serializer to persist changes between editor/playmode is Unity's serializer! Yes, Unity's default serialization system, believe it or not... For a couple of a reasons:

    1. It's fast, and more robust/reliable in the long run. Other serializers are either slow/generates garabge (FullSerializer), not flexible enough for the framework needs (custom attributes, serialization logic etc, like protobuf-net) or just not mature enough yet, change of layout happens often, not good for framework usage yet (the serializers I wrote (FastSerializer and BinaryX20)
    2. Its limitations are not deal-breakers. Let's take public auto-properties for example, why not just use a public field instead? it's practically the same from the usage standpoint, fields are faster anyways. Properties with side effects: Just serialize their backing field instead. Generics: just create serializable subclasses. Polymorphic types: Just don't use polymorphism! I don't have a single polymorphic field in any of my game scripts. Yes, as bold as that sound I've come to the realization that OOP and all its terminology and ideology are bad, very bad especially in game development. They drastically over-complicate things, drive the focus away from the real problem (data) into things so abstract that exit in a fantasy rosy world (objects). I will stop ranting, and maybe make a video about this, discussing some of the much more powerful and flexible data designs.
    Vfw was initially about custom drawing, then I added custom serialization on top. From that time it has always been that those two things are combined into BetterBehaviour. So for this reason and the things we talked about, we now have BaseBehaviour/ScriptableObject = Vfw editor power, and BetterBehaviour/ScriptableObject = Vfw editor + serialization power. So if you ever need Vfw editor stuff but not any custom serialization (uses Unity's serialization) use BaseBehaviour. This is what I would recommend as the standard initial base to inherit from in your scripts. If you ever need something from BetterBehaviour, think twice about, do you really need it? can you live with Unity's serialization and work-around the limitations you're having in a minimalistic/ideal fashion, other than using custom serialization?... - One of the limitations I faced in my game were dictionaries, so I did this.

    The only custom serializer left now is FullSerializer. The binary ones I wrote will be used in FastSave, which I promise I will release very soon.
     
    Last edited: Jul 1, 2015
  4. snw

    snw

    Joined:
    Mar 13, 2014
    Posts:
    42
    Hi vexe,

    my question is more a general one, but may be related to Vfw:
    I want to save references to GameObjects in a ScriptableObject. As Unity destroys/rebuilds all objects when recompiling, there seems no "native" way to do this.

    Is Vfw capable of doing this kind of stuff? If not, maybe you know some kind of workaround?

    Cheers.
     
  5. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @snw could you give me more details/context? are those GameObjects living in the scene? is your ScriptableObject an asset?
     
  6. snw

    snw

    Joined:
    Mar 13, 2014
    Posts:
    42
    Yes, I mean scene GameObjects and ScriptableObject assets.
     
  7. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @snw AFAIK you simply can't make assets (persistent) objects reference scene (non-persistent) objects. Like you said Unity rebuilds the scene with new GameObjects that has memory addresses different than the ones were before.

    What you can do however, is to add some sort of "Id" component on your gameObjects, (the id is persistent/serialized), and look them up that way instead of storing direct references of them. The Id could be a string (guid) or an int generated in one way or another (like Vfw's BaseBehaviour 'id' in GetPersistentId). You would have to have something in your ScriptableObject editor that accepts drags from scene so you can do a GetComponent and get the Id of that gameObject. Let me know if that works for you, and whether or not you need more help.
     
  8. snw

    snw

    Joined:
    Mar 13, 2014
    Posts:
    42
    Yes, already thought about an uid approach.
    I guess I have to go this route then.

    Thanks.
     
  9. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    Is there a recommended procedure to update to 1.3.3? I'm using the default serialization mechanism that came with deriving from BetterBehaviour. I don't need any specialized serialization, meaning I'm fine with whatever the default happens to be. Do I just need to derive from BaseBehaviour now instead?
     
  10. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @blizzy You don't have to derive BaseBehaviour, but it will make things simpler. BetterBehaviour serialization has not changed. But your data 'might' break if you switch to BaseBehaviour. If you don't have a lot of data, or if you have your data in file, or it doesn't take a lot to set things up again then just go for BaseBehaviour. You could give it a test: setup a Test script, inheriting BetterBehaviour, setup some data and then switch to BaseBehaviour, see if the data is gone.
     
    Last edited: Jul 2, 2015
  11. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
  12. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    So does this library only work with inheritance? I am asking because I am using UNET which means all my objects are derived from NetworkBehaviour

    Would something like this be possible?

    Code (CSharp):
    1. [VFW]
    2. class Foo: NetworkBehaviour{..}
    3.  
     
  13. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Hey there. Unfortunately this is currently not possible. However; I've had this sort of problem in my mind when I designed the system and I knew eventually a user with your needs would pop up.

    I do have an idea in mind, to make my editors target MonoBehaviour instead of BaseBehaviour, but only when the script is marked with, say [VFW] like in your example. Otherwise I'd draw the script with whatever editor is specified for its runtime type (via Editor.CreateEditor), I'll give that a try and let you know.

    But keep in mind even if this works, it'll probably only work to give you Vfw editor capabilities, and not custom serialization.
     
    Last edited: Jul 16, 2015
  14. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @maikklein scratch that idea, with the current way Unity assigns editor to scripts the idea is not applicable

    Here's what you can try: if NetworkBehaviour already has an Editor script make it inherit BaseEditor.cs - if it doesn't have an editor, well problem solved: just create a NetworkBehaviourEditor and derive from BaseEditor.cs (this is how BaseBehaviourEditor.cs is basically implemented)

    Let me know if that works.
     
    maikklein likes this.
  15. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    Hey thanks for trying but I am not sure if I understand what you are trying to say. You want me to change the base class of NetworkBehavior?

    It's not possible, it ships with Unity and I don't have the source code.

    I think the only possibility would be to reimplement BetterBehavior for NetworkBehavior and to create a BetterNetworkBehavior.
     
  16. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Ah, they probably have their own editor then =(

    No don't change the base of NetworkBehaviour. What I was saying is, to change the base of NetworkBehaviourEditor to BaseEditor if it exists and you have access to it, otherwise create a NetworkBehaviourEditor yourself and derive BaseEditor. (are you familiar with Editor scripts?)

    Are you looking for the editor or serialization features of Vfw?
     
    maikklein likes this.
  17. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    Oops, no I haven't done any editor scripting yet, I should probably have a look at it, thanks.

    I am still new to Unity and I just wanted to assign interfaces with the inspector.

    Edit: I also just found your framework a few minutes ago and I love 'RequiredFromThis' and 'HideTarget'.
     
  18. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @maikklein No problem :) Here's what you can try:

    Code (csharp):
    1.  
    2. public class MyNetworkBehaviour : NetworkBehaviour
    3. {
    4.      // copy-paste the code in BaseBehaviour if you're only interested in Vfw editor features or
    5.      // BaseBehaviour + BetterBehaviour if you want editor features + custom serialization
    6. }
    7.  
    8. // in an Editor folder
    9. using UnityEditor;
    10. using Vexe.Editor.Editors;
    11.  
    12. [CustomEditor(typeof(MyNetworkBehaviour), true)]
    13. public class MyNetworkBehaviourEditor : BaseEditor
    14. {
    15. }
    16.  
    Then any script deriving from MyNetworkBehaviour will have BaseEditor inspect it.
     
    Last edited: Jul 16, 2015
    maikklein likes this.
  19. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    Okay nice it sort of works already.



    The only "weird" thing is that I get 2 Serialzation Data fields, but it's not a big deal.
     
  20. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Just [Hide] or [HideInInspector] anything you don't want to see.
     
  21. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    Do you want a PR? I mean it's a bit ugly because of the duplicated code, but I wonder if that could be improved.

    I think to remember that something like this wasn't possible in C# the last time I checked.
    Code (CSharp):
    1. class BaseBehavior<T>: T where T: MonoBehavior
     
  22. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Generic constraints are possible in C# yes, but how would it solve the problem? Maybe you meant multiple inheritance? yes C# doesn't have it.
     
  23. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    To avoid duplicated code and to allow users to extend you behaviors easily. Someone could write

    Code (CSharp):
    1. class MyScript: BetterBehavior<MonoBehavior>{..}
    2. class MyScript2: BetterBehavior<NetworkBehavior>{..}
    3. class MyScript3: BetterBehavior<SomeOtherBehavior>{..}
    But it doesn't matter because this is probably illegal in C#. I don't think that you can have generic inheritance.
     
  24. LuceraProject

    LuceraProject

    Joined:
    Jul 14, 2015
    Posts:
    2
    Hi!

    Is there a way to make a property visible in editor [Show] and specify a numeric range [Range(0, 1)]?

    I tried [Show, Range(0, 1)] but seems that dows no work.

    Thanks in advance!
     
  25. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    @LuceraProject: Use [fRange(0, 1)] or [fSlider(0, 1)].

    I've got a request for a new feature, or at least I haven't found it yet should it already exist: A slider where you can choose a range (start and end) between a min and a max value. Should be persisted into a Vector2, I guess.
     
    vexe likes this.
  26. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @LuceraProject Use [iSlider] for integers, and [fSlider] for floats :)

    @blizzy

    Hope this is what you mean lol



    Stores 25, 50 in the vector.

    // in SliderAttributes.cs

    Code (CSharp):
    1.  
    2.     /// <summary>
    3.     /// Apply to a Vector2 to store the min/max range in it
    4.     /// </summary>
    5.     [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)]
    6.     public class vSliderAttribute : DrawnAttribute
    7.     {
    8.         public readonly float left, right;
    9.  
    10.         public vSliderAttribute(float left, float right)
    11.         {
    12.             this.left = left;
    13.             this.right = right;
    14.         }
    15.     }
    16.  
    // in SliderDrawers.cs

    Code (CSharp):
    1.     public class vSliderDrawer : AttributeDrawer<Vector2, vSliderAttribute>
    2.     {
    3.         public override void OnGUI()
    4.         {
    5.             using(gui.Horizontal())
    6.             {
    7.                 gui.Prefix(displayText);
    8.                 float x = gui.FloatSlider(memberValue.x, attribute.left, attribute.right);
    9.                 float y = gui.FloatSlider(memberValue.y, attribute.left, attribute.right);
    10.                 memberValue = new Vector2(x, y);
    11.             }
    12.         }
    13.     }
    14.  
    // TypeDrawerMapper.cs ('Others' block)

    Code (CSharp):
    1. ...
    2.   .Add<vSliderAttribute, vSliderDrawer>()
    3. ...
     
    Last edited: Jul 17, 2015
  27. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    Yes, kind of. I remember seeing a UI widget where both handles are embedded into one slider bar. I don't know if Unity comes with such a widget or if they built it themselves. I don't even remember exactly where I saw that :-(

    It looked something like this:

    Code (csharp):
    1. ---------[ ]------------------[ ]---------
    But the one you posted is quite a good start, thanks!
     
  28. LuceraProject

    LuceraProject

    Joined:
    Jul 14, 2015
    Posts:
    2
    Thanks! ^_^
     
  29. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
  30. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Hey Vexe.

    As it is now when I have a base class as a field, you get the Unity-style Object Field in the inspector where you can select which derived-class you want that field to be set to. I want to remove the Object field and only show the actual instance class's members....if that makes sense. The reason being I want the containing class itself to have complete control over what the derived class is, but I still want to be able to tweak the derived class members through the inspector.

    I'm sometimes terrible at explaining things so I made a picture to illustrate.
    http://imgur.com/YmS8HnD

    I've been digging around but I can't seem to figure it out. Is there some easy way to do this?
     
  31. Ghopper21

    Ghopper21

    Joined:
    Aug 24, 2012
    Posts:
    170
    HI Vexe, I'm leaning about VFX (looks great!) and have question you. You mentioned above that "Other serializers are either slow/generates garabge (FullSerializer)" -- can you say more about what garbage you are referring to? Do you mean data gets corrupted or something else? Thanks.
     
  32. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
  33. Ghopper21

    Ghopper21

    Joined:
    Aug 24, 2012
    Posts:
    170
  34. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    I've included 'Obj' options (coming next version) in [Display] so you can say:

    Code (csharp):
    1.  
    2. [Display(Obj.DisablePicker)]
    3. public MyClass field;
    4.  
    This would still show the object thumb but clicking it will just create a new instance of MyClass (assuming it's not abstract)

    Those messages might not be related to FS nor GC, try basic divide and conquer and narrow down the list of suspects, it might be something else, always doubt your code first :p
     
    Ghopper21 and Sarkahn like this.
  35. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Sounds good, looking forward to the next version then. Thanks!
     
  36. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    So I released 1.3.4 finally with FastSave! It's actually been sitting in my computer for a while now I was hoping I'd find some time for a quick tutorial but just couldn't. You just have to get along with the README file included and the contrived example scenes in VFWExamples. I'll keep an eye out for chances to make a tutorial.

    It's still not thoroughly used (used it for room saving/loading), I figured the only way to really make something good out of it is by you the community, your usage of it, your help, ideas, suggestions and criticism! - There's a couple of limitations you have to be aware of, they're mentioned in the README, I highly suggest you read it before using the system. The API and the serializer implementation are both dead stupid simple. Keep in mind this is a framework solution aims to help you in your custom saving/loading solutions of your game.

    @blizzy vSlider/MinMaxSlider

    @Sarkahn Obj enum
     
  37. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
  38. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    So I managed to sneak in an hour of recording, did a FastSave intro tutorial giving an overview, talking about certain aspects of it and demonstrating simple usage.

    Part1:



    Part2:

     
  39. NavyFish

    NavyFish

    Joined:
    Aug 16, 2013
    Posts:
    28
    Hey Vexe, great stuff. Ever since 1.34, the framework stopped working for me. So I removed "Editor" and "Vexe" under my Assets/Plugins folder, as well as "VFW Examples" and "VFW Misc" from Assets.

    Next, I reimported the vfw134.unitypackage package, loaded the VFW/Examples/Scenes/Attributes scene, and hit run. Still not working. For example, the Better Vector:

    upload_2015-8-1_19-12-12.png

    Unless things have dramatically changed, I'm expecting there to be Copy/Paste/r/1/0, and they're not there. I'm sure I'm missing something obvious here, but am a bit stuck. Any ideas?
     
  40. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @NavyFish Hey! - Everything's working fine on my end. It looks to me however that your inspector is in 'Debug' mode, it should be set to Normal mode for Vfw editors to be activated. Click on the small down arrow on the top right corner beside the lock icon to switch to normal mode (Inspector modes)
     
  41. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    I've added a donation button at the first page of this thread. If any one found any of my stuff useful and would like to drop me some bytes or nibbles to keep the serializable ship sailing, I'd appreciate it sir. If you feel it's a drop in a bucket, remember every drop counts :)
     
  42. NavyFish

    NavyFish

    Joined:
    Aug 16, 2013
    Posts:
    28
    @vexe Debug mode, doh! That did it. I thought it'd be something simple. Thank you.

    And WRT donations - as an open-source mod dev myself (KSP) every drop does indeed count! Here's some coffee $$ for your time!

    -----------------------------

    Edit: Just noticed this Argument Out Of Bounds Exception occurring w/ VFW:

    Code (CSharp):
    1. ArgumentOutOfRangeException: Cannot be negative.
    2. Parameter name: length
    3. System.String.Substring (Int32 startIndex, Int32 length) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/String.cs:348)
    4. Vexe.Runtime.Extensions.TypeExtensions.<get_getNiceName>m__5D (System.Type type) (at Assets/Plugins/Vexe/Runtime/Library/Extensions/TypeExtensions.cs:265)
    5. Vexe.Runtime.Extensions.DelegateExtensions+<Memoize>c__AnonStoreyD`2[System.Type,System.String].<>m__2A (System.Type n) (at Assets/Plugins/Vexe/Runtime/Library/Extensions/DelegateExtensions.cs:38)
    6. Vexe.Runtime.Extensions.TypeExtensions.GetNiceName (System.Type type) (at Assets/Plugins/Vexe/Runtime/Library/Extensions/TypeExtensions.cs:289)
    7. Vexe.Runtime.Types.RuntimeMember..ctor (System.Reflection.MemberInfo memberInfo, System.Type memberType, System.Object memberTarget) (at Assets/Plugins/Vexe/Runtime/Types/Others/RuntimeMember.cs:91)
    8. Vexe.Runtime.Types.RuntimeMember.TryWrapField (System.Reflection.FieldInfo field, System.Object target, Vexe.Runtime.Types.RuntimeMember& result) (at Assets/Plugins/Vexe/Runtime/Types/Others/RuntimeMember.cs:107)
    9. Vexe.Runtime.Types.RuntimeMember.WrapMember (System.Reflection.MemberInfo member, System.Object target) (at Assets/Plugins/Vexe/Runtime/Types/Others/RuntimeMember.cs:179)
    10. Vexe.Runtime.Types.RuntimeMember.WrapMembers (IEnumerable`1 members, System.Object target) (at Assets/Plugins/Vexe/Runtime/Types/Others/RuntimeMember.cs:164)
    11. Vexe.Runtime.Serialization.ISerializationLogic.GetSerializableMembers (System.Type type, System.Object target) (at Assets/Plugins/Vexe/Runtime/Serialization/SerializationLogic.cs:41)
    12. Vexe.Runtime.Serialization.ISerializationLogic.<ISerializationLogic>m__83 (System.Type type) (at Assets/Plugins/Vexe/Runtime/Serialization/SerializationLogic.cs:31)
    13. Vexe.Runtime.Extensions.DelegateExtensions+<Memoize>c__AnonStoreyD`2[System.Type,Vexe.Runtime.Types.RuntimeMember[]].<>m__2A (System.Type n) (at Assets/Plugins/Vexe/Runtime/Library/Extensions/DelegateExtensions.cs:38)
    14. Vexe.Runtime.Serialization.SerializerBackend.DeserializeTargetFromData (UnityEngine.Object target, Vexe.Runtime.Serialization.SerializationData data) (at Assets/Plugins/Vexe/Runtime/Serialization/Serializers/SerializerBackend.cs:60)
    15. Vexe.Runtime.Types.BetterBehaviour.DeserializeObject () (at Assets/Plugins/Vexe/Runtime/Types/Core/BetterBehaviour.cs:87)
    16. Vexe.Runtime.Types.BetterBehaviour.OnAfterDeserialize () (at Assets/Plugins/Vexe/Runtime/Types/Core/BetterBehaviour.cs:58)
    That happens when using BaseBehavior. A similar one occurs with BetterBehavior.
     
    Last edited: Aug 2, 2015
  43. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @NavyFish thanks a lot buddy, it means a lot I truly appreciate it!
     
    Last edited: Aug 2, 2015
  44. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @NavyFish can you tell me when the error happens, how to replicate?
     
  45. NavyFish

    NavyFish

    Joined:
    Aug 16, 2013
    Posts:
    28
    Absolutely, sorry for the quick initial report, was running out of the house to get a coffee for myself :)

    It seems to happen when a class deriving from BaseBehavior uses the https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern - i.e. MyClass<T> : BaseBehavior where T : MyClass<T>. I'm trying to build a simple example for reproduction now.
     
  46. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Sorry but, why would you ever want to do that? X<T> : Y where T : X<T>
     
  47. NavyFish

    NavyFish

    Joined:
    Aug 16, 2013
    Posts:
    28
    I know it seems odd, and I rarely use the pattern because it's essentially a hack. But in this case I needed it because my base class implemented the Singleton pattern and I wanted inheriting classes to each form their own Singleton, i.e. one per dervied class. Without the CRTP, all derived classes' 'Instance' variable will refer to the base class's Instance.

    I'm exploring other ways of achieving this - perhaps by making Instance a property and then overriding it in the derived classes - but this brings about it's own host of problems.
     
  48. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    I've never seen a singleton like that. I'll share mine with you, this is all I ever needed from a singleton structure. Don't know if it works for you.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public static class SingleScript<T> where T : ScriptableObject
    5. {
    6.     private static T _instance;
    7.     public static T instance
    8.     {
    9.         get
    10.         {
    11.             if (_instance == null)
    12.             {
    13.                 _instance = Object.FindObjectOfType<T>();
    14.                 if (_instance == null)
    15.                 {
    16.                     var path = "Singles/" + typeof(T).Name;
    17.                     _instance = Resources.Load<T>(path);
    18.                     if (_instance == null)
    19.                     {
    20.                         if (typeof(ScriptableObject).IsAssignableFrom(typeof(T)))
    21.                         {
    22.                             _instance = ScriptableObject.CreateInstance<T>();
    23.                             #if UNITY_EDITOR
    24.                             UnityEditor.AssetDatabase.CreateAsset(_instance, path);
    25.                             #endif
    26.                         }
    27.                     }
    28.                 }
    29.             }
    30.             return _instance;
    31.         }
    32.     }
    33. }
    34.  
    35. public static class SingleBehaviour<T> where T : MonoBehaviour
    36. {
    37.     private static T _instance;
    38.  
    39.     public static T get()
    40.     {
    41.         return get(true);
    42.     }
    43.  
    44.     public static T get(bool create)
    45.     {
    46.         if (_instance == null)
    47.         {
    48.             _instance = Object.FindObjectOfType<T>();
    49.             if (_instance == null)
    50.             {
    51.                 if (create)
    52.                     _instance = new GameObject(typeof(T).Name).AddComponent<T>();
    53.                 else
    54.                     Debug.Log("Couldn't find object of type: " + typeof(T).Name);
    55.             }
    56.         }
    57.         return _instance;
    58.     }
    59. }
    60.  
    Then I have a globals class:

    Code (csharp):
    1.  
    2. public static class globals
    3. {
    4.   public static Database database { get { return SingleScript<Database>.instance; } }
    5.   public static Tasks tasks { get { return SingleBehaviour<Tasks>.get(); } }
    6.   public static readonly Record prefs = new Record();
    7.   // etc
    8. }
    9.  
     
    NavyFish likes this.
  49. NavyFish

    NavyFish

    Joined:
    Aug 16, 2013
    Posts:
    28
    I like that much better, thank you for the solution. In the past, I've always derived from a "Singleton<T>" class. This made further inheritance impossible, so I resorted to hacks like the CRTP pattern. Using composition instead of inheritance makes much, much more sense.
     
  50. BTStone

    BTStone

    Joined:
    Mar 10, 2012
    Posts:
    1,422
    Hey vexe, a quick one :)

    I have this little script:

    Code (CSharp):
    1. public class SpriteSwapper : BetterBehaviour
    2. {
    3.     public GameObject firstSpriteGO;
    4.     public GameObject secondSpriteGO;
    5.  
    6.     [Show]
    7.     public void DoSwap(bool swapped)
    8.     {
    9.         var currentSprite = GetComponent<tk2dSprite>();
    10.  
    11.         var firstSprite = firstSpriteGO.GetComponent<tk2dSprite>();
    12.         var secondSprite = secondSpriteGO.GetComponent<tk2dSprite>();
    13.  
    14.         if (!swapped)
    15.         {
    16.             currentSprite.SetSprite(secondSprite.spriteId);
    17.             swapped = true;
    18.         }
    19.         else
    20.         {
    21.             currentSprite.SetSprite(firstSprite.spriteId);
    22.             swapped = false;
    23.         }
    24.     }
    25. }
    This is intended for our level-designer where he drops two prefabs in the inspector of this script and can Hit the Button "DoSwap" and check out the runtime-swapping of sprites. Now I have this bool parameter and when I hit the button the bool checkbox isn't checked in the inspector when I hit it for the first time. The "else" code is never executed, only when I check the checkbox manually myself in the inspector. Same goes for swapping the sprites again, I have to uncheck the checkbox manually.

    The checkbox doesn't get checked/unchecked at runtime, too. I added this to my script:

    Code (CSharp):
    1. void Start()
    2.     {
    3.         StartCoroutine(Swappy());
    4.     }
    5.  
    6.  
    7.     IEnumerator Swappy()
    8.     {
    9.         yield return new WaitForSeconds(1f);
    10.  
    11.         DoSwap(false);
    12.  
    13.         yield return new WaitForSeconds(1f);
    14.  
    15.         DoSwap(true);
    16.     }
    Just wanted to check if the bool param gets checked/unchecked in the inspector when the game runs in the editor, but it doesn't. Any insight on this? :)