Frameworks

Easy Framework

UniEasy - simple framework for unity

Created by chaolun

Welcome, this framework was based on my years of project experience summed up. I hope everyone like it and easy to use, cheers!

Quick Start

Sample Repository https://github.com/chaolunner/FateForSpeed

Github Source URL https://github.com/chaolunner/FateForSpeed.git

As Project Plugin :

  • $ git submodule add [email protected]:chaolunner/EasyFramework.git Assets/Plugins
  • $ git submodule add [email protected]:chaolunner/EasyFrameworkStreamingAssets.git Assets/StreamingAssets

History

Create a new repository [back]

1. Set user name and email :

$ git config --global user.name "chaolun"
$ git config --global user.email "[email protected]"

2. Create ssh key :

$ ssh-keygen -t rsa -C "[email protected]"

If you don’t need password continuous input enter 3 times

Finally get 2 files : id_rsa and id_rsa.pub

3. Login Github and add ssh id_rsa.pub :

Copy id_rsa.pub content to Settings -> SSH and GPG keys -> New SSH key

Title can input an alias that is displayed on the GitHub by the SSH key

4. Test ssh whether successful :

$ ssh -T [email protected]

The authenticity of host 'github.com' (207.97.227.239) can’t be established. RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.

  Are you sure you want to continue connecting (yes/no)?
$ yes

If you see your user name behind Hi. It mean success!

5. Modified .git/config file :

Use [email protected] replace https://github.com

6. New github repository

Sign in github and click the plus button next to the avatar in the upper right, Then select New Repository

New Unity Project [back]

Open the Unity3d and create a new unity project

Use unity project path to create a repository with SourceTree

If you want to upload your project to github, click the plus button next to the avatar in the upper right, Then select Import Repository

In the Your old repository’s clone URL column fill in your project path and in the Your new repository details/Name column fill in your project name, Finally press Begin import button

Add Submodule [back]

1. Create EasyFrameworkStreamingAssets repository

2. $ git submodule add [email protected]:chaolunner/EasyFrameworkStreamingAssets.git Assets/StreamingAssets

3. Move files from StreamingAssets folder to EasyFrameworkStreamingAssets folder

Remove Submodule [back]

Use EasyFrameworkStreamingAssets for example

1. Open the .gitmodules and Delete

[-][submodule "Assets/StreamingAssets"]
[-]path = Assets/StreamingAssets
[-]url = [email protected]:chaolunner/EasyFrameworkStreamingAssets.git

2. Open the .git/modules folder and delete the StreamingAssets folder

3. Open the .git/config and Delete

[-][submodule "Assets/StreamingAssets"]
[-]url = [email protected]:chaolunner/EasyFrameworkStreamingAssets.git

4. Commit and Push your changes

5. $ git rm --cached Assets/StreamingAssets

6. $ rm -rf Assets/StreamingAssets

Dependency Injection [back]

1. Before start don’t forgot using UniEasy.DI

2. About inject you can use like :

1. Constructor Injection

public class Foo
{
    IBar bar;

    public Foo(IBar bar)
    {
        this.bar = bar;
    }
}

2. Field Injection

public class Foo
{
    [Inject]
    IBar bar;
}

3. Property Injection

public class Foo
{
    [Inject]
    public IBar Bar {
        get;
        private set;
    }
}

4. Method Injection

public class Foo
{
    IBar bar;

    [Inject]
    public Init(IBar bar)
    {
        this.bar = bar;
    }
}

3. About binding you can use like :

Container.Bind<Foo>().AsSingle();
Container.Bind<IBar>().To<Bar>().AsSingle();
Container.Bind<IBar>().To<Bar>().FromInstance(new Bar()).AsSingle();
Container.Bind<IBar>().WithId("id").To<Bar>().FromInstance(new Bar ()).AsSingle ();
Container.Bind<Foo>().AsSingle().WhenInjectedInto<Bar>(); (It mean delay binding wait until have Bar type Inject)
Container.Bind<Foo>().AsSingle().NonLazy(); (Normally, The ResultType will instantiate only when the binding variable first used. But, if used NonLazy, The ResultType will be created immediately when application starts)

4. Want Inject work :

After var bar = new Bar() don’t forgot use DiContainer.Inject (bar);

If Bar is sub class of MonoBehaviour, It is better add DiContainer.Inject (this) to void Awake ()

Installer [back]

1. Installer

2. MonoInstaller

3. ScriptableObjectInstaller

First Inherit one of the three classes and override InstallBindings() function
Then binding and inject objects in InstallBindings() function
Finally use UniEasy.DI.Context class install you created Installer

Context [back]

1. Context

2. ProjectContext

ProjectContext need to create a prefab and put in Resources/ProjectContext.prefab

Drag any MonoInstallers that you have added to your Scene Hierarchy to ProjectContext’s Installers ReorderableList

All MonoInstallers will be called InstallBindings() function when before scenes loaded

3. SceneContext

SceneContext need to added to scene root gameObject

Drag any MonoInstallers that you have added to your Scene Hierarchy to SceneContext’s Installers ReorderableList

All MonoInstallers will be called InstallBindings() function when SceneContext’s gameObject Awake()

Important you need to set SceneContext Script Execution Order high than Default Time

Entity Component System [back]

1. As a Entity you need to add a EntityBehaviour Component on GameObject

2. You can use right click in Project Window Select Create -> Custom Script -> ComponentBehaviour Installer Create a Component script

3. You can use right click in Project Window Select Create -> Custom Script -> SystemBehaviour Installer Create a System script

4. For Example :

[Entity]

Scene :
    Level(GameObject) : [Transform|SceneContext|SceneInstaller(MonoInstaller)]
        Entity(GameObject) : [Transform|EntityBehaviour|HealthComponent(ComponentBehaviour)]
        System(GameObject) : [Transform|HealthSystem(SystemBehaviour)]

[Component]

using UniEasy.ECS;

public class HealthComponent : ComponentBehaviour
{
    public float CurrentHealth;
    public float StartingHealth;
}

[System]

using UniEasy.ECS;
using System;
using UniRx;

public class HealthSystem : SystemBehaviour
{
    public IGroup Healths;

    public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory)
    {
        base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory);

        Healths = this.Create (typeof(HealthComponent));
    }

    public override void OnEnable ()
    {
        base.OnEnable ();

        Healths.OnAdd().Subscribe (entity =>
        {
            var healthComponent = entity.GetComponent<healthcomponent> ();
            healthComponent.CurrentHealth = healthComponent.StartingHealth;
        }).AddTo (this.Disposer);
    }
}

ECSInstaller [back]

Add ECSInstaller Component to ProjectContext prefab(Resources/ProjectContext.prefab)

Drag ECSInstaller Component to ProjectContext Installers ReorderableList

ProjectContext will call ECSInstaller InstallBindings() function when before scenes loaded

ECSInstaller will create and binding all ECS framework needed core classes

ProjectInstaller [back]

Add ProjectInstaller Component to ProjectContext prefab(Resources/ProjectContext.prefab)

Drag ProjectInstaller Component to ProjectContext Installers ReorderableList

ProjectContext will call ProjectInstaller InstallBindings() function when before scenes loaded

ProjectInstaller will instantiate, binding and inject all gameObjects from Resources/Kernel folder

SceneInstaller [back]

Create a gameObject named Level in the root directory of the scene

Set other gameObjects transform parent were Level gameObject

Add SceneContext Component to Level gameObject

Add SceneInstaller Component to Level gameObject

Drag SceneInstaller Component to SceneContext Installers ReorderableList

SceneContext will called SceneInstaller’s InstallBindings() function when Awake, so SceneInstaller will inject all SystemBehaviour

For Performance we don’t want to SceneInstaller GetComponents<SystemBehaviour> When Awake(), So we need to pre GetComponents<SystemBehaviour> and save them in array or list, we did it, too

You can see a Auto Update toggle and Force Update button on SceneInstaller Inspector panel

If set Auto Update toggle is true SceneInstaller will auto GetComponents<SystemBehaviour> and save them in Systems List when you save scene

Click Force Update button SceneInstaller will GetComponents<SystemBehaviour> and save them in Systems List immediately

If you also want this system can be binding and as a single system, you can add it to Binding Systems List by your hand

GroupFactory [back]

Use GroupFactory.Create (Type[] types) you can get the group(entities) that contain all of these types

You also can use this.Create (Type[] types) get the group when you are in the SystemBehaviour class

WithPredicate (GroupFactory Extend) [back]

Now we add WithPreficate to the group, so we can do more cool things like this :

public class ActiveComponent
{
    public BoolReactiveProperty IsActive;
}
public class ActiveSystem : SystemBehaviour
{
    public IGroup Actives;

    public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory)
    {
        base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory);

        Actives = GroupFactory.AddTypes (new Type[] {
            typeof(EntityBehaviour),
            typeof(ActiveComponent),
        }).WithPredicate ((entity) =>
        {
            var activeComponent = e.GetComponent<ActiveComponent> ();

            activeComponent.gameObject.ObserveEveryValueChanged (go => go.activeSelf).Subscribe (b => {
                activeComponent.IsActive.Value = b;
            }).AddTo (activeComponent.Disposer);
            return activeComponent.IsActive;
        }).Create ();
    }

    public override void OnEnable ()
    {
        base.OnEnable ();

        Actives.OnAdd ().Subscribe (entity => {
            Debug.Log ("every time the gameObject is set for active will be called");
        }).AddTo (this.Disposer);

        Actives.OnRemove ().Subscribe (entity => {
            Debug.Log ("every time the gameObject is set for disactive will be called");
        }).AddTo (this.Disposer);
    }
}

As Single System [back]

For Performance for a high frequency used group you can choose to create a class that inherit from Group for him, then bind and inject it into every system that needs to be used, for example :

public class DeadEntities : Group
{
    public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager)
    {
        Components = new Type[] { typeof(HealthComponent) };

        Func<IEntity, ReactiveProperty<bool>> checkIsDead = (e) =>
        {
            var health = e.GetComponent<HealthComponent> ();

            health.CurrentHealth.Value = health.StartingHealth;

            var isDead = health.CurrentHealth.DistinctUntilChanged ().Select (value => value <= 0).ToReactiveProperty();
            return isDead;
        };

        Predicates.Add(checkIsDead);
        base.Initialize (eventSystem, poolManager);
    }
}
public class GroupsInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
        Container.Bind<DeadEntities>().To<DeadEntities>().AsSingle();
    }
}

Then add the GroupsInstaller component to the SceneContext List

PrefabFactory [back]

If you want to dynamic create an entity GameObject, you need to use PrefabFactory.Instantiate() method

public class ExampleSystem : SystemBehaviour {

    public GameObject Prefab;
    public Transform Parent;
    public bool WorldPositionStays = true;

    public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory)
    {
        base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory);

        if (Prefab != null)
        {
            var go = PrefabFactory.Instantiate (Prefab, Parent, WorldPositionStays);
            var entity = (go.GetComponent<EntityBehaviour>() ?? go.AddComponent<EntityBehaviour>()).Entity;      
        }
    }
}

EntityBehaviour [back]

For Performance we don’t want to EntityBehaviour GetComponents<Component> When Awake(), So we need to pre GetComponents<Component> and save them in array or list, we did it, too

You can see a Auto Update toggle and Force Update button on EntityBehaviour Inspector panel

If set Auto Update toggle is true EntityBehaviour will auto GetComponents<Component> and save them in Components List when gameObject’s components count changed

Click Force Update button EntityBehaviour will GetComponents<Component> and save them in Components List immediately

Runtime Components [back]

Runtime component does not contain references to Objects or Transforms, so it can makes components more single and more clear

You can found it on EntityBehaviour and it is a ReorderableList named Runtime Components [0]

You can use ReorderableList’s Add(+) Button to select and add a runtime component to EntityBheaviour

// Use UniEasy.ContextMenuAttribute can easy to pack runtime components into groups
// You can see them at drop down context menu when you click `Runtime Components [0]` ReorderableList's `Add(+) Button`
[UniEasy.ContextMenu ("Test/HealthComponent")]
public class HealthComponent : RuntimeComponent
{
    public float CurrentHealth;
    public float StartingHealth;
}

Scriptable Components [back]

The object you want to add scriptable components must be prefab or asset!

Because ScriptableComponent inherit from ScriptableObject and we used AssetDatabase.AddObjectToAsset() function to save the ScriptableObject

Note that your data will be modified and saved, whether you are playing or editing mode. Of course, we will disable edit of data at run time. But you still can modify it use scripts at run time

// Use UniEasy.ContextMenuAttribute can easy to pack scriptable components into groups
// You can see them at drop down context menu when you click `Scriptable Components [0]` ReorderableList's `Add(+) Button`
[UniEasy.ContextMenu ("Test/HealthComponent")]
public class HealthComponent : ScriptableComponent
{
    public float CurrentHealth;
    public float StartingHealth;
}

Feature (Runtime Systems) [back]

If you want to create a group system, you must inherit from the Feature instead of using it directly !

You can use Runtime Systems [0] ReorderableList’s Add(+) Button to select and add a runtime system to the group system inherited from the Feature

Divide the systems with similar functions into a group, this can better help you manage complex systems, like I made the Console Systems !

public class ConsoleSystems : Feature {}
[UniEasy.ContextMenu ("Console/DebugSystem")]
public class DebugSystem : RuntimeSystem
{
    ...
}
[UniEasy.ContextMenu ("Console/ConsoleSystem")]
public class ConsoleSystem : RuntimeSystem
{
    ...
}

Create a gameObject and add ConsoleSystems component and click ConsoleSystems’s Runtime Systems [0] ReorderableList’s Add(+) Button in Inspector panel

Then select and add DebugSystem and ConsoleSystem in drop down context menu, Save the scene or make the gameObject a prefab and drag the prefab to the Resources/Kernel/... folder (The Console Systems in this folder will be automatically injected and bindings as a single)

Serialize/Deserialize [back]

Base on WriterExtensions (EasyDictionary<string, EasyObject>)

#if Serialize entity all can be serialize components
string data = entity.Serialize ();
#elif Only Serialize include in the includeTypes components
Type[] includeTypes = Type[] { typeof(SerializeComponent) }
string data = entity.Serialize (includeTypes);
#elif Serialize but ignore include in the ignoreTypes components
Type[] ignoreTypes = Type[] { typeof(NonSerializeComponent) }
string data = entity.Serialize (null, ignoreTypes);
#endif
entity.Deserialize (data);

ReorderableListDrawer https://github.com/SubjectNerd-Unity/ReorderableInspector [back]

Usage

To draw an array as a ReorderableList, mark the property with the Reorderable attribute

// Add this `using` statement to the top of your file
using UniEasy;

public class ReordrableListTest : MonoBehaviour
{
    [Reorderable]
    public string[] stringArray; // This will be drawn with a ReorderableList

    public List<string> stringList; // This will be drawn as a default array
}

Inline ScriptableObject editing

Edit settings stored in a ScriptableObject in the inspector with the Reorderable attribute

public class SkinData : ScriptableObject
{
    public string Id;
    public Sprite Sprite;
}

public class TestEntity : MonoBehaviour
{
    public string EntityName;

    // Add the Reorderable attribute to edit the ScriptableObject in the GameObject inspector
    // When the Skin is empty, a Create button will be displayed on the right of the inspector on the right side of the Skin column
    // When the Skin is not empty, a Foldout button will be displayed, and you can quickly check the internal data of SkinData through it.
    [Reorderable]
    public SkinData Skin;
}

Custom Inspectors

Custom inspectors will not automatically draw arrays as ReorderableLists unless they inherit from ReorderableDrawer

[CustomEditor(typeof(YourCustomClass))]
public class CustomReorderableInspector : ReorderableDrawer
{
    // Called by OnEnable
    protected override void Initialize()
    {
        base.Initialize();
    }

    // Override this function to draw
    protected override void DrawInspector()
    {
        // Draw all properties
        // Change DrawPropertiesAll function or Add new functions here
        /*
        DrawPropertiesAll();
        */

        // Write your custom inspector functions here
        EditorGUILayout.HelpBox("This is a custom inspector", MessageType.Info);
    }
}

You can also refer to EntityBehaviourDrawer, FeatureDrawer

Draw Object Reference Property Field in List

// Add this `using` statement to the top of your file
using UniEasy;

public class ReordrableComponent : MonoBehaviour
{
    public float FloatValue;
    public string StringValue;
}

public class ReordrableListTest : MonoBehaviour
{
    // Important is add isDrawObjectReference = true
    [Reorderable (isDrawObjectReference: true)]
    public ReordrableComponent[] List1;
    [Reorderable (isDrawObjectReference: true)]
    public ScriptableObject[] List2;
}

DropdownMenuAttribute

Use DropdownMenuAttribute can quickly override the dropdown menu function of reorderable list

DropdownMenuAttribute(typeof(T)), T is the parent class of the class you want to add

Also can be referred to EntityBehaviour, Feature, StateMachineHandler, PublishEvent

public class ReordrableListTest : MonoBehaviour
{
    [Reorderable, DropdownMenuAttribute(typeof(RuntimeComponent))]
    public ReordrableComponent[] List1;
}

BackgroundColorAttribute

Use BackgroundColorAttribute can add a custom background to your reorderable list, making it easier for you to distinguish your list

Also can be referred to EntityBehaviour, Feature, StateMachineHandler, SceneInstaller, Context

public class ReordrableListTest : MonoBehaviour
{
    [Reorderable, BackgroundColor("#00808080")]
    public ReordrableComponent[] List1;
}

ReorderableDrawer [back]

ReorderableDrawer Inherit from PropertyDrawer, can draw array or list property(SerializedProperty) who has ReorderableAttribute

We can’t use EditorGUI.PropertyField() directly, because Unity don’t want PropertyDrawer deal the array or list

So I use EasyGUI.PropertyField() bypassing the restrictions of unity, maybe this is not a wise decision, but why not try it 😛

ReorderableInspectableDrawer [back]

Unity provided ReorederableList only support SerializedProperty, so I created InspectableReorderableList to support editing InspectableProperty

ReorderableInspectableDrawer Inherit from InspectableDrawer, can draw array or list property(InspectableProperty) who has ReorderableAttribute. See Also: InspectableDrawer class

[InspectablePropertyDrawer (typeof(ReorderableAttribute))]
public class ReorderableInspectableDrawer : InspectableDrawer
{
    // Draw the property inside the given rect
    public override void OnGUI(Rect position, InspectableProperty property, GUIContent label)
    {
        // Draw the InspectableReorderableList, Please check the code for the details
        ...
    }
}
public class ViewComponent : RuntimeComponent
{
    [Reorderable]
    public List<Transform> Transforms;
}

InspectableDrawer [back]

Is same as PropertyDrawer, The only difference is that it acts on the object of the InspectableProperty type and PropertyDrawer acts on the object of the SerializedProperty type

So If you want to the InspectableProperty, it has the same effect as SerializedProperty does, you need to use InspectableDrawer rewrite the class that inherits from the PropertyDrawer

Also can be referred to ReorderableInspectableDrawer, InspectorDisplayDrawer, MinMaxRangeDrawer, RangeDrawer

EasyGUI(SerializedProperty) [back]

EasyGUI is a partial class for drawing properties(SerializedProperty).

EasyGUI(InspectableProperty) [back]

EasyGUI is a partial class for drawing properties(InspectableProperty). See Also: InspectableObject class, InspectableProperty class

InspectableObject [back]

InspectableObject and InspectableProperty are classes for editing properties on objects(System.Object) in a completely generic way that automatically handles undo and styling UI for prefabs

InspectableObject is used in conjunction with InspectableProperty and Editor classes

It exists only to make up for the problem that SerializedObject only can editing properties on UnityEngine.Object objects

See Also: InspectableProperty class

InspectableProperty [back]

InspectableProperty and InspectableObject are classes for editing properties on objects(System.Object) in a completely generic way that automatically handles undo and styling UI for prefabs

InspectableProperty is used in conjunction with InspectableObject and Editor classes. See Also: SerializedObject class

It exists only to make up for the problem that SerializedProperty only can editing properties on UnityEngine.Object objects

StateMachineHandler [back]

StateMachineHandler is a component that can be added to a state machine state. It’s the base class every handler on a state derives from

StateMachineHandler has some predefined handlers:OnStateEnterHandler, OnStateExitHandler, OnStateIKHandler, OnStateMoveHandler, OnStateUpdateHandler, OnStateMachineEnterHandler, OnStateMachineExitHandler, OnStateNormalizedTimeHandler

  • OnStateEnterHandler Execute all the actions under the action list on the first Update frame when a statemachine evaluate this state
  • OnStateExitHandler Execute all the actions under the action list on the last update frame when a statemachine evaluate this state
  • OnStateIKHandler Execute all the actions under the action list right after MonoBehaviour.OnAnimatorIK
  • OnStateMoveHandler Execute all the actions under the action list right after MonoBehaviour.OnAnimatorMove
  • OnStateUpdateHandler Execute all the actions under the action list at each Update frame except for the first and last frame
  • OnStateMachineEnterHandler Execute all the actions under the action list on the first Update frame when making a transition to a StateMachine. This is not called when making a transition into a StateMachine sub-state
  • OnStateMachineExitHandler Execute all the actions under the action list on the last Update frame when making a transition out of a StateMachine. This is not called when making a transition into a StateMachine sub-state
  • OnStateNormalizedTimeHandler Execute all the actions under the action list at each fixed interval except for the first and last frame

StateMachineAction [back]

StateMachineAction is a ScriptableObject that can be added to a state machine handler.

StateMachineAction has some predefined actions:SetBoolParameter, SetIntParameter, SetFloatParameter, SetLayerWeights, PublishEvent, PublishState, Repeat, LogMessage, DebugBreak, ExecuteDelegateAction, DelegateAction

How to create a custom actions:

// You can see them at drop down context menu when you click state machine handler's Actions [0](ReorderableList) Add(+) Button
// Use UniEasy.ContextMenuAttribute can easy to pack state machine actions into groups
[UniEasy.ContextMenu ("Actions/SetBoolParameter")]
public class SetBoolParameter : StateMachineAction
{
    // Search the script to see the details
    ...
}

EasyWriter [back]

  • Use new EasyWriter (string path) Open or Create a data file
  • Most of data should be saved as EasyDictionary<string, EasyObject>
  • WriterExtensions (EasyDictionary<string, EasyObject>) or ReactiveWriter can use Get<T> or Set<T> serialize and deserialize data

Reactive Writer [back]

The reason why we gave up reading data in the original way is that it may take longer to read data (eg. Android need to use WWW to load resources under the streamingassets folder). So we need to a lazy and we can don’t care when it was loaded way, like…

public class WriterSystem : SystemBehaviour
{
    public EasyWriter SimpleWriter;

    public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory)
    {
        base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory);

        SimpleWriter = new EasyWriter("Application.streamingAssetsPath + "/example.json");
    }

    public override void OnEnable ()
    {
        base.OnEnable ();

        SimpleWriter.OnAdd ().Subscribe (writer =>
        {
            // Use writer.Set<T> (string key, T value) and writer.SetArray<T> (string key, object value) to save the data
            // Use writer.Get<T> (string key) and writer.GetArray<T> (string key) to load the data
            // Use writer.Get<T> (string key, T target) and writer.GetArray<T> (string key, T[] target) to overwrite the MonoBehavior or ScriptableObject
            // Use writer.HasKey (string key) to check the data is exist or not
            if (writer.HasKey ("...")) {
                var b = writer.Get<bool> ("...");
            }
            // If you want to automatically Dispose when a ReactiveWriter is disposed, use AddTo(ReactiveWriter.Disposer):
            Observable.EveryUpdate().Subscribe(_ => {
                if (writer.HasKey ("...")) {
                    Debug.Log (writer.Get<string> ("..."));
                }
            }).AddTo(this.Disposer).AddTo(writer.Disposer);
        }).AddTo(this.Disposer)
    }
}

Console https://github.com/proletariatgames/CUDLR [back]

Quick Start

  • Add submodule $ git submodule add [email protected]:chaolunner/EasyFrameworkStreamingAssets.git Assets/StreamingAssets
  • Use the ~ key switch console system, Use the esc key turn off console system
  • Find the Plugins/UniEasy/Resources/Kernel/Console.prefab and select Server component
  • Set the port on the Server component (default value is 55055)
  • Add the UniEasy.Console.Command attribute to your code
  • Run the game and connect to http://localhost:55055 with your browser

How To Register Commands

[Command ("Quit", "Quit the application.", "Quit")]
public static string Execute (params string[] args)
{
    Application.Quit ();
    #if UNITY_EDITOR
    UnityEditor.EditorApplication.isPlaying = false;
    #endif
    return "Quitting...";
}

or

Console.RegisterCommand ("Quit", "Quit the application.", "Quit", (args) =>
{
    Application.Quit ();
    #if UNITY_EDITOR
    UnityEditor.EditorApplication.isPlaying = false;
    #endif
    return "Quitting...";
});

Deregister Commands

public class QuitSystem : SystemBehaviour
{
    public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory)
    {
        base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory);

        UniEasy.Console.Console.RegisterCommand ("Quit", "Quit the application.", "Quit", (args) =>
        {
            Application.Quit ();
            #if UNITY_EDITOR
            UnityEditor.EditorApplication.isPlaying = false;
            #endif
            return "Quitting...";
        }).AddTo (this.Disposer);
    }
}

Logging

public class ConsoleSystem : SystemBehaviour
{
    void Start ()
    {
        Console.Log ("output");
    }

    public override void OnEnable ()
    {
        base.OnEnable ();

        Console.RegisterLog (OnLog);
    }

    public override void OnDisable ()
    {
        base.OnDisable ();

        Console.DeregisterLog (OnLog);
    }

    void OnLog (string[] args)
    {
        Debug.Log (args.FirstOrDefault ());
    }
}

Default Commands

The console comes with some commands by default

  • HELP - Display the list of available commands or details about a specific command
  • LOADSCENE - Load the specified scene by name. Before you load scene you have to add it to the scenes in build Use File -> Build Settings… in Unity and add the .scene to the scenes in build
  • DEREGISTER - Deregister a specific command.
  • CLEAR - Clear console output.
  • Debug - Open or Close console by input debug on or debug off.
  • QUIT - Quit the application.

Shortcut key

  • Tab - Fast completion command
  • Arrow Up/Down - Input commands history
  • Enter - Execute command
  • ~ - Switch console open or colse
  • Esc - Close console
  • Click 20 times(Android/iOS) - Open console

Debugger [back]

using UniEasy.Console;

public class Example : MonoBehaviour
{
    void Start ()
    {
        Debugger.Log ("white context", "Layer 0");
        Debugger.LogWarnning ("yellow context", "Layer 1");
        Debugger.LogError ("red context", "Layer 2");
    }
}

1. Debug System Prefab Path : Assets/UniEasy/Resources/Kernel/…

2. Prefabs under the Kernel folder will auto be create when playing and Add to DontDestoryOnLoad scene

3. Debug Config File Path : Assets/UniEasy/Preferences/DebugSetting.asset

4. Selected DebugSetting you can see a IsLogEnable toggle in Inspector Window, if you select IsLogEnable for False, nothing will output on Console Window

5. You can see a ShowOnUGUI toggle in Inspector Window, It mean if you select it for true, Debug Canvas will turn on

6. You can see a DebugView List in Inspector Window, It Include Collapse, Log, Warning, Error same as unity console (click to show/hide corresponding content)

7. You can see a DebugMask List in Inspector Window, it include all you setted layer name (eg. If set Layer 0 for false white context will not be output on Console Window)

8. The new layer will auto add to DebugMask List when you do Debugger.Log (content, layer name) in editor playing

9. If you want to open the Debug Canvas in the scene, you just need to press the ~ key and input debug on or debug true then press the enter key

ScriptableObject Window [back]

1. Right click in Project Window and Select Create -> Custom Script -> ScriptableObject Window

2. You can use search or drop-down menu select a ScriptableObject (you can found all ScriptableObject in project)

3. Click Create Button create you selected class as a .asset file

Template Script Window [back]

1. Right click in Project Window and Select Create -> Custom Script -> Template Script Window

2. You can use search or drop-down menu select a IScriptAssetInstaller (you can found all IScriptAssetInstaller in project)

3. Click Create Button create you selected template script as a .cs file

Hierarchy Context Menu [back]

Base on EasyContextMenu

The ContextMenu functions you want to called must are Static. You can set the split line by setting the priority value (split line every 50 values). You even can call a method with a parameter and the parameter type must be set as System.Object. The enter parameter is you current selected Object

[ContextMenu ("GameObject/Do Something/NonParam", false, 1)]
static public void DoSomething () { ... }

[ContextMenu ("GameObject/Do Something/NonParam", true, 1)]
static public bool CheckDoSomething () { ... return true; }

[ContextMenu ("GameObject/Do Something/Param", false, 2)]
static public void DoSomething (object activeGameObject) { ... }

Search Missing Components [back]

The components on the gameObject are missing? This is a very common situation, because programmers need to modified components and can’t remember all gameObjects added these components

But we don’t want to missing components of the gameObjects exists in the scene. Of course we can code a simple script to remove all missing components. But it’s not intuitive, maybe we need know where missing component and use a new component to replace it

Fortunately, UniEasy achieved this feature. You can right click in Hierarchy Window and select UniEasy -> Search for All Missing Components Then click …

Now all gameObjects that missing components are listed in the Hierarchy Window

Ranged Int and Ranged Float [back]

you can use RangedInt or RangedFloat like :

public class Example
{
    [MinMaxRange (0, 10)]
    public RangedInt a;
    [MinMaxRange (0, 10)]
    public RangedFloat b;
}

Then you just need drag the slider to select the range in Inspector Window

Distortion (UI Effect) [back]

You can add this component to the Text component, Then you can adjust the animation curve in the Inspector Window to change the shape of the Text text You also can add it use Inspector -> Add Component -> UI -> Effects -> Distortion

Circular (UI Effect) [back]

You can add this component to Image, then you can adjust the params in the Inspector Window to change the shape of the image You also can add it use Inspector -> Add Component -> UI -> Effects -> Circular The shape of an image can be easily transformed into a circle, a sector, a ring

Restructure EasyAsset(ScriptableObject) [back]

Now you can code a ScriptableObject eg. EasyBlock : EasyAsset<string, Blockobject>

Then you can use ScriptableObject Window to create it

I also Add EasyBlock you can right click Hierarchy gameObject Select UniEasy -> Export Block or Export Block Group to export preference

The structure of the exported blocks needs to meet the following conditions

BlockGroup(GameObject) [Right Click Export Block Group]

    Block0(GameObject) [Right Click Export Block]

        Cube0(Prefab)
        Cube1(Prefab)
        ...  (Prefab)

    Block1(GameObject) [Right Click Export Block]

        Cube0(Prefab)
        Cube1(Prefab)
        ...  (Prefab)

EasyContextMenu [back]

QuickStart

1. Get all the Static methods that have ContextMenu attribute when [InitializeOnLoadMethod] called

2. Get all the UnityEngine.Object methods that have ContextMenu attribute when OnEnable() called

3. Add these methods to a special list, and then other classes that inherit the EasyContextMenu can easily call these methods

ContextMenu Buttons

Quickly add buttons for utility functions to the inspector by using UnityEngine. ContextMenuAttribute

public class ContextMenuTest : MonoBehaviour
{
    public bool isTestEnabled;

    [ContextMenu("Test Function")]
    private void MyTestFunction()
    {
        Debug.Log("Test function fired");
    }

    [ContextMenu("Test Function", isValidateFunction:true)]
    private bool TestFunctionValidate()
    {
        return isTestEnabled;
    }

    [ContextMenu("Other Test")]
    private void NonValidatedTest()
    {
        Debug.Log("Non validated test fired");
    }
}

EnumMaskDrawer [back]

You can use EnumMaskAttribute to draw a field for enum masks, eg

public enum LoadingScreenLayer
{
	Default,
	Overlay,
}

public class Example : MonoBehaviour
{
	[EnumMask]
	public LoadingScreenLayer LoadingMask = (LoadingScreenLayer)(1 << 0);
}

TypePopupDrawer [back]

You can use TypePopupAttribute to draw a type popup selection field, eg

public class Example : MonoBehaviour
{
	[TypePopup(typeof(AnimatorEvent))]
	public string EventType;
}

PrefabsUtility [back]

Selected all you want to apply changes prefabs in the Hierarchy, then right click select [UniEasy/Apply Changes To Selected Prefabs] or click the [GameObject/Apply Changes To Selected Prefabs] button on the menu bar

Selected all you want to revert changes prefabs in the Hierarchy, then right click select [UniEasy/Revert Changes Of Selected Prefabs] or click the [GameObject/Revert Changes Of Selected Prefabs] button on the menu bar

FormatUtility [back]

Selected all you want to format gameObjects in the Hierarchy, then right click select [UniEasy/Format Selected GameObjects Name] or click the [GameObject/Format Selected GameObjects Name] button on the menu bar