StarlingMVC
IOC Framework for Starling based games
Install / Use
/learn @CreativeBottle/StarlingMVCREADME
StarlingMVC Framework
StarlingMVC is an IOC framework for use in games built using the great Starling framework. Closely modelled after established IOC frameworks like Swiz and RobotLegs, StarlingMVC features:
- Dependency Injection(DI)/Inversion of Control(IOC)
- View Mediation
- Event Handling
- Stays out of the way of your Starling game code
- Simple configuration
- Easily extended
- More utilities to help with your game code
StarlingMVC Framework is provided under the Apache License 2.0.
Requirements
Contributors
Setup
Getting your Starling project configured to work with StarlingMVC requires only a few lines of code. From your base Starling display class (starling.display.*), you need to create an instance of StarlingMVC and provide it the root Starling display object, an instance of StarlingMVCConfig, and some Beans.
package com.mygame.views
{
import com.creativebottle.starlingmvc.StarlingMVC;
import com.creativebottle.starlingmvc.config.StarlingMVCConfig;
import com.creativebottle.starlingmvc.views.ViewManager;
import com.mygame.models.GameModel;
import starling.core.Starling;
import starling.display.Sprite;
public class GameMain extends Sprite
{
private var starlingMVC:StarlingMVC;
public function GameMain()
{
var config:StarlingMVCConfig = new StarlingMVCConfig();
config.eventPackages = ["com.mygame.events"];
config.viewPackages = ["com.mygame.views"];
var beans:Array = [new GameModel(), new ViewManager(this)];
starlingMVC = new StarlingMVC(this, config, beans);
}
}
}
The StarlingMVCConfig instance above tells StarlingMVC which event packages and view packages it should mediate. The beans Array is merely a collection of objects. The array can accept an object of any type. The framework will handle it accordingly.
Additional setup steps for Flash Builder
When exporting release builds using Flash Builder, the ActionScript compiler will strip out non-standard metadata unless it is instructed otherwise. StarlingMVC's custom metadata is required in order for powerful features such as automatic dependency injection (DI) to work correctly and so the removal of the metadata can effectively render your application useless.
Preventing the removal (or "stripping") of StarlingMVC's custom metadata is simple and just requires some additional compiler arguments to be set for your project.
To add the additional compiler arguments, right-click your project and click Properties. Next go to "ActionScript Compiler" and under "Additional compiler arguments" add the following:
-keep-as3-metadata+=Dispatcher
-keep-as3-metadata+=EventHandler
-keep-as3-metadata+=Inject
-keep-as3-metadata+=Juggler
-keep-as3-metadata+=PostConstruct
-keep-as3-metadata+=ViewAdded
-keep-as3-metadata+=ViewRemoved
You will now be able to export release builds and StarlingMVC will function as expected.
Beans
A Bean is an instance of an object that is provided to StarlingMVC to manage. Beans can be injected, receive injections, and handle events. There are several ways that beans can be provided to StarlingMVC during setup:
Object instance
var beans:Array = [new GameModel(), new ViewManager(this)];
Bean instances
var beans:Array = [new Bean(new GameModel()), new Bean(new ViewManager(this))];
Providing a Bean instance as shown above does not give much benefit. However, there is an option second parameter to thw Bean constructor that allows for an id. If you provide an id then you can use the id during dependency injection. Additionally, beans are stored within the framework by class type unless you provide an id. So if you have two beans of the same type you will need to specify an id or subsequent beans will overwrite the previous beans. For example:
var beans:Array = [new Bean(new GameModel(),"gameModelEasy"),new Bean(new GameModel(),"gameModelHard"), new ViewManager(this)];
BeanProvider instances
A BeanProvider is a collection of Beans. The beans within the provider, like with a simple array, can be of any type, including BeanProvider.
package com.mygame.config
{
import com.creativebottle.starlingmvc.beans.BeanProvider;
import com.mygame.assets.AssetModel;
import com.mygame.models.AudioModel;
import com.mygame.models.GameModel;
public class Models extends BeanProvider
{
public function Models()
{
beans = [new GameModel(), new Bean(new AudioModel(),"audioModel"), new AssetModel()];
}
}
}
Once you have your BeanProvider set up, you can pass that as a part of your original beans array.
var beans:Array = [new Models(), new ViewManager(this)];
ProtoBeans
A ProtoBean is a bean that is created at the time of injection. Where normal beans require a class instance, a ProtoBean requires a class and an id.
var beans:Array = [new ProtoBean(Character,"character"), new ViewManager(this)];
Using a ProtoBean here will allow StarlingMVC to create the instances of this class for you. Each time it is injected, it will be a new instance of the, in this case, "Character" class instead of using a singleton like a normal Bean. The advantage to allowing the framework to create the class over just using "new Character()" is that when StarlingMVC creates the instance it will run injection and all processing on the created instance.
Dependency Injection
Dependency injection occurs on all beans and all Starling display objects. A dependency is denoted with an Inject metadata tag over a public property or getter/setter. Injection can be done by type:
package com.mygame.controllers
{
public class GameController
{
[Inject]
public var gameModel:GameModel;
public function GameController():void
{
}
}
}
or by id, if an id was specified when the bean was created:
package com.mygame.controllers
{
public class GameController
{
[Inject(source="gameModel")]
public var gameModel:GameModel;
public function GameController():void
{
}
}
}
In the above example, if the GameModel is a normal bean, the framework will set the value to the singleton instance that was created during setup. If it was a protobean, a new instance will be created and injected into the property.
Starling also supports injecting properties of beans. In order to use this functionality, the source Bean must contain an id (i.e. new Bean(new GameModel(),"gameModel");). To inject a property of a bean, simply append the property name to the end of the id parameter in your Inject tag:
package com.mygame.controllers
{
public class GameController
{
[Inject(source="gameModel")]
public var gameModel:GameModel;
[Inject(source="userModel.currentUser")]
public var currentUser:User;
public function GameController():void
{
}
}
}
In the example above, the value of the currentUser property on the userModel bean would be injected into the currentUser property of our controller. This functionality is also recursive. If you wanted to inject the first name of the currentUser you could potentially use [Inject(source="userModel.currentUser.firstName")].
Binding
The InjectProcessor also supports a very simple binding mechanism that will cause injected properties to be automatically refreshed when they are changed.
package com.mygame.controllers
{
public class GameController
{
[Inject(source="gameModel")]
public var gameModel:GameModel;
[Inject(source="userModel.currentUser", bind="true")]
public var currentUser:User;
public function GameController():void
{
}
}
}
The example above uses the optional bind="true" parameter of the [Inject] tag to create a binding. When the currentUser property of the userModel is updated StarlingMVC will automatically update any injections using binding. This will also work with getter/setters methods. Using these will allow code to easily react to changes in the properties.
package com.mygame.controllers
{
public class GameController
{
[Inject(source="gameModel")]
public var gameModel:GameModel;
[Inject(source="userModel.currentUser", bind="true")]
public function set currentUser(value:User):void
{
_currentUser = value;
// Do something to update your UI with the new value
}
public function get currentUser():User
{
return _currentUser;
}
private var _currentUser:User;
public function GameController():void
{
}
}
}
Binding is connected directly to the Starling juggler instance and will check for changes on each bound property everytime the advanceTime() method is called. This does not provide a binding that works as instantaneously as Flex binding. Binding should be used sparingly as there is still overhead to check for changes to the bound properties.
As an alternative to auto bound properties, StarlingMVC supports binding through invalidation. This method is much more efficient than the auto bound properties because it give you much more control over when properties are updated. This is done through an injected Bindings class and the optional "auto" parameter.
package com.mygame.controllers
{
public class GameController
{
[Inject(source="gameModel")]
public var gameModel:GameModel;
[Inject(source="userModel.currentUser", bind="true", auto="false")]
public function set currentUser(value:User):void
{
_currentUser = value;
// Do something to update your UI with the ne
