Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[RELEASED] StrangeIoC - Inversion-of-Control Framework for Unity C#

Discussion in 'Assets and Asset Store' started by srimarc, Jun 13, 2013.

  1. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    ThirdMotion and I are parting ways (on great terms). What does this mean for StrangeIoC and for you?

    http://wp.me/p3VbXx-2S
     
  2. nsxdavid

    nsxdavid

    Joined:
    Apr 6, 2009
    Posts:
    476
    Some curiosities about StrangeRocks:

    Given the View/Controller concept, it seems odd to me that ship control input is interpreted and acted on in, for instance, the ShipView. And, as I look deeper, only some of the input as firing is handled in the Mediator. Wouldn't it be better to have a command for input that handles it all?

    Similarly I'm wondering why the AI (such as it is) for an Enemy is in the EnemyView. Given the classic definition of a view in MVC type patterns, this seems wrong.

    Am I misunderstanding something?

     
  3. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Hello,

    I'm a Strange newbie and I'm trying to shoehorn it to my development process. I'm really confused. What I want to achieve is I want some injection to the View components that are added in editor time (attached to GameObject already). I used MyFirstProject scene and added a dummy GameObject and attached an ExampleView component. I get a NullPointerException when I play it. The mediator binding runs because an ExampleMediator is added to the object but its 'dispatcher' variable is null. The dispatcher in ClickDetector is also null.

    Code (csharp):
    1. [Inject]
    2. public IEventDispatcher dispatcher{get;set;}
    So why can't Strange inject an instance to a view that is added to a GameObject in editor time? It seems injection only works when the view component is added via AddComponent(). I want this to work because our designers make levels using the Unity scene editor. Is there another way to make this work?
     
  4. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    davenirline,

    Injections will certainly work on any View, regardless of whether they're placed in the scene programmatically or at author time, and regardless of whether or not they are prefabs. The key to understanding them, however, is knowing when the injection occurs. When the View fires its Awake() method, it attempt to contact the Context (remember that the injection mappings live in the Context, not the View). This may or may not succeed, because the Context itself may or may not have been able to instantiate by that time. If it fails, the View will try again at Startup(). Either way, until the View makes contact with the Context, there can be no injecting.

    Now, one thing you could do is manipulate the script execution order in Unity and make sure that the Context executes first. That'll work, but it's not really a replacement for understanding the order of things under-the-hood. A better answer, IMO, is to use your Mediator to tell you when injections are safe to address. The Mediator's OnRegister() method fires immediately after injection. Thus, if a View has an Init() method, and the Mediator calls view.Init() as part of its own OnRegister(), you know exactly when your injections have been satisfied.

    HTH!

    [EDIT]I should probably also point out that injecting directly into Views, while allowed, is often poor form. We allow injection into Views since there are some good use cases for this...especially when the injection is explicitly View-related. But definitely err on the side of injecting into the Mediator, not the View.[/EDIT]
     
    Last edited: Feb 5, 2014
  5. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    So you're quite right about the enemy "AI". My only excuse on this is that I rushed StrangeRocks out over Xmas break. Given the tutorial nature of the project, I should definitely correct this.

    The ShipView is a different matter. The Input itself is via a controller (see strangerocks/game/controller/input). Whether that control comes from a Keyboard/Joystick/TapController/etc makes no difference to the View or Mediator. The Mediator receives a Signal indicating the current input value and sets the current state of input onto the View. The View simply takes the possible types of input and decides how to apply those values to the RigidBody. Now in a pure MVC world, the View probably wouldn't interact quite so closely with a physics body. But this is Unity, and we compromise because RigidBody is definitely part of Unity's world (my philosophy -- all puns intended -- has always been "render unto Unity that which is Unity's"). In short, the View is where we touch Unity most directly. Physics is definitely Unity's job, and I'm content to let it do its job.
     
  6. nsxdavid

    nsxdavid

    Joined:
    Apr 6, 2009
    Posts:
    476
    While I totally understand that, the ramifications for a MVC pattern are pretty severe in my opinion. Mainly that when I walk into any unknown code base that uses MVC, I at least know where to look for things. But, for me at least, I found StrangeRocks' use of StrangeIOC's MVCS giving me a lot less code navigation hints than I would have thought, and in some cases completely tripping me up.

    While I understand the uncomfortable relationship of the view vs. components, having game logic in the view still doesn't seem right. After all, the "Render unto Unity that which is Unity's" is a slipper slope grey area. Why do you treat touching the Rigidbody from input signals as a view thing vs. updating a score being done from, say, a mediator. As patterns go, I'd wager that's to colloquial and arbitrary.

    Could not the same thing be accomplished by having a command interpret the input signals and then command >> mediator >> view?
     
  7. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Thanks srimarc. I'll try your suggestions. I also found that the multiple context sample also throws the same error. I tried it since one of the objects in the game scene already has the View component attached. I don't know if that should be fixed. I ran it using the main scene.
     
  8. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    I don't know if this is a silly question. Is there such a thing as cross context mediation binding? I've successfully set-up a cross context environment. I've got injection binder and command binder working in different contexts. What I want to achieve is to map mediation in only those context that supposedly knows about them. What happens is I'm repeating mediation mapping in those contexts that needs it.

    Code (csharp):
    1.  
    2.     /**
    3.      * Context for input layer management
    4.      */
    5.     public class InputLayerManagementContext : SignalContext {
    6.        
    7.         /**
    8.          * Constructor
    9.          */
    10.         public InputLayerManagementContext(MonoBehaviour contextView) : base(contextView) {
    11.         }
    12.        
    13.         protected override void mapBindings() {
    14.             base.mapBindings();
    15.  
    16.                         ...
    17.  
    18.                         // this should only be invoked here
    19.             mediationBinder.Bind<InputProcessorView>().To<InputProcessorMediator>();
    20.         }
    21.        
    22.     }
    23.  
    Right now, I have to invoke the mapping in other contexts as well. If not, no mediator would be added to the view (no binding).

    Code (csharp):
    1.  
    2.     public class PlayerCharacterContext : SignalContext {
    3.  
    4.         /**
    5.          * Constructor
    6.          */
    7.         public PlayerCharacterContext(MonoBehaviour contextView) : base(contextView) {
    8.         }
    9.  
    10.         protected override void mapBindings() {
    11.             base.mapBindings();
    12.  
    13.             ...
    14.  
    15.                         // I should no longer need to do this in other contexts
    16.             mediationBinder.Bind<InputProcessorView>().To<InputProcessorMediator>();
    17.         }
    18.  
    19.     }
     
  9. Zynx87

    Zynx87

    Joined:
    Oct 31, 2013
    Posts:
    9
    This is probably a simple question - I'm confused how constructors with parameters are provided when I am trying to inject them.
    My novice brain wants to do this:
    [Inject]
    NoiseGenerator noise (pScale, pOctaves) {get; set;}

    or perhaps, attempt to set the variables like noise.pScale, although this doesn't work either.

    I've read over setter and constructor injection in the HowTo, although I still fail to see how parameters get passed in.
    Another way to put it: one example in the HowTo shows Spaceship(IWeapon weapon) selected as the construct, but I do not know how to pass in the weapon.

    Thanks for any assistance.
     
  10. WilliamBNewton

    WilliamBNewton

    Joined:
    Nov 18, 2013
    Posts:
    54
    So here's what I gathered from looking around in Strange...

    Code (csharp):
    1.  * Dependencies may be Constructor injections (all parameters will be satisfied),
    2.  * or setter injections.
    3.  *
    4.  * Classes utilizing this injector must be marked with the following metatags:
    5.  * <ul>
    6.  *  <li>[Inject] - Use this metatag on any setter you wish to have supplied by injection.</li>
    7.  *  <li>[Construct] - Use this metatag on the specific Constructor you wish to inject into when using Constructor injection. If you omit this tag, the Constructor with the shortest list of dependencies will be selected automatically.</li>
    8.  *  <li>[PostConstruct] - Use this metatag on any method(s) you wish to fire directly after dependencies are supplied</li>
    9.  * </ul>
    So, from what I understand this means that as long as the Constructor parameters are bound in the injection binder, when a new instance of the class is created it'll inject the parameters into the constructor. However, those parameters can't be named injections or come from a pool. It's unclear to me if they can be singletons, but I'm sure they can. I'm also fairly sure you could inject a pool itself. After the Constructor is run, any setter injections will be satisfied, and then the post construction method(s) will be called if they're marked.

    I will say this, if you're having trouble with strange, the best possible way to learn is to look through the code to see what is actually going on.
     
  11. WilliamBNewton

    WilliamBNewton

    Joined:
    Nov 18, 2013
    Posts:
    54
    Ok, so I was curious if I was correct on the way injection works as far as setter injections and constructor injections, as well as post construction injections. So I wrote a little test.

    Code (csharp):
    1.     public class ContextRoot : ContextView
    2.     {
    3.         void Start()
    4.         {
    5.             context = new ExampleContext(this);
    6.            
    7.         }
    8.     }
    9.  
    10.     public class SignalContext : MVCSContext
    11.     {
    12.         public SignalContext(MonoBehaviour contextView): base(contextView)
    13.         {}
    14.  
    15.         protected override void addCoreComponents()
    16.         {
    17.             base.addCoreComponents();
    18.             injectionBinder.Unbind<ICommandBinder>();
    19.             injectionBinder.Bind<ICommandBinder>().To<SignalCommandBinder>().ToSingleton();
    20.         }
    21.  
    22.         public override void Launch()
    23.         {
    24.             base.Launch();
    25.             StartSignal startSignal = (StartSignal)injectionBinder.GetInstance<StartSignal>();
    26.             startSignal.Dispatch();
    27.         }
    28.  
    29.         protected override void mapBindings()
    30.         {
    31.             base.mapBindings();
    32.         }
    33.     }
    34.  
    35.     public class StartSignal : Signal
    36.     {
    37.     }

    Code (csharp):
    1.     public class ExampleContext : SignalContext
    2.     {
    3.  
    4.         public ExampleContext(MonoBehaviour contextView)
    5.             : base(contextView)
    6.         {
    7.         }
    8.  
    9.  
    10.         protected override void mapBindings()
    11.         {
    12.             commandBinder.Bind<StartSignal>().To<ExampleStartCommand>().Once();
    13.  
    14.             injectionBinder.Bind<int>().To(4).ToName("exampleInt");
    15.             injectionBinder.Bind<IExampleModel>().To<ExampleModel>().ToName("exampleModel");
    16.             injectionBinder.Bind<IExampleModel>().To<ExampleModelInjected>().ToName("injectionModel");
    17.             injectionBinder.Bind<ExampleModelConstructOne>().To<ExampleModelConstructOne>();
    18.             injectionBinder.Bind<ExampleModelConstructTwo>().To<ExampleModelConstructTwo>();
    19.         }
    20.  
    21.         protected override void postBindings()
    22.         {
    23.             base.postBindings();
    24.         }
    25.     }
    So the important part here is the bindings. We have one int bound to 4 with the name "exampleInt" and four classes all implementing "IExampleModel". Two of them with names, and two bound to themselves seeing how they're meant to be construction injections, and you can't use names on construction injections.

    Here's what IExampleModel and it's implemented classes look like:

    Code (csharp):
    1.     public interface IExampleModel
    2.     {
    3.         int Number { get; }
    4.     }
    5.  
    6.     public class ExampleModelInjected : IExampleModel
    7.     {
    8.         private int number = 3;
    9.  
    10.         public int Number
    11.         {
    12.             get { return number; }
    13.         }
    14.     }
    15.  
    16.     public class ExampleModelConstructOne : IExampleModel
    17.     {
    18.         private int number = 1;
    19.  
    20.         public int Number
    21.         {
    22.             get { return number; }
    23.         }
    24.  
    25.     }
    26.  
    27.     public class ExampleModelConstructTwo : IExampleModel
    28.     {
    29.         private int number = 2;
    30.  
    31.         public int Number
    32.         {
    33.             get { return number; }
    34.         }
    35.     }
    36.  
    37.     public class ExampleModel : IExampleModel
    38.     {
    39.  
    40.         [Inject("injectionModel")]
    41.         public IExampleModel injectedModel { get; set; }
    42.  
    43.         [Inject("exampleInt")]
    44.         public int injectedInt { get; set; }
    45.  
    46.         private int totalOfAllNumbers;
    47.  
    48.         private int combinationOfConstructionNumbers;
    49.  
    50.         [Construct]
    51.         public ExampleModel(ExampleModelConstructOne one, ExampleModelConstructTwo two)
    52.         {
    53.             combinationOfConstructionNumbers = (one.Number + two.Number);
    54.             Debug.Log(combinationOfConstructionNumbers);
    55.         }
    56.  
    57.         [PostConstruct]
    58.         public void PostConstruct()
    59.         {
    60.             Debug.Log((injectedInt + injectedModel.Number));
    61.             totalOfAllNumbers = injectedModel.Number + combinationOfConstructionNumbers + injectedInt;
    62.         }
    63.  
    64.         public int Number
    65.         {
    66.             get { return totalOfAllNumbers; }
    67.         }
    68.     }
    So IExampleModel only contains a get for "Number". Three of the four classes contain a private int (1, 2, and 3 respectively) that Number points to. The last class is where all of the injection takes place. In the Constructor ExampleModelConstructOne and ExampleModelConstructTwo are injected into the properties and added together. At this point the setter injected model is not available. I tested this by adding this code to the constructor:

    Code (csharp):
    1. if (injectedModel != null)
    2. {
    3.     Debug.Log("available");
    4. }
    which didn't print to the console. So the Numbers of the Constructor models are added together.

    Then the Setter Injections take place and the method marked with [PostConstruct] is called. In PostConstruct() the setter injections are added to the constructor injections and all placed in the private int "totalOfAllNumbers". The final thing to not is that "Number" in the final model refers to "total of all numbers".

    So to test this all out I call the command mapped to the StartSignal:

    Code (csharp):
    1.     public class ExampleStartCommand : Command
    2.     {
    3.  
    4.         [Inject("exampleModel")]
    5.         public IExampleModel exampleModel { get; set; }
    6.  
    7.  
    8.         public override void Execute()
    9.         {
    10.             Debug.Log(exampleModel.Number);
    11.         }
    12.     }
    Which injects the exampleModel and then prints the contents of "Number" (which should be 10) to the console.

    If you hook this all up the output in the console is
    Code (csharp):
    1. 3
    2. 7
    3. 10
    Which is exactly what you'd expect. I've included the scripts and the text scene. Just import the package as well as strange and it should work.
     

    Attached Files:

  12. Zynx87

    Zynx87

    Joined:
    Oct 31, 2013
    Posts:
    9
    Appreciate the advice William - I'm realizing now that having classes requiring parameters in their constructors may not be the best fit for the framework. This Noise class was something I just pulled from the internet and was looking to plug it in without modification, but I'm guessing the nature of the class itself goes against the framework by requiring concrete dependencies.
    I started thinking that maybe sending a signal to my noise class with the required information may be the appropriate approach.
    Currently I had my noise set as a model, and the Bible states DON'T ALLOW MODELS AND SERVICES TO LISTEN FOR EVENTS(!).
    My current understanding of model is "a class that contans data and methods that act solely on its own data", and I've now realized that Noise already violates this by requiring input. This being the case, I'm going to start looking at breaking up this Noise into a command that receives the necessary input and the model that holds the data.
    Sorry, I realize this is all just my own thought process to a solution - maybe others that come across it might find it helpful.

    EDIT: Thanks for the insight, just saw the additional post above, your perception of the framework it much better than mine. That is a solution I hadn't managed to work out. I'll have to sit and think for a while whether my signal --> command --> model approach or your solution would be a better fit. It seems to me the key difference is the use of signals versus the use of constructor injection.
     
    Last edited: Feb 12, 2014
  13. WilliamBNewton

    WilliamBNewton

    Joined:
    Nov 18, 2013
    Posts:
    54
    Just one thing to keep in mind, not all Controllers have to be commands or signals.

    In my current project I have the basics for a simple state machine that kicks off after the initial setup commands build out a level. The main game "update" sets off a coroutine using the routine runner class that's available in strangerocks, and then has whichever yieldInstruction needed passed to it through child IStates, each containing a "StateRunner" class that handles iterating through each state's IEnumerators.

    I use signals to pass information about the states back and forth, commands whenever something needs to happen and to my "view manager" class and my "model manager" class , but the whole thing itself isn't anything that would require strange.

    From just the documentation it seems like you're only suppose to use the obvious "View, Mediator, Command, Signal" classes and anything not fitting that is a model or service, but that's just not true. strangerocks kicks off ISpawners (in coroutines) from commands, but they aren't commands, and they send and recieve signals.

    While MCVS is a great way to program, just remember that you can stick to that without sticking completely to strange. Any variables that need to be stored are Models. Anything that needs to happen are Controllers. Anything that interacts with the user is a View. Anything that needs to interact with the outside is a Service.
     
  14. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Hey WilliamBNewton,

    Really, really appreciate you stepping up to answer questions! (I've been on vacation and only rarely checking in on threads) I love that Strange has started to develop a community of experts who can help each other. Please keep it up.

    WRONG! Anything that isn't Strange is bad!!! ;)

    Of course you're entirely correct. Strange is just a framework to get you 90% of the way there. I firmly believe that every principle has its exceptions...especially when we live in Unity's MonoSpace! Take everything Strange recommends with a grain of salt: examine it critically and decide if it meets your needs for the given problem (it should do...most of the time).
     
  15. nsxdavid

    nsxdavid

    Joined:
    Apr 6, 2009
    Posts:
    476
    I think strange has some solid ideas, but the implementation of the MVCS pattern still baffles.

    The Mediator for instance seems pointless, despite all the admonishments to the contrary. It is supposed to provide a "buffer" between the Views and the rest of the app. But I don't see in what way it does that. In all of the examples of Mediators in StrangeRocks, there's no real sense that it adds any value nor any real buffer. Just addiing an object in between two objects that pass events along doesn't seem to be of any particular isolating value.

    You might say it "isolates" the view, but the view is still dependent on the mediator. So what was gained? How is the ShipView listening on the gameInputSingal any worse than relying on the ShipMediator to listen on that and call a method on the ShipView?

    What did this fix? What scenerio are we afraid of? Just saying it isolates the views chaos from the app doesn't really mean anything all by itself. It's still dependent on the mediator and the mediator to just relay info with little or not thinking on its part. I just don't get it.
     
  16. asheeshv

    asheeshv

    Joined:
    Nov 22, 2013
    Posts:
    4
    Hi Marc,

    I've started evaluating StrangeIoC since last couple of days, and I find it totally awesome. The kind of flexibility and code structuring it provides is just great. I was trying to understand the framework more through the StrangeRocks game that you've posted on Github. I'm able to figure out the multiple contexts being used in the game, however, I'm not able to locate the code which launches the game. I know there are three contexts, main, ui, and game, and in each of those context, there's a startSignal which is bound to the startupcommand accordingly for the main, Ui, and game. The main startup command loads the ui and the game contexts. The UI startup command doesn't do anything, and the game start signal is bound to GameModuleStartCommand, but that doesn't do anything. It's a No-op. I was wondering how exactly is the very first UI screen is launched. I know the button events for start game, and start level are mapped to the commands, so that part works totally, but how is the very first screen launched, I haven't been able to figure out. I know it's running under a tight loop, but just haven't been able to figure it out. I'd appreciate if you can provide some inputs as to the launch of the game under multiple contexts that'd be great.

    Once again thanks for a great Unity framework.
     
  17. nsxdavid

    nsxdavid

    Joined:
    Apr 6, 2009
    Posts:
    476
    @asheeshv

    One of the things patterns that StrangeIoC promotes is reducing the dependencies that lead to rigid, spaghetti code bases. The down side of all this decoupling is that everything starts to look disembodied rather than being part of a whole. This is especially true when you try to follow the execution chain of source code, like you are.

    Ironically it seems one hell gets replaced by another. I spent a lot of time trying to connect the dots of Strangerocks too. I found the experience to be very different than disentangling spaghetti code, but the time and mental effort required nearly identical. It also doesn't help that, especially in the case of Strange's patterns, so many files are involved. A class for every command? So much more boiler-plate skeleton code is required (similar thing in uFrame) that you use up a lot of eye-strain just trying to find the meat of stuff.

    But how one functional unit leads to another is sometimes difficult to discern. Worse, once you get two, three, twelve, of these indirections in your head you start to run out of mental capacity to keep a map of it. That's the point at which I question the wisdom.

    I love the binding mechanism, and the dependency injection (to a point). I dislike the way in which signals map to commands, and way in which commands are implemented in general. Conversely I love the idea of sequences of commands. The MVCS pattern seems unusually implemented in Strange, even though I like such patterns in general. That unusualness leads one to have more difficulty rather than less figuring out where to find stuff in, at least, Strangerocks.
     
  18. asheeshv

    asheeshv

    Joined:
    Nov 22, 2013
    Posts:
    4
    Thanks for the response nsxdavid. I agree with you it takes a while to wrap one's head around the StrangeIoC usage, it gets confusing at time. Though overall, I'm really impressed with the way you can architect and structure your game using the MVCS pattern, which is great for maintenance and future revisions. The binding and the injection works just great, though there is that extra code one has to write for all the indirections. It's like a trade-off, that you get clean, maintainable, and well-architected code but at the same time some verbosity which usually is the case for such frameworks.

    I was able to answer my question by figuring out that as soon the injection binding is done for the mediator, it is instantiated, and in its OnRegister method which serves as a constructor, initiates the view and sets it up for display, alongside adding a listener for the signal within that view. I wasn't able to connect this piece initially but after looking closely, it became clear to me. Though I'd say there's a fair learning curve for this framework initially, but I hope that it eventually pays and is worth it.
     
  19. GermyGames

    GermyGames

    Joined:
    May 20, 2012
    Posts:
    38
    I'm seeing something weird in one of my projects: When I have two views attached to a gameobject in the editor, two mediators will get added for the second view. If you add the second view at runtime, only one mediator is added.

    Another super weird thing is if you then swap the positions of the view components before running, you don't get two mediators.

    I'm guessing that two views on a gameobject is a big no-no if something like this is happening, but there is a lot of power in having multiple views.
     
  20. Zynx87

    Zynx87

    Joined:
    Oct 31, 2013
    Posts:
    9
    I'm having some difficulty attempting to resolve my "attempt to instantiate a null binding."
    I've attempted to follow along with strangerocks, where my TerrainModel is much like its GameModel, and I have to inject it into my NoiseCommand much like it does with its StartLevelCommand in order to set its properties.
    Within my context I've bound ITerrainModel to TerrainModel To Singleton with no luck. Additionally setting my noisecommand to singleton and a few other odd things.
    Specifically, the error says I'm attempting to instantiate a null binding and targets NoiseCommand.

    Any suggestions would be appreciated.

    EDIT: Found the issue, simple mistake - initially I didn't have an interface for my TerrainModel, as I didn't see the need for one because for now the code is entirely duplicate. I only added it in an attempt to be more like strangerocks to figure out the issue. So I had injected TerrainModel terrainmodel in my NoiseCommand , and failed to fix the injection to ITerrainModel. Works fine for now, I feel I will attempt to get it working without the interface.
     
    Last edited: Feb 23, 2014
  21. asheeshv

    asheeshv

    Joined:
    Nov 22, 2013
    Posts:
    4
    Guys,

    I'm trying to create a brand new sample using StrangeIoC, and I'm running into the following scenario.

    So, here's what I'm doing.
    1. I've created a parent game object by the name of HomeContextView, and have assigned the script MainContext that instantiates the GameContext.
    2. In the GameContext, I do the following
    public class MainContext : MVCSContext
    {
    public MainContext(MonoBehaviour contextView) : base(contextView)
    {
    }


    public MainContext(MonoBehaviour contextView, ContextStartupFlags flags): base(contextView, flags)
    {
    }


    protected override void addCoreComponents ()
    {
    base.addCoreComponents ();
    injectionBinder.Unbind<ICommandBinder> ();
    injectionBinder.Bind<ICommandBinder> ().To<SignalCommandBinder> ().ToSingleton ();
    }


    public override IContext Start()
    {
    base.Start();
    StartSignal startSignal = (StartSignal)injectionBinder.GetInstance<StartSignal>();
    startSignal.Dispatch();
    return this;


    }


    protected override void mapBindings()
    {
    base.mapBindings ();
    mediationBinder.Bind<HomeView>().To<HomeViewMediator>();
    commandBinder.Bind<StartSignal> ().To<GameStartCommand> ().Once();

    }


    protected override void postBindings()
    {
    base.postBindings();
    }
    }

    3. I created two new classes HomeView, and HomeViewMediator. In the HomeView I simply injected the HomeView so that it calls its init method as mentioned in some of the strange samples.

    4. I also created another GameObject, and assigned the HomeView script to that game object.

    Now when I execute the program in Unity I get the following mediation exception.
    A view was added with no context. Views must be added into the hierarchy of their ContextView lest all hell break loose.

    I haven't been able to figure out as to what am I missing out on, or what am I doing things incorrectly?

    Any help here would be highly appreciated.

    Thanks,
    Asheesh
     
  22. asheeshv

    asheeshv

    Joined:
    Nov 22, 2013
    Posts:
    4
    I posted this query in Strange's google group account where wcorwin replied to it. He suggested me to try the script execution order, and that fixed the problem for me. It appears that there's a known bug in Strange though it doesn't show up to everyone, but in case it shows up, this is the solution to that issue. Sharing this information with others.

    Thanks,
    Asheesh
     
  23. wikiup

    wikiup

    Joined:
    Sep 15, 2013
    Posts:
    1
    Hi all, just a quick post to let y’all know that Will Corwin and I are organizing a Strange meetup at GDC next week.

    Date: Thursday, 20th March
    Time: Noon, ’til we get bored
    Place: Jamber (http://www.yelp.com/biz/jamber-san-francisco)

    Hope to see you there!
     
  24. NmpTech

    NmpTech

    Joined:
    Apr 23, 2014
    Posts:
    3
    Hello,

    I just wanted to let you know we've shipped a Windows Phone 8 game using StrangeIoC framework and we've been very pleased! It's a 3d-platformer called Project: Steal. Website http://www.projectsteal.com

    I might write a more detailed post how we exactly used it (if anyone is interested), but here's some tidbits:

    - We used EventCommand only for certain very high-level actions such as moving back/forward in menus, sharing highscore at the facebook, bootstrapping level, etc.

    - Many gameobjects contains only View which then instanciates a controller which handles per frame logic. More complicated objects like pathfinding enemies have both View and Model for better separation of designer/artist tweakable properties. E.g. Enemy View would have death fx parameter, mesh, death sound fx and so on. And Enemy Model would have movement speed, hitpoints and such.

    - Models doesn't listen for events, just like documentation suggests.

    - CrossContext is useful and makes it easy to separate HUD / UI from game logic. We made one level scenefile and on level bootstrap game would additively load HUD scene :)

    - I can't recall having any WP8 platform related problems with StrangeIoC.

    Thanks.

    //TechGuy @ NMP Games
     
  25. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    @TechGuy,

    Very cool looking game. Awesome work.

    Would love to get a more detailed write up on how you used StrangeIoC. Would really help all of us to understand how to use StrangeIoC in a real world scenario. It could be a series of small blogs.

    1. How is the performance.
    2. What to look out for.
    3. General architectural tips.

    Cheers.
     
  26. pretender

    pretender

    Joined:
    Mar 6, 2010
    Posts:
    862
    Hi! Since there are not much tutorials it would be appreciated if NpTech could share his experience :) thanks!
     
  27. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,551
    The thing is it's going to be difficult to see it because looking at strangerocks as it is is like seeing a snapshot of a product in development. We don't know how many times the code in ShipView was changed. Imagine working in a project where people keep on making so many tweaks on the UI or the way the player is controlled, if there was no isolation, every change might have required changing so many of the codebase as a whole too. Strangerocks is a very simple game so it's hard to see such a case there.

    However, I'd say that you'd want to use a mediator only when you need it. Indeed, you can make the code work without it.




    I admit I found it difficult to understand the code in strange rocks as a whole.

    I don't think it's required to always use commands though.

    Think of signals like C# delegates/events, it's just that you can use injection on them. They're like functions-as-variables, right? So you can use them that way. Use AddListener() RemoveListener() and pass the function you want to get called, then call Dispatch() on the signal to actually fire the signal.

    And it's certainly ok to use the injection features without using the MVC framework that Strange offers.

    At least, that's how I understand it.
     
  28. ScottDC

    ScottDC

    Joined:
    Jun 13, 2014
    Posts:
    4
    How does the StrangeRocks RoutineRunner get initialised and injected?

    I've tried incorporating the classes/interface into my code, but it's not injected into my command.

    Edit: Never mind - must have had my namespaces messed up.
     
    Last edited: Jun 13, 2014
  29. maliceCO

    maliceCO

    Joined:
    Jun 26, 2014
    Posts:
    4
    Is possible break a command InSequence?
     
  30. noooodley

    noooodley

    Joined:
    Jun 25, 2013
    Posts:
    4
    Hello all,

    I am curious what your recommendations are for injecting dependencies into MonoBehaviours with StrangeIoC.

    Constructor injection is out of the question since we cannot access the constructor, and setter injection makes me a bit uneasy as it breaks encapsulation. In an attempt to avoid setter injection, I extended Strange to include another attribute, [PseudoConstruct]. When a public method is tagged with [PseudoConstruct], its arguments are resolved similarly to how a constructor's arguments are resolved by Strange. This means you can initialize / pseudo-construct a MonoBehaviour without setter injection. Here is a simple example:

    Code (CSharp):
    1. public class PrintScript : View {
    2.    private IPrinter printer;
    3.  
    4.    [PseudoConstruct]
    5.    public void PseudoConstruct(IPrinter printer) {
    6.       this.printer = printer;
    7.    }
    8. }
    A method tagged by [PseudoConstruct] is executed after [Construct] and before [PostConstruct]. This solution seems elegant to me, but I could be missing something. What do you think?
     
    Last edited: Jun 29, 2014
  31. Grahammmm

    Grahammmm

    Joined:
    Jun 4, 2013
    Posts:
    12
    Hello,

    I have a quick question I'm hoping someone can help me with:

    Is it possible to bind a mediator to the base class of a view?

    Given views Aview and Bview that both extend Pview. I would like one mediator that is used for both.

    Thanks in advance!
     
  32. gabrielgiordan

    gabrielgiordan

    Joined:
    Jul 4, 2012
    Posts:
    1
    Hello!

    First of all, thanks for the awesome framework @srimarc, I'm using it in my new projects and I'm loving it!

    Here's one workaround for have access on MonoBehaviour's StartCoroutine:

    Code (CSharp):
    1.     public class MainBootstrap : ContextView
    2.     {
    3.         void Awake()
    4.         {
    5.             CrossContext myContext = new MainContext(this);
    6.             myContext.injectionBinder.Bind<MonoBehaviour>().ToValue(this).CrossContext();
    7.  
    8.             context = myContext;
    9.         }
    10.     }
     
  33. TokyoDan

    TokyoDan

    Joined:
    Jun 16, 2012
    Posts:
    1,080
  34. Grim_Reaper

    Grim_Reaper

    Joined:
    Nov 5, 2013
    Posts:
    32
  35. Texaggie96

    Texaggie96

    Joined:
    Jan 23, 2009
    Posts:
    81
    I am running into timing issue with strangeioc. I have a monobehaviour that is supposed to be injected with a signal. However the signal is not injected before the first tick of Update(). Thus the signal is null and throws and error. Shouldn't signals be injected before the first tick of Update(). Here is my code:
    Code (csharp):
    1.  
    2. public class StartCommand : Command
    3. {
    4.      [Inject(ContextKeys.CONTEXT_VIEW)]
    5.      public GameObject contextView{get;set;}
    6.  
    7.      public override void Execute()
    8.      {
    9.         // JavascriptMessenger is a MonoB so I attach it to the ContextView
    10.        JavascriptMessenger jMessenger = contextView.AddComponent<JavascriptMessenger>();
    11.  
    12.        // spawn the vehicle gameobject; pretty standard
    13.        string vehicleName = "MyCoolCar";
    14.        GameObject vehiclePrefab = Resources.Load<GameObject> (vehicleName) as GameObject;
    15.        GameObject vehicleGO = GameObject.Instantiate (vehiclePrefab) as GameObject;
    16.  
    17.        // Get the car settings component on the vehicle.
    18.        CarSettings carSettings = vehicleGO.GetComponent<CarSettings>() as CarSettings;
    19.  
    20.        // register delegates
    21.        carSettings.TractionAxleCallBack = jMessenger.TractionAxleUpdate;
    22.      }
    23.    }
    24.  
    JavascriptMessenger.cs
    Code (csharp):
    1.  
    2.    using System;
    3.    using UnityEngine;
    4.    using strange.extensions.context.api;
    5.    using strange.extensions.dispatcher.eventdispatcher.api;
    6.  
    7.    public class JavascriptMessenger : MonoBehaviour {
    8.  
    9.      [Inject]
    10.      public Set4x4Signal set4x4Signal {get; set;}
    11.  
    12.      public void TractionAxleUpdate(int axle)
    13.      {
    14.        Debug.Log ("axle update received: " + axle.ToString());
    15.  
    16.        if (axle == 2)
    17.          set4x4Signal.Dispatch(true);
    18.        else
    19.          set4x4Signal.Dispatch(false);
    20.      }
    21.    }
    22.  
    CarSettings will fire off TractionAxleCallBack during its first tick of Update(). JavascriptMessenger.TractionAxleUpdate receives it just fine. However, the signal, set4x4Signal, has not been injected yet, causing this the Dispatches() to NullReference exception. Have I misconfigured this somehow?
     
  36. wcorwin

    wcorwin

    Joined:
    Feb 7, 2014
    Posts:
    9
    Sorry folks, I had totally forgotten that we had a thread here. We tend to see all of our activity on github and google group
     
  37. wcorwin

    wcorwin

    Joined:
    Feb 7, 2014
    Posts:
    9
    @Texaggie96:

    In general we have a few best practices you might find useful. First off, you'll find using views and mediators far superior to simple monobehaviours, as we solve all of these problems and decouple the code in a better way. It also gives our code a more focused, single-concern pattern.

    Additionally you are never going to get injections automatically. A monobehaviour being added to a contextview has no code telling it to do anything. It's not recommend to simply refer to the contextView directly and addcomponent, anyways. I'd probably recommend using Instantiate/Resources.Load to generate prefabs.

    I'd recommend a look at the Big Strange How-To to better understand some of the best practices and fundamentals of the framework!

     
  38. Texaggie96

    Texaggie96

    Joined:
    Jan 23, 2009
    Posts:
    81
    I need a MonoB similar to the GameLoop in the multiple context example. Parts of the program are done in Javascript and I need the rest of the program (done in Strange) to interface with those pieces. I am creating a javascript messenger to receive those javascript events and convert them into signals to work with the rest of Strange. I was attaching it to ContextView because that is what was done for GameLoop MonoB. I tried adding injection binding to value (similar to lines 57-58 on StartAppCommand, multicontext example) to my StartCommand right after attaching the component.
    Code (csharp):
    1.  
    2. injectionBinder.Bind<JavascriptMessenger>().ToValue(jMessenger);
    3.  
    But this is not triggering injection inside JavascriptMessenger. I guess the injection won't be invoked until another instance needs a JavascriptMessenger injected (similar to GameLoop and ITimer).
     
    Last edited: Feb 12, 2015
  39. Texaggie96

    Texaggie96

    Joined:
    Jan 23, 2009
    Posts:
    81
    Well adding a command that injects the MonoB bound to a value worked (e.g. in the multiple context example - GameOverCommand injects the ITimer) and actually triggers the injection in the MonoB (GameOverCommand, and others injecting ITimer, are what is causing the actualy injection happening inside GameLoop). I did something similar and now it works.
     
  40. Anatolii_Landyshev

    Anatolii_Landyshev

    Joined:
    Aug 10, 2012
    Posts:
    31
    Hi.

    I'm using StrangeIOC in my current project. I follow MVCS pattern and bind all my models as singleton:
    Code (CSharp):
    1. injectionBinder.Bind<IInterface>().To<Model>().ToSingleton();
    But now I have the case when one model FootballField contains a list of Footballer models and I need to create Footballer classes inside FootballField model to fill that list.

    I tried mapping Footballer as a factory:
    Code (CSharp):
    1. injectionBinder.Bind<IFootballer>().To<Footballer>();
    And inside FootballerField class:
    Code (CSharp):
    1. [Inject]
    2. public IFootballer footballer { get; set; }
    3.  
    4. private List<IFootballer> _footballers = new List<IFootballer>();
    5.  
    6. public void Init()
    7. {
    8.     for (int i = 0; i < 22; i++) {
    9.         _footballers.Add(footballer)
    10.     }
    11. }
    In this case should _footballers list be filled with different instances of Footballer class? Or will it add same instance on every iteration?
    Should I use new operator instead?
     
  41. wcorwin

    wcorwin

    Joined:
    Feb 7, 2014
    Posts:
    9
    In the future just ask the question in one place. Response is on google groups :) Hope it helped!

    For anyone who needs the answer, a factory only supplies a single injection. You're better off looking at pooling for this, or using an injected list and managing it yourself.
     
  42. TokyoDan

    TokyoDan

    Joined:
    Jun 16, 2012
    Posts:
    1,080
    I'm still trying to get my head around StrangeIoC, but with no luck. It seems that one of the problems it is supposed to solve, namely dependency spaghetti, is more than offset by the complexity of using it.

    Trying to figure out what is going on I spend probably more time going back and forth, here and there, between numerous (way too many) files than I would trying to track brittle dependencies in my code.
     
  43. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    Try this setup tutorial.
     
  44. notoriousFF

    notoriousFF

    Joined:
    Jan 19, 2016
    Posts:
    1
    A have a question about the setup of Strange on a project.
    Do I create a Context for every "part" of the game? For example would I create a AudioContext : MCVSContext, EnemyContext..., PlayerContext...., MenuContext.... etc?
    Is that the idea? Having this Contexts as Binding "fathers" for the framework?