StarlingMVC:为Starling量身打造的MVC框架

详细了解StarlingMVC框架,请登录其官方站点:

http://creativebottle.github.com/starlingMVC/

以下中文翻译转自Starling中文站,仅供部分参考之用:

http://www.starlinglib.com/wiki/News:StarlingMVC

StarlingMVC是一个为使用Starling来开发游戏的MVC框架。这个框架的特性方面,很像Swiz和RobotLegs。特性列表如下:

  • 依赖注入(DI)/控制反转(IOC)
  • 视图代理(View Mediation)
  • 事件捕获(Event Handling)
  • 非侵入性框架
  • 配置简单
  • 容易扩展
  • 包含了很多对您的游戏有帮助的工具

StarlingMVC 框架是基于 Apache License 2.0协议开源的.

目录

 [隐藏

Requirements

Contributors

安装

在线获取StarlingMVC项目并通过几行代码从Starling项目中配置StarlingMVC。你必须在Starling显示类(starling.display.*)中实例化StarlingMVC事例,并在StarlingMVCConfig中传入Starling的显示对象。

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), 
Starling.juggler];
 
            starlingMVC = new StarlingMVC(this, config, beans);
        }
    }
}

在StarlingMVCConfig类中,我们必须告诉StarlingMVC有哪些事件包和视图包以便StarlingMVC调用。beans数组实际上是一个对象集合,这个集合可以存入任何类型的对象。框架对他们进行相应的处理。

Beans

Bean是为StarlingMVC提供对象管理的一个工具,Bean可以接受注入操作,并处理相应的事件。Bean为StarlingMVC提供了几种可用的方法:

Object 实例

var beans:Array = [new GameModel(), new ViewManager(this), Starling.juggler];

Bean 多实例

var beans:Array = [new Bean(new GameModel()), 
new Bean(new ViewManager(this)), new Bean(Starling.juggler)];

上面的代码,提供了一个Bean实例,但是并没有进行任何逻辑操作。但是,这里要注意第二个参数,这个参数允许你传递一个ID,你可以通过这个ID对其进行注入操作。除此之外,Bean内还可以存储框架内的自定义类型(class type),但前提是你必须提供一个ID。如果你有两个相同的Bean对象,那么你需要指定ID,否则后面的Bean对象将覆盖掉前面的对象。例如:

var beans:Array = [new Bean(new GameModel(),
"gameModelEasy"),new Bean(new GameModel(),"gameModelHard"), 
new ViewManager(this), Starling.juggler];

BeanProvider instances

BeanProvider是Bean对象的集合。BeanProvider内提供的Bean对象可以是任何类型,也包括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()];
        }
    }
}

一旦你创建了一个BeanProvider,那么你可以将以前的所有Bean对象添加进去。

var beans:Array = [new Models(), new ViewManager(this), Starling.juggler];

ProtoBeans

ProtoBean可以在Bean对象创建的时候注入进去。在注入的时候你需要为ProtoBean传递一个类和一个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.

依赖注入

依赖注入可以用于所有的Bean对象和所有的Starling显示对象。实现方法可以使用元标签来实现getting/setting的方式来存取,注入的实现方法如下:

package com.mygame.controllers
{
    public class GameController
    {
        [Inject]
        public var gameModel:GameModel;
 
        public function GameModel():void
        {
 
        }
    }
}

或者指定一个ID,当你创建Bean对象的时候指定一个ID:

package com.mygame.controllers
{
    public class GameController
    {
        [Inject(source="gameModel")]
        public var gameModel:GameModel;
 
        public function GameModel():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 GameModel():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")].

Events

Dispatching Events

Events in StarlingMVC are dispatched in one of two ways: 1) StarlingMVC contains a global instance of starling.events.EventDispatcher. The quickest way to dispatch an event into the StarlingMVC framework is to use this dispatcher. This dispatcher can be injected into your bean by using the [Dispatcher] metadata tag. 2) DisplayObjects can dispatchEvents using their own dispatchEvent() method. This is only available to DisplayObjects and the events must set `bubbles=true'.

Handling Events

Event handlers are denoted by using the [EventHandler(event="")] metadata tag on a public method of a bean. The event argument in the tag can contain one of two options: the event type string

package com.mygame.controllers
{
    public class GameController
    {
        [EventHandler(event="scoreChanged")]
        public function scoreChanged(event:ScoreEvent):void
        {
 
        }
    }
}

or the typed event

package com.mygame.controllers
{
    public class GameController
    {
        [EventHandler(event="com.mygame.events.ScoreEvent.SCORE_CHANGED")]
        public function scoreChanged(event:ScoreEvent):void
        {
 
        }
    }
}

By using the second approach, you will gain the benefit that StarlingMVC will type check any of the events during initialization and throw and error if the event or event type doesn't exist. This protects against typos.

In both examples above, the handler must accept the type of the dispatched event to handle. However, a second optional parameter exists in the EventHandler tag that will allow you to specify specific properties of the event to use as parameters to the event handler. For example:

package com.mygame.controllers
{
    public class GameController
    {
        [EventHandler(event="com.mygame.events.ScoreEvent.SCORE_CHANGED", 
properties="user, newScore")]
        public function scoreChanged(user:User, newScore:int):void
        {
 
        }
    }
}

In the above example, instead of passing the entire event into the handler, StarlingMVC will pass only the "user" and "newScore" properties. Note that the types must match or an error will be thrown.

View Mediation

View mediators are a great way of keeping your view classes separate from the code that controls them. A view mediator is set up just like any other bean. To link a view to a view mediator a [ViewAdded] metadata tag is used on a public method. When a DisplayObject is added to the stack, StarlingMVC will look for instances of the ViewAdded tag. If the parameter of any ViewAdded methods are of the type of the view that was just added, the new DisplayObject will be passed to that method. To unlink a mediator from a view when the view has been removed the [ViewRemoved] metadata tag is used.

package com.mygame.mediators
{
    public class GameMediator
    {
        private var view:Game;
 
        [ViewAdded]
        public function viewAdded(view:Game):void
        {
            this.view = view;
        }
 
        [ViewRemoved]
        public function viewRemoved(view:Game):void
        {
            this.view = null;
        }
    }
}

Bean 生命周期

Normal beans are set up on initialization. However, since the dependency injection and event handling happens after creation bean values are not available immediately. To receive notification of when a bean has been fully processed we can add the [PostConstruct] tag to a public method. This method will be automatically called when all DI has been completed. Similarly, when a bean is being destroyed we can specify a public method to be called with the [PreDestroy] tag. This works in all standard beans and DisplayObjects.

package com.mygame.controllers
{
    public class GameController
    {
        [Inject]
        public var gameModel:GameModel;
 
        [PostConstruct]
        public function postConstruct():void
        {
            // set up code here
        }
 
        [PreDestroy]
        public function preDestroy():void
        {
            // tear down code here
        }
 
        [EventHandler(event="com.mygame.events.ScoreEvent.SCORE_CHANGED", 
properties="user, newScore")]
        public function scoreChanged(user:User, newScore:int):void
        {
 
        }
    }
}

Bean的创建/删除

通过Bean可以手动的创建和移除系统中的事件侦听。BeanEvent.ADD_BEAN会侦听系统中添加和处理一个新的Bean。BeanEvent.REMOVE_BEAN会侦听系统中移除Bean。

package com.mygame.view
{
    public class Game
    {
        public var gamePresentationModel:GamePresentationModel;
 
        [PostConstruct]
        public function postConstruct():void
        {
            gamePresentationModel = new GamePresentationModel();
 
            dispatchEvent(new BeanEvent(BeanEvent.ADD_BEAN, 
gamePresentationModel));
        }
 
        [PreDestroy]
        public function preDestroy():void
        {
            dispatchEvent(new BeanEvent(BeanEvent.REMOVE_BEAN, 
gamePresentationModel));
 
            gamePresentationModel = null;
        }
    }
}

在上面的例子中,我们创建了一个演示模型,它被作为一个Bean对象添加到StarlingMVC。下面我们来看一下如何管理Bean中的事件。

EventMap

EventMap是一个用于创建和管理事件侦听器的实用工具类。使用EventMap可以很容易清理类中的监听。

package com.mygame.mediators
{
    import com.creativebottle.starlingmvc.events.EventMap;
 
    public class GameMediator
    {
        private var eventMap:EventMap = new EventMap();
 
        [ViewAdded]
        public function viewAdded(view:Game):void
        {
            eventMap.addMap(view.playButton,TouchEvent.TOUCH, 
playButtonTouched);
            eventMap.addMap(view.instructionsButton,TouchEvent.TOUCH, 
instructionsTouched);
        }
 
        [ViewRemoved]
        public function viewRemoved(view:Game):void
        {
            event.removeAllMappedEvents();
        }
 
        private function playButtonTouched(event:TouchEvent):void
        {
 
        }
 
        private function instructionsButtonTouched(event:TouchEvent):void
        {
 
        }
    }
}

ViewManager

ViewManager是一个工具类,通过它可以用来在舞台上添加删除视图。当我们创建ViewManager事例的时候,我们需要传递一个根显示对象。这样我们通过ViewManager可以在Starling的任意位置方便的添加可视化交互内容。

setView

调用setView方法,将删除现有的视图,同时添加一个新的视图。ViewManager会将新的视图自动实例化并添加到堆栈中。

package com.mygame.controllers
{
    public class NavigationController
    {
        [Inject]
        public var viewManager:ViewManager;
 
        [EventHandler
(event="com.mygame.events.NavigationEvent.NAVIGATE_TO_VIEW", 
properties="viewClass")]
        public function navigateToView(viewClass:Class):void
        {
            viewManager.setView(viewClass);
        }
    }
}

添加视图

调用addView方法将在现有视图上添加一个新的视图。这里通过addView方法将GameHUD类型的视图添加到现有视图管理器中。

package com.mygame.views
{
    public class Game
    {
        [Inject]
        public var viewManager:ViewManager;
 
        private var hud:GameHUD;
 
        [PostConstruct]
        public function postConstruct():void
        {
            hud = new GameHUD();
 
            viewManager.addView(hud);
        }
    }
}

移除视图

通过调用removeView可以删除堆栈中制定的视图。

移除所有视图

调用removeAll可以移除堆栈中存在的所有视图。当你调用setView()的时候这个方法会被自动调用。

猜你喜欢

转载自kenkao.iteye.com/blog/1768608