Coder Social home page Coder Social logo

karma's Introduction

What is Karma?

MVC Framework for Unity3D

Karma is an MVC framework for Unity3D. Because of how Unity is structured, it actually turns out to be an MVCP architecture (Model/View/Controller/Presenter) where the Presenter is a MonoBehaviour that serves as an intermediary between the Controller and the View. You can read more about this in MODEL VIEW CONTROLLER PATTERN FOR UNITY3D USER INTERFACES.

Based on Zenject

It's built on top of Zenject which provides Dependency Injection (DI). DI is mainly used to route the app to the desired view, it also enables us to build composable and testable systems.

Inspired by AngularJS and ASP vNext

Some of the basic constructs and code layout is inspired by other MVC frameworks such as AngularJS and ASP vNext.

Note to Game Developers

Karma uses concepts like views and presenters instead of scenes. The problem with scenes is that they are too heavy weight, there is no good way to communicate between them, changing scenes is slow (especially if you are doing UI stuff), and they aren't composable. The "Karmic" way of doing a game would be to store each level/scene in a prefab, treat it as a MVC View, store all your characters/entities in separate prefabs, and get them instantiated onto the level's view through DI.

Simple Routing System

Karma has a built in routing system that enables you to create isolated views/scenes as prefabs and easily switch between them. Using an http-like flow, a presenter can Request the router to render another view.

As Stateless as possible

Karma aims to be as stateless as possible to try to give you the guarantee that if you entered a view once with certain Request parameters and reached a successful state, then you will always reach that same state if you pass the the same parameters. Unity3D doesn't provide by default a best practice changing from a view to another. A common way to do this is to have all possible views instantiated in the scene but only enable the current one, the problem is that you maintain state when reusing Game Objects and often end in bad states because of the many paths you need to account for. Karma keeps things simple and functional by just destroying the current view and instantiates a new next view when changing views.

Message Passing

In Karma state is mainly maintained through message passing, being as true as possible to Go's philosophy:

Don't communicate by sharing memory; share memory by communicating.

The added benefit of this is that views become configurable without depending on local storage or static variables, is in turn is very important to keep a system testable.

Pub/Sub System

All Presenters integrate a pub/sub system that enables the communication between entities on different branches and levels in the dependency hierarchy. It's a simple yet powerful message passing mechanism on channels by topic where any Presenter can subscribe and broadcast. By convention the top level application is used as the main channel.

Folder Structure + Conventions

As many MVC frameworks, Karma tries to keep the developers sane by establishing conventions. Among these conventions are the folder structure, concepts (presenters, controllers, services, etc), code organization, a configuration mechanism (dev, prod, test environments).

Parts

  • Views
    • Plain old prefabs
  • Presenters
    • Handle the presentation layer
    • Extend MonoBehaviour
    • Are tied to a Prefab
    • Get instantiated on Game Objects
    • Integrate a Pub/Sub mechanism
    • Are Transient
    • Are divided as:
      • Plain Presenter (Routable)
      • Elements (Reusable)
      • Layouts (Provide context)
  • Controllers
    • Handle the logic layer
    • Don't extend MonoBehaviour
    • Are Transient
    • Are 100% testable
    • Are usually coupled to a Presenter
  • Services
    • Handle Resources
    • Should be Stateless
    • Are Singleton
    • Usually handle communication with a server on a particular resource, local storage, specialized logic for e.g. handling certain user inputs, etc.
  • Applications
    • Handle general configuration
    • Are Presenters
    • Contain the current view
    • Can be nested to create subviews
  • Router
    • Belongs to a specific Application
    • Tells the application which view to render next
    • Can store request history
  • Middleware
    • Each application can configure its one pipeline
    • Each middleware can modify the Request and Response
    • Enables to e.g. create an authentication layer separate from the view itself
    • It's asynchronous so e.g. http requests can be made to the server to get extra information

Why Karma?

Unity3D doesn't give much structure

While good developers do follow certain conventions, new developers struggle to keep their project in order. Karma provides conventions for both code structure and folder organization so you can keep your project clean and productive.

Composable elements

Mainly thanks to Zenject, with Karma you can create composable elements that you can reuses through your application. Defining you all the components in your view/level directly in the hierarchy, with Karma you define each subcomponent in a separate prefab with their own presenter, and get them to you current view through DI. This way you avoid these common problems:

  • Finding components in hierarchy (you can stop abusing GameObject.Find)
  • Having to update prefabs that are also nested in other prefabs
Testable components

One of the major goals of Karma is testability. This is achieved through these mechanisms:

  1. Configurable transient views
  2. POCO Controllers and Services that are 100% mockable
  3. Dependency Injection

Getting Started

Sample Project

The easiest way to get started is to clone this repository and open it with Unity3D. It contains a sample project layout with an Application, Presenter, Controller and a Service. Just

git clone https://github.com/cgarciae/karma.git

and open the karma folder with Unity3D. Then open the scene /Assets/App/App.unity and hit play!

Integrating it with your project

The easiest way to integrate Karma with your own project is to clone this repo with

git clone https://github.com/cgarciae/karma.git

and then copy the folders /Assets/App and /Assets/Lib to your project.

Zenject Contexts

Karma was built to work without any other library-specific stuff, like Zenject Contexts - and by default this means that contexts are wiped. To use your Zenject context features, like installers, scene persistent objects, etc. you need to enable the Use Zenject Context checkbox, which you will find on your Karma App gameobject (using the Unity Editor).

Videos
Hello World

Hello World

Dependency Injection

Dependency Injection

Pub Sub

Pub Sub

Guides

Coming soon!

karma's People

Contributors

cgarciae avatar sacredskull avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

karma's Issues

Error in Example App

Can you please help me in resolving this?

ZenjectException: Unable to resolve type 'Karma.IRouter' while building object with type 'MenuPresenter'.
Object graph:
MenuPresenter

Zenject.DiContainer.Resolve (Zenject.InjectContext context) (at Assets/Lib/Karma/Zenject/Source/Main/DiContainer.cs:753)
Zenject.DiContainer.InjectExplicitInternal (System.Object injectable, System.Type injectableType, Zenject.InjectArgs args) (at Assets/Lib/Karma/Zenject/Source/Main/DiContainer.cs:1133)
Zenject.DiContainer.InjectExplicit (System.Object injectable, System.Type injectableType, Zenject.InjectArgs args) (at Assets/Lib/Karma/Zenject/Source/Main/DiContainer.cs:1046)
Zenject.DiContainer.InjectExplicit (System.Object injectable, System.Collections.Generic.List1 extraArgs) (at Assets/Lib/Karma/Zenject/Source/Main/DiContainer.cs:1008) Zenject.DiContainer.Inject (System.Object injectable, IEnumerable1 extraArgs) (at Assets/Lib/Karma/Zenject/Source/Main/DiContainer.cs:1794)
Zenject.DiContainer.Inject (System.Object injectable) (at Assets/Lib/Karma/Zenject/Source/Main/DiContainer.cs:1788)
Zenject.LazyInstanceInjector.LazyInjectAll () (at Assets/Lib/Karma/Zenject/Source/Main/LazyInstanceInjector.cs:65)
Zenject.DiContainer.FlushInjectQueue () (at Assets/Lib/Karma/Zenject/Source/Main/DiContainer.cs:314)
Zenject.SceneContext.Resolve () (at Assets/Lib/Karma/Zenject/Source/Install/Contexts/SceneContext.cs:269)
Zenject.SceneContext.RunInternal () (at Assets/Lib/Karma/Zenject/Source/Install/Contexts/SceneContext.cs:137)
Zenject.RunnableContext.Run () (at Assets/Lib/Karma/Zenject/Source/Install/Contexts/RunnableContext.cs:36)
Zenject.RunnableContext.Initialize () (at Assets/Lib/Karma/Zenject/Source/Install/Contexts/RunnableContext.cs:22)
Zenject.SceneContext.Awake () (at Assets/Lib/Karma/Zenject/Source/Install/Contexts/SceneContext.cs:113)
UnityEngine.GameObject:AddComponent()
Karma.App:CreateZenjectContext() (at Assets/Lib/Karma/Karma/App.cs:89)
Karma.App:Awake() (at Assets/Lib/Karma/Karma/App.cs:56)

Support for NUnit 3

Because the Unity 5.6 has new NUnit 3, I'm getting errors on TestStatus and ExpectedExceptionAttribute.

Karma & ZenjectSceneLoader

I have a scene that I want to load, and ideally share context with. It seems like ZenjectSceneLoader is an appropriate way to load in the new scene, but It doesn't seem like Karma's organization allows for that.

If I include:

[Inject]
public void PostConstructor(ZenjectSceneLoader sceneLoader)...

then I receive the following error:

Zenject.ZenjectException: Unable to resolve type 'ZenjectSceneLoader' while building object... 

If I also include the following in Startup.Configure:

container.Bind<ZenjectSceneLoader> ().FromResolve ().AsSingle ();

then I receive the following error instead:

Zenject.ZenjectException: Assert hit! Found circular dependency when creating type 'Zenject.ZenjectSceneLoader'

ZenjectSceneLoader depends on a SceneContext, which as far as I can tell is not created. It seems that neither SceneContext nor ProjectContext are created when using Karma. Is the intention to only use vanilla Dependency Injection from Zenject without bothering with a lot of the extra features of Zenject?

Prevent child objects from being applied to a prefab

Hello there,

i came up with another problem that exists because of the philosophy of composing elements and align them separately during runtime.
Imagine you got a hierarchy like:
App > Start > Environment Camera Canvas
If you apply your changes now to the Start Element that is a single prefab itself, it also saves it's children that you maybe applied for testing purposes in your hierarchy. But nevertheless this has to be a single prefab (without any children) because you want to instantiate and apply children to it while in runtime.
According to this topic:
http://answers.unity3d.com/questions/225304/is-there-a-hideflagsdontsave-equivalent-for-preven.html
I assume that unity still didn't come up with a solution on their own, so what i wanted to ask you is how you manage to do it. What's your workflow?

Greetings,
Joe

Models?

Hello there,

what are the models in karma?

videos are private

The Youtube videos on the main github page are private. I guess this is because of some Youtube update recently, which changed some videos to private (I think all unlisted videos).

Transitions

Is there a way to define smooth transitions between views? For instance, when using router.Goto() I'd like the new view to slide in from the right, and the old view to slide off the left.

All compile errors have to be fixed before you can enter playmode!

I am new to Unity, although an experienced developer. I immediately gravitated to this project as testing is critical and love DI. I followed the Readme file, basically cloning the repo, installing Unity 2019.1.0 (April), opening the project, loading up Assets/App and clicking Play. It won't play because there are at least 90 compile errors, mostly from not finding the Zenject classes:

Assets\Lib\Karma\Zenject\OptionalExtras\Signals\Internal\Binders\DeclareSignal\DeclareSignalAsyncTickPriorityCopyBinder.cs(3,6): error CS0246: The type or namespace name 'NoReflectionBakingAttribute' could not be found (are you missing a using directive or an assembly reference?)

I have tried doing this under both Ubuntu 18.04 and Windows 10 Pro. What am I missing? Thank you.

Scene Loading

Hello there,

there is another question that came up to my mind recently.
How do you determine whether a scene (another view so to speak) is fully loaded asynchronously (e.g. while in loading screen)? I know that there is an app.ready property returning boolean.
But how do you exactly switch to another level (view instance) if it's fully loaded.

Could you please make an example for that one?
Also interesting to know would be how you usually share objects between different scenes.

With best regards,
Joe

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.