SkillAgentSearch skills...

MolecularLibCore

This is a unity package that aims to add useful features for unity like a SerializableDictionary, a safe Tag wrapper, Timers, Vector conversion and manipulation methods and more

Install / Use

/learn @Heymity/MolecularLibCore

README

MolecularLibCore · GitHub license Unity 2020.3 or later Tests Status

<img align="right" width="160px" height="160px" src="Media/LogoOnly@160.png" alt="Logo"/>

This is a package for unity that provide useful utilities like the PolymorphicVariable and SerializableDictionary<TKey, TBase> classes and editor drawers, the ability to instantiate GameObjects with passing parameters to it, a safe Tag wrapper class, support for optional fields, a VolatileScriptableObject class and more!

How to download it

The asset is available in the Unity Asset Store where it can be easily downloaded and installed like any other unity package. Otherwise you can just download this repository and add it to your project.

What does it have?

Contents

Here is a quick overview of the contents of this package, for more details check the documentation present in "Assets/HandsomeDinosaur/MolecularLib/Core/MolecularLib Docs.pdf or .docx":

PolymorphicVariable<T>

The Polymorphic Variable adds support for polymorphism in unity serializable fields. If you don’t know what polymorphism is, I strongly suggest reading this page (It is very short, mostly examples).

You can access this value as TBase using myPolymorphicVar.Value or you can get it already converted using myPolymorphicVar.As<TDerived>(out TDerived, bool onlyPerfectTypeMatch) like this:

myPolymorphicVar.Value // returns the value as TBase

if (myPolymorphicVariable.As<A>(out var asA))
    Debug.Log($"As A | aClassInt: {asA.aClassInt}");
else if (myPolymorphicVariable.As<B>(out var asB))
    Debug.Log($"As B | bClassInt: {asB.bClassInt}");
else if (myPolymorphicVariable.As<C>(out var asC))
    Debug.Log($"As C | cClassFloat: {asC.cClassFloat}");
else
    Debug.Log($"As Base | myBaseString: {myPolymorphicVariable.Value.myBaseString}");

VolatileScriptableObject<T>

As you probably know, scriptable objects in Unity have persistent data for entering and leaving play mode, so if you have an int in a scriptable object set to 100, and then, while in play mode, you change it to 50, when you exit play mode, it will still be 50, not 100. This is sometimes good and sometimes bad. One of these bad times is when you’re using scriptable objects to hold changeable data, say player health. You would want the player's health to be reset when you leave play mode, but you also want to change it during play mode. If you are thinking this is a very strange way to code a game by the way, check this, it has some very good benefits. So, what the VolatileScriptableObject class does is that it solves this problem! You can change the data in it, and when you leave play mode it won’t be changed.

There is a very good demo and implementation of this here “Demo > TestVolatileScriptableObject.cs”. But if you want a quick sneak-pic of it, here it is:

[CreateAssetMenu(fileName = "Volatile SO", menuName = "New Volatile SO", order = 0)]
public class TestVolatileScriptableObject : VolatileScriptableObject<TestVolatileScriptableObject.Data>
{
    // Here is a quick way of accessing the data. Can be done in other ways too.
    public Data VolatileData
    {
        get => Value;
        set => Value = value;
    }
    
    // Here you will put all the data you want to be volatile
    [Serializable]
    public class Data
    { 
        [TextArea] public string myString;
        public MonoBehaviour myBehaviour;
        public int myInt;
        public float myFloat;
        public List<string> myList;
        public Optional<SerializableDictionary<int, string>> myOptionalDictionary;
        public ScriptableObject myScriptableObject;
    } 
}

SerializableDictionary<TKey, TValue>

As it is commonly known, unity serializes Lists, but not Dictionaries. But what is a serialized dictionary if not 2 lists, one for the keys, and one for the values? That’s exactly what the SerializableDictionary<TKey, TValue> does! Right before Unity serializes the class, it converts its dictionary to two lists, keys and values, which are then serialized by Unity. Then just after deserialization, those lists are converted back to a dictionary. It also comes with a neat editor drawer! It will look like this in the inspector (if the variable is public or has [SerializeField]):

Timers

Well, it is kind of obvious what it does, so let’s jump right into how to use the timers. There are two types of timers in the library:

• Timer Async • Timer Coroutine

And the timer Async can generate a TimerReference class.

Both types of timers have the same functionalities: • OnComplete / OnFinish • Duration • ElapsedSeconds • Repeat

The main difference between Timer Async and Timer Coroutine is the way they work: Timer Async, as the name suggests, uses an asynchronous function to count the time using Task.Delay(secondsToFinish) and the ElapsedSeconds are calculated via UnityEngine.Time.time – Timer.StartTime (Timer.StartTime is set to UnityEngine.Time.time when the timer starts).

Now the Timer Coroutine uses a coroutine to count time, using yield return new WaitForSeconds(delay), and the ElapsedSeconds are also calculated via UnityEngine.Time.time – Timer.StartTime (Timer.StartTime is set to UnityEngine.Time.time when the timer starts).

Aside from how they work, TimerCoroutine will instantiate 1, and only one through the entire program execution, GameObject with the TimerManager script (It has a singleton by the way). While the Async timer will not. The Timer Async CANNOT be paused or resumed, can only be permanently stopped in repeat mode. The Timer Coroutine CAN be paused and resumed, even in repeat mode.

The way I suggest looking at this is like so: The Async timer is a lightweight more basic version of the TimerCoroutine. If you just need a timer, real quick for some real basic stuff, use the Async, if you need it to be more controllable, use the Coroutine.

Timer.TimerAsync(TimerDelay, () => Debug.Log("Finished”));
    
   
var timerReference = Timer.TimerAsyncReference(TimerDelay);
    
timerReference.OnFinish += () => Debug.Log("Finished");
if (timerReference.HasFinished) Debug.Log("Already finished");
Debug.Log($"There has elapsed {timerReference.ElapsedSeconds} seconds");

var timer = Timer.Create(TimerDelay, () => Debug.Log("Finished"));
    
// Repeat timer
var timer = Timer.Create(TimerDelay, () => Debug.Log("Finished"), true);

AutoSingleton

Need to use a singleton but don’t want to write the same stuff every time? Just do this: In your MonoBehaviour class, change the parent class from MonoBehaviour to AutoSingleton<YOUR TYPE HERE>, so that it looks like this:

public class TimerManager : AutoSingleton<TimerManager>

Using it this way, from anywhere in the code you will be able to access TimerManager.Current and get a TimerManager instance!

Note: AutoSingleton<T> derives from MonoBehaviour

How does it get the instance?

In some ways: First, before you call Current for the first time, it has no idea where is this instance. When you call it the first time it will do the following:

Instantiate with args

First off to use this, the object that you want to instantiate needs to have this interface: IArgsInstantiable<>. There are a total of 10 overrides of this interface, one with no parameters, one with 1 parameter, one with 2 parameters … and one with 10 parameters. The function that this interface implements will as parameters the types passed into the interface, like so:

public class TestArgInstantiable : MonoBehaviour, IArgsInstantiable<float, int, string, GameObject>
{
    public float floatArg;
    public int intArg;
    public string stringArg;
    public GameObject gameObjectArg;
    
    public void Initialize(float arg1, int arg2, string arg3, GameObject arg4)
    {
        Debug.Log(
	$"I was instantiated with args: args1: {arg1} args2: {arg2} args3: {arg3} args4: {arg4}");
        floatArg = arg1;
        intArg = arg2;
        stringArg = arg3;
        gameObjectArg = arg4;
    }
}

This function “Initialize” will then be called just after the awake and after the object is instantiated. To instantiate this object, for example, you would do it like this:

var floatIntStringGo = Molecular.Instantiate(prefab, 23.3f, 342, "I am a string", someGo);

It is simple to use and implement it!

In the Demo folder, there is a great example of this called InstantiateWithArgsDemoObject

Vector helper methods

There are only extension methods, and the class they are contained in is the VectorHelperExtensionMethods. So they are all used like this: my

Related Skills

View on GitHub
GitHub Stars18
CategoryDevelopment
Updated4mo ago
Forks0

Languages

C#

Security Score

92/100

Audited on Nov 19, 2025

No findings