Robotlegs2中文教程-1使用MVCBundle

Robotlegs2中文教程-1使用MVCBundle

本系列全部文章:using robotlegs2

目的

本章使用Robotlegs2自带的MVCBundle实现一个简单的MVC实例。

Robotlegs2在架构设计上,框架仅实现了生命周期管理、Logger、消息调度、插件管理器、配置管理器等核心功能,其他功能全部使用插件实现。而MVCBundle,就是Robotlegs2提供的一个插件和配置集合,这个集合包含所有MVC需要的插件和功能。

本章不会研究Robotlegs2在结构上的设计,而是从最终用户的角度来使用MVCBundle。若希望了解Robotlegs2的架构,请关注本系列后续文章。 继续阅读Robotlegs2中文教程-1使用MVCBundle

Robotlegs2中文教程-概述

Robotlegs2中文教程-概述

起因

好久没写长文了,感觉平时写代码多了,在遣词造句上逐渐生疏起来。博客也慢慢写得七零八落,彻底沦为只有自己能看懂的个人笔记(当然,对我来说这并没有什么不好 :))。

趁介绍Robotlegs2的机会,锻炼一下文笔,看看自己还有没有被废掉。

本文开始的时候,Robotlegs2的版本为b6。此时,网上完全找不到像样的中文介绍,更别说文档了。即使是在Robotlegs2官网知识库,也没有系统的学习资料,只有爱好者们写的一些Sample,或者框架作者以及资深用户在回答网友问题的时候形成了一些有用的资料。当然,还有框架源码中可爱的README以及源码注释。

Robotlegs2有一个漫长的发展期。正因为这个“漫长”,导致了网上找到的一些依赖“旧版本”的Robotlegs2制作的sample无法在新版本上运行。前段时间,Robotlegs的作者闭关了一段时间,框架的进展突然加速,接连发布了几个beta版本。到了现在的b6版本,整个框架已经比较稳定了。

我在 Github 上watch了Robotlegs2项目,每天都能收到关于框架的最近进展与issue。框架的两个作者关于功能的讨论相当活跃和激烈,即使是在我写本文的过程当中,某几个类的位置都发生过变动。两个作者甚至在讨论修改SwiftSuspender的问题。因此,在 框架release 之前,我不会深入到源码级别进行介绍。

本系列教程会比较长,完整目录会在这里更新:using robotlegs2继续阅读Robotlegs2中文教程-概述

Starling框架帮助手册中文版

如果你因为 对Adobe的失望 不愿意再学习Stage3D,而选择了其它语言。那么在转换的这段痛苦的时间里,不如继续利用Stage3D的GPU加速功能开发2D游戏吧!如果你决定这样,那么一定不要错过 Starling

Starling 是一个基于Stage3D所开发的一个能够使用GPU来加速的2D Flash 应用程序的ActionScript3 框架。

Facebook上的Flash版《愤怒的小鸟》,就使用了这个框架。

这里是ByteArray.org提供的《Introducing Starling》,介绍该框架的使用方法。

英文版下载:

  Introducing Starling (8.2 MiB, 801 hits)

中文版下载(S_eVent翻译):

  Introducing Starling中文版 (1.8 MiB, 1,369 hits)

Signals框架介绍(三)原生事件

注意:本文参考An introduction to AS3 Signals写成,但不是翻译,有增删改。


原生事件

为了达到替换AS3事件机制的目的,Signals当然包含了对AS3原生事件的支持。这依赖于NativeSignal类。

下面的范例演示了如何在Stage上添加单击事件。由于一看就懂,这里就不废话解释了。

[NativeSignalSample.as]

package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import org.osflash.signals.natives.NativeSignal;

[SWF(width=500,height=300,frameRate=30,backgroundColor=0xFFFFFF)]
/**
 * 测试原生事件
 * @author zrong(zengrong.net)
 */
public class NativeSignalSample extends Sprite 
{
    public function NativeSignalSample()
    {
        _click = new NativeSignal(this.stage, MouseEvent.CLICK, MouseEvent);
        _click.add(handler_click);
        //测试只发生一次的点击事件
        //_click.addOnce(handler_click);
    }

    private var _click:NativeSignal;

    private function handler_click($evt:MouseEvent):void
    {
        trace('currentTarget:',$evt.currentTarget);
        trace('target:',$evt.target);
    }
}
}

其它资料

Signals框架介绍(一)基本用法

注意:本文参考An introduction to AS3 Signals写成,但不是翻译,有增删改。


Signals是一个基于AS3的轻量级事件框架,它被设计用来代替AS3内置的Event框架。

为什么我们要放弃Event框架,改用Signals呢?原因主要有以下几点:

  1. 使用AS3内置的Event框架,必须继承EventDispatcher或者自行实现IEventDispatcher,而Signals使用组合,可以避免继承;
  2. 使用AS3内置框架在事件中实现值的传递,必须自定义事件类才可以。而Signals可以方便的实现多个强类型值的传递;
  3. Signals不使用字符串来区分不同的事件,而是使用实例;
  4. Signals的速度更快,据说是AS3内置事件机制的4倍。

来看个简单的例子吧,这个例子中的闹钟会叫我们起床。此范例部分源码来自An introduction to AS3 Signals

基本用法

先看看闹钟类AlarmClock.as

package
{
import org.osflash.signals.Signal;

/**
* Signals闹钟范例
* @author Aiden Tailor(http://www.developria.com/2010/10/an-introduction-to-as3-signals.html)
* @author zrong(zengrong.net)
*/

public class AlarmClock
{
    public function AlarmClock()
    {
        alarm = new Signal();
    }

    /**
     * 声明一个Signal实例用来发送Signal
     */
    public var alarm:Signal;

    public function ring():void
    {
        //发布闹钟的响铃事件
        alarm.dispatch();
    }
}
}

再来看看起床类Wakeup.as

package
{
import flash.display.Sprite;

[SWF(width=500,height=300,frameRate=30,backgroundColor=0xFFFFFF)]
/**
 * 测试闹钟
 * @author Aiden Tailor(http://www.developria.com/2010/10/an-introduction-to-as3-signals.html)
 * @author zrong(zengrong.net)
 */
public class Wakeup extends Sprite
{
    public function Wakeup()
    {
        _alarm  = new AlarmClock();

        //向alarm注册事件,这里不需要提供任何的事件名称。因为alarm就是一个确定的Signal实例。
        _alarm.alarm.add(handler_ring);

        //使用addOnce,让alarm在事件收到一次后立即取消
        //_alarm.alarm.addOnce(handler_ring);

        _alarm.ring();
        _alarm.ring();
    }

    private var _alarm:AlarmClock;

    /**
     * 由于我们并没有在事件中传递参数,因此这里的方法也不需要提供任何参数。
     */
    private function handler_ring():void
    {
        trace('起床了!!!');
    }
}
}

在进行事件注册的时候,我们使用的是AlarmClock的public属性alarm。在面向对象编程中,这种方式是不可取的。但我们现在只是个范例对么?不要要求那么严格好不好?

当然,如果你知道在AS3中,使用get方法会比直接使用public属性的性能低不少,或许你也会让这种“不规范”的编程方法延续下去?

取消事件注册

如果运行这个范例,应该可以看到2条“起床了!!!”的trace信息。然后,取消addOnce一行的注释,并注释掉add那行,让它们变成这样:

public function Wakeup()
{
    _alarm  = new AlarmClock();

    //向alarm注册事件,这里不需要提供任何的事件名称。因为alarm就是一个确定的Signal实例。
    //_alarm.alarm.add(handler_ring);

    //使用addOnce,让alarm在事件收到一次后立即取消
    _alarm.alarm.addOnce(handler_ring);

    _alarm.ring();
    _alarm.ring();
}

再次运行范例,应该只能看到1条trace信息了。你可以把这种现象理解成原来的AS事件机制中的removeEventDispatcher被自动执行了。

当然,手动移除也是可以的。如果你使用的是add方法注册,可以使用下面的方法来移除事件的注册。

_alarm.alarm.remove(handler_ring);
_alarm.alarm.removeAll();

传递参数

看看传递参数有多简单吧……修改AlarmClock.as中的相关代码:

public function AlarmClock()
{
    //让我们传递一个AS3的标准Date对象吧,让那个懒虫知道现在几点
    alarm = new Signal(Date);
}

public function ring():void
{
    //把当前的时间发出去
    alarm.dispatch(new Date());
}

再修改Wakeup.as中的相关代码:

private function handler_ring($date:Date):void
{
    trace('起床了!!!也不看看几点了:'+$date.toString());
}

就这样,不需要该死的继承Event和重写clone()了,是不是很清净呢?

Signals框架介绍(二)高级事件

注意:本文参考An introduction to AS3 Signals写成,但不是翻译,有增删改。


也许你现在又想起了AS3内置事件框架的好处,希望使用currentTarget?或者希望支持冒泡?OK,Signals也能满足你那多变的心……(貌似是我自己多变罢了ˇ^ˇ)

高级事件

使用DeluxeSignal可以实现更高级的事件传递。还是基于闹钟的例子进行修改,将原来AlarmClock中的Signal改为DeluxSignal:

[AlarmClock.as]

public function AlarmClock()
{
    //将自己作为引用传递给DeluxeSignal,同时增加GenericEvent的传递
    alarm = new DeluxeSignal(this, GenericEvent, Date);
}

public var alarm:DeluxeSignal;

public function ring():void
{
    alarm.dispatch(new GenericEvent(), new Date());
}

修改Wakeup.as中的处理器函数,让它能够接受到传递的2个参数。

[Wakeup.as]

private function handler_ring($evt:GenericEvent, $date:Date):void
{
    trace('currentTarget:',$evt.currentTarget);
    trace('target:',$evt.target);
    trace('signal:',$evt.signal);
    trace('起床了!!!也不看看几点了:'+$date.toString());
}

在这里出现的GenericEvent,并非继承自flash.events.Event,而是实现了Signals自己的IEvent接口,与AS3的事件机制毫无关系。取一个貌似兄弟的名称,是为了方便大家理解罢了。它所提供的currentTarget和target属性,也是由IEvent自身提供。

运行修改后的例子,可以看到如下输出:

[trace] currentTarget: [object AlarmClock]
[trace] target: [object AlarmClock]
[trace] signal: [object DeluxeSignal]
[trace] 起床了!!!也不看看几点了:Mon Jan 23 17:07:16 GMT+0800 2012

现在,是不是可以对currentTarget“为所欲为”了呢?

冒泡事件

Signals一样可以冒泡,而且并不依赖AS3自带的事件机制。当然,发送和接收冒泡事件的对象必须处于显示列表中。

为了让AlarmClock能够被加入显示列表,我们让AlarmClock继承Sprite。而抛出冒泡事件就非常简单,只需要在实例化GenericEvent的同时传递true参数即可。看看AlarmClock类被修改的部分吧:

[AlarmClock.as]

public class AlarmClock extends Sprite
{
    public function ring():void
    {
        alarm.dispatch(new GenericEvent(true), new Date());
    }
}

接收事件的类,必须实现IBubbleEventHandler接口,在onEventBubbled中处理冒泡事件。同时,要将_alarm实例加入显示列表。

为了方便查看冒泡效果,可以将addOnce所在的一行注释掉,只接收冒泡事件。

[Wakeup.as]

public class Wakeup extends Sprite implements IBubbleEventHandler
{
    public function Wakeup()
    {
        _alarm  = new AlarmClock();
        addChild(_alarm);
        //_alarm.alarm.addOnce(handler_ring);
        _alarm.ring();
    }

    public function onEventBubbled($evt:IEvent):Boolean
    {
        trace('冒泡 currentTarget:',$evt.currentTarget);
        trace('冒泡 target:',$evt.target);
        trace('冒泡 signal:',$evt.signal);
        //返回false代表不再继续冒泡
        return false;
    }
}

运行修改后的例子,可以看到如下输出:

[trace] 冒泡 currentTarget: [object Wakeup]
[trace] 冒泡 target: [object AlarmClock]
[trace] 冒泡 signal: [object DeluxeSignal]

完整的类

[AlarmClock.as]

package
{
import flash.display.Sprite;
import org.osflash.signals.Signal;
import org.osflash.signals.DeluxeSignal;
import org.osflash.signals.events.GenericEvent;

/**
* Signals闹钟范例
* @author Aiden Tailor(http://www.developria.com/2010/10/an-introduction-to-as3-signals.html)
* @author zrong(zengrong.net)
*/

public class AlarmClock extends Sprite
{
    public function AlarmClock()
    {
        alarm = new DeluxeSignal(this, GenericEvent, Date);
    }

    public var alarm:DeluxeSignal;

    public function ring():void
    {
        //使用冒泡的方式发布闹钟的响铃事件
        alarm.dispatch(new GenericEvent(true), new Date());
    }
}
}
</pre>

**[Wakeup.as]**

<pre lang="ActionScript" line="1" coloa="+">
package
{
import flash.display.Sprite;
import org.osflash.signals.events.GenericEvent;
import org.osflash.signals.events.IBubbleEventHandler;
import org.osflash.signals.events.IEvent;

[SWF(width=500,height=300,frameRate=30,backgroundColor=0xFFFFFF)]
/**
 * 测试闹钟
 * @author Aiden Tailor(http://www.developria.com/2010/10/an-introduction-to-as3-signals.html)
 * @author zrong(zengrong.net)
 */
public class Wakeup extends Sprite implements IBubbleEventHandler
{
    public function Wakeup()
    {
        _alarm  = new AlarmClock();
        addChild(_alarm);
        _alarm.alarm.addOnce(handler_ring);
        _alarm.ring();
    }

    private var _alarm:AlarmClock;

    private function handler_ring($evt:GenericEvent, $date:Date):void
    {
        trace('currentTarget:',$evt.currentTarget);
        trace('target:',$evt.target);
        trace('signal:',$evt.signal);
        trace('起床了!!!也不看看几点了:'+$date.toString());
    }

    public function onEventBubbled($evt:IEvent):Boolean
    {
        trace('冒泡 currentTarget:',$evt.currentTarget);
        trace('冒泡 target:',$evt.target);
        trace('冒泡 signal:',$evt.signal);
        //返回false代表不再继续冒泡
        return false;
    }
}
}

pureMVC实现、术语阐述及最佳实践(中文版)

pureMVC的官方文档,介绍pureMVC用法、特点、结构。
介绍 下载

我已经使用pureMVC2个月左右,感觉确实是很不错的框架,上手也不难,当时是看了几个官方范例之后就开始动手改原来写的项目了。强烈推荐!