This project is read-only.

ninject

May 11, 2011 at 4:52 AM

Hello, Im coordinator on techcraft, a fellow codeplex project. I already integrated nuclex locally, and now i would like to refactor my codebase to use Nuclex + Components + Ninject.

I m basing my research on your Nuclex.Ninject.Xna project on svn + your ninject / sunburn article + your old ninject/xna article and code, and its quite difficult to mix all this whith drawableGameComponents and maybe even nuclex drawablecomponents without game dependency. Its the concrete use case thats difficult to handle : where should I wire the components. 

First stage would be to just make a demo/proof of concept project having just two different components writing 2 different texts on screen with the shared spritebatch.  

If you happen to have something useful but not ready for prime time, you can send it at enomi dot enomi at gmail I ll do the cleanups and implement the simple 2 texts use case.

May 11, 2011 at 10:14 AM

Hi!

I have checked out your project during various phases already :) - Nice smooth loading animation while chunks are pregenerated!

-

The download link in my Ninject+Sunburn article contained a working example application, though for some reason, the link was broken. It's fixed now. Up-to-date sources for my Nuclex.Ninject.Xna library are available from my Subversion repository: https://devel.nuclex.org/framework/svn/Nuclex.Ninject.Xna/trunk

With the updated Nuclex.Ninject.Xna library, plain old GameComponents now resolve nicely and be able to reference the Game class. It's also been ported to XNA 4.0, of course.

-

About the wiring issue, I usually design my libraries so their components just use plain interfaces for accessing their bits and pieces, without adding Ninject to the libraries themselves. This allows the libraries to be reused in projects without dependency injection and improves consistency with third party libraries like Sunburn baking Ninject right into the code isn't an option anyway.

The wiring is then performed either in my Game project or (for common stuff like Sunburn or XNA itself) by a library sitting on top of the dependency-injected library, providing a NinjectModule implementation as can be seen in my Ninject+Sunburn article's XnaModule and SunburnModule. So in your case, I'd probably have a TechCraft.dll with GameComponents and their interfaces, plus a TechCraft.Ninject.dll containing a TechCraftModule class with the bindings.

May 11, 2011 at 1:22 PM

Thanks for the quick response. And for repairing the download links !

But you re mistaken, the smooth loading animation is in the commercial xbox project fortresscraft, not in our opensource engine techcraft, these two products are not related ! 

May 11, 2011 at 1:47 PM

I haven't ever played FortressCraft :)

What I'm referring to is the rotating rectangle in 4 colors TechCraft displays while it's building the initial chunk. I thought it was cool because, if that animation can run smoothly while the GraphicsDevice is being accessed, it might eventually be able to page in and out chunks without jerky gameplay, too!

May 11, 2011 at 1:59 PM

aaahh ok now i remember ( had to ask bamyazi the original author :) , I ve been working so much on the rewrite ( NewTake project in techcraft) that I forgot this one.

May 11, 2011 at 4:08 PM

for anyone interested, the snippet i was missing was in sunburnTestGame / Program.cs / method prepgame .  

May 12, 2011 at 5:01 AM

Right, I made some progress, I can start a game with  2 simple DrawableGameComponents wired with ninject  + my world and player classes wired as ninject singletons too.  

2 questions :

 - Is there a way to bind the components in mygame.cs instead of  program.cs ? My attempts ended up in infinite loops / stack overflow exception.

 - I can not get the sharedSpriteBatch to work, I get  "The GraphicsDevice must not be null when creating new resources" in the sharedSpriteBatch constructor.

  I reference ISpritebatch in my drawableGameComponent constructor.

btw, thanks a lot for primitiveBatch, Deque, Nuclex.input , and all those other goodies !

May 12, 2011 at 10:59 AM

1. Theoretically, there's nothing preventing you from doing that. But if you try to create a GameComponent in your Game class' constructor via Ninject (Kernel.Get) and that GameComponent requires a reference back to the Game (even if it's over ISpriteBatch), this will prove unsolvable to Ninject: ame constructor creates new GameComponent requires Game instance, new Game, Game constructor creates new GameComponent, new GameComponent requires Game instance, new Game...

Usually, one sets up all bindings when the application starts (some DI frameworks even load their bindings from an XML file and offer no programmatic interface). If you require dynamic bindings (eg. switching to different implementations of an interface like IGameState), it's usually better to write a manager (eg. IGameStateManager) that performs this task. Most DI frameworks are also heavily optimized for performance in Get()/GetService() to the point of incurring some serious overhead when the bindings are set up, possibly even including dynamic compilation.

I have worked around this by moving my main game code into a GameComponent instead of having it in the Game class. In hindsight, I like this design very much because it clearly separates the concerns: the Game's responsibility is to keep the game loop running while a component, in my case typically a GameState sitting in the GameStateManager, is what maintains the logic for whatever is happening on the screen at any time.

2. That is one of two places where XNA doesn't play nice with dependency injection (the other being the GameComponent's dependency in the Game class). The GraphicsDevice is create somewhere in Game.Run() (a pretty quirky design decision if you ask me :p), so you'll have to make sure nothing that depends on the GraphicsDevice is created before Game.Run() has been called or IGraphicsDeviceService.GraphicsDevice will return null.

In my Sunburn example I achieved that by starting my game logic only after Sunburn's logo had been displayed (see prepGame()), in a pure XNA game I would instead monitor the IGraphicsDeviceService's DeviceCreated event and do my stuff after that has happened. This design also makes it possible to, for example, display something like a "Loading..." message early in the game's initialization, even before all dependencies have been resolved.

I have built a modified version of my SunburnTestGame project that only uses the ISpriteBatch (via SharedSpriteBatch) without Sunburn that shows the above: Nuclex.Ninject.TestGame.7z

 

May 13, 2011 at 3:20 AM
Edited May 13, 2011 at 5:33 AM

Thanks a lot for answers and sample project . SharedSpriteBatch now works perfectly.

Now, reading you, I would like to integrate the nuclex GameStateManager with ninject & components, maybe you could enlighten me !

I m working on a simple proof of concept :   

- WelcomeGameState , just does debug.writeln("Hello") in the update loop, and then activate the playingGameState. 

- PlayingGameState is using a FPS Component and a HudComponent, could as well be 2 different hello world components. In reality it will be skydomeComponent + FPSCompo + DiagnosticsCompo + WorldCompo + ...  

I tried for few hours, but i m lost for few reasons :

- where should the GameStateManager be plugged, plain old new in testGame, wired with the kernel in testGame, something with gameservices, or in program.prepgame()  instead of components   ?

- gamestate doesnt have a list of components, should I create my own gamestate base class with a list of components to update & draw ?

Note that when I m satisfied enough, I will push this code to the opensource TechCraft project, so you will be able to see the results of a nuclex / ninject integration in another project ; )

Thanks.

May 13, 2011 at 8:17 AM

I swear this was not an attempt to plug my GameStateManager ;-)

For global components like the GameStateManager, I'd just wire it up via Ninject (see the TestModule class in the example I posted) and everything will be taken care of when a GameComponent requires the IGameStateManager.

How you design from there is completely up to you. You could use private GameComponents in your GameStates (then it's probably a good idea to create a custom GameState class with a Components list) or you could let your GameStates add their components into the global GameComponentCollection (which is also wired up to Ninject) and remove them again when a GameState is left (this sounds like it might be more prone to error)

In the game I'm working on, I use a few global GameComponents (like the GameStateManager, InputManager and such), while the GameStates just call .Update() and .Draw() on the components that only exist in specific game states directly. If components need to be shared between multiple game states, I create a hierarchy of game states (for example, I have a MissionGameState that maintains the game's world while one of three sub-states always sits on top of it in the GameStateManager's stack, either a TargetSelectionGameState, a ConstructionGameState or a MapDisplayGameState. The MissionGameState also provides a less-global ContentManager that is cleaned up whenever the player finishes a mission.

May 15, 2011 at 3:35 AM
Edited May 15, 2011 at 3:36 AM

Okay, after more reading, here is the approach I took  :

I choose to have all components in the standard unique gameComponentCollection, and my gamestates are only enabling or disabling components. This way I still can use updateorder & draworder.

- In program.prepgame, I bind all my components (even the GameStateManager component)  in the singleton scope, not the default object/transient scope, or else i get a different instance each time.

kernel.Bind<FPSComponent>().ToSelf().InSingletonScope();
gameComponents.Add(kernel.Get<FPSComponent>());

kernel.Bind<HudComponent>().ToSelf().InSingletonScope();
gameComponents.Add(kernel.Get<HudComponent>());

GameStateManager gsm = kernel.Get<GameStateManager>();
gsm.UpdateOrder = -1;
gameComponents.Add(kernel.Get<GameStateManager>());

- In myGame.loadContent I initialize the first gamestate ( this part feels hackish, needs more work but good for now) :

GameStateManager gsm = kernel.Get<GameStateManager>();            
gsm.Push(kernel.Get<WelcomeState>());

( I added kernel as a field of MyGame, btw I think to be a real dependency injection purist there should be no ninject kernel referenced in game & no ninjectGame base class, only an xnaModule  ) 

- In my gamestates, I reference all needed components in the constructor, and let constructor injection do its magic . Then I just set the enabled / visible state of the different components in the onEntered method.

 

May 17, 2011 at 9:16 AM

Sounds good!

Yes, in an academically clean implementation, only the game's startup code should know about Ninject's Kernel class.

Non-XNA code usually binds the dependency injector of choice to the System.IServiceProvider interface in case the application wants to use it after startup is complete (ASP.NET MVC even has its own registerable factories, eg. ControllerFactory and ViewFactory that can be replaced by custom implementations using a dependency injector).

I guess something similar could be done in XNA, eg. create an IGameStateFactory like this:

/// <summary>Creates new game states</summary>
public interface IGameStateFactory {

  /// <summary>Creates a new game state of the specified type</summary>
  /// <typeparam name="TGameState">Type of game state that will be created</typeparam>
  /// <returns>The new game state</returns>
  TGameState Create<TGameState>() where TGameState : IGameState;

}

But it probably only makes sense if your goal is to keep even the game independent of the dependency injector being used.