Date post: | 01-Nov-2014 |
Category: |
Technology |
Upload: | raimundas-banevicius |
View: | 11,038 times |
Download: | 0 times |
The Next Step in AS3 Framework Evolution
02.2013
About me
Senior AS3 Developer
Working with Flash from 2001
Author of open source AS3 framework – mvcExpress
Twitter : @Deril
About this presentation
● AS3 framework evolution ● Modular programming in mvcExpress
● mvcExpress live
AS3 framework evolution
AS3 framework history
●PureMVC (2006)●Cairngorm (2007?) [flex only]●Springactionscript (2007)●Parsley(2008)●Mate(2008) [flex only]●Robotlegs(2009)●Swiz(2009) [flex only]
●MvcExpress(2012)●Robotlegs 2 (2012) (in beta)
(ActionScript 3.0 released in 2006)
AS3 framework history
●PureMVC (2006)●Cairngorm (2007?) [flex only]●Springactionscript (2007)●Parsley(2008)●Mate(2008) [flex only]●Robotlegs(2009)●Swiz(2009) [flex only]
●MvcExpress(2012)●Robotlegs 2 (2012) (in beta)
(ActionScript 3.0 released in 2006)
PureMVC
● Organize your code is small units
● Let those units communication
● Standardize your code
● Focus on app instead of architecture
● Ported to many languages
● Slightly hurts performance
● Built on static classes
● Lot of boilerplate code
Can't it be done simpler?
The good The bad
The good The bad
robotlegs
● All PureMVC goodness.
● Removed most boilerplate code
● Introduces dependency injection
● Hurts performance a lot!
Can't it be done simpler...
and run fast?
The good The bad
robotlegs 2 (beta)
● Highly configurable
● Modular
● Guards ,hooks, rules.
● Adds some boilerplate code
● Code less standardized
● Hurts performance a lot (and more)
I meant faster! Not slower...
The good The bad
mvcExpress
● All PureMVC and robotlegs goodness.
● Focus on modular development
● Simplifies code even more
● Hurts performance the least
● Young framework
Simplest and fastest MVC framework!
package {public class PureMvcMediator extends Mediator implements IMediator {
public static const NAME:String = "PureMvcMediator"; public function PureMvcMediator(initViewComponent:ViewComponent) { super(NAME, initViewComponent); } // cast view for convenient local use. public function get view():ViewComponent { return super.getViewComponent() as ViewComponent; } // listen for framework notices override public function listNotificationInterests():Array { return [ // DataNote.STUFF_DONE // ]; } // handle framework events override public function handleNotification(notice:INotification):void { switch (notice.getName()) { case DataNote.STUFF_DONE: // do stuff… break; }
}}
pureMVC mediator
package {public class PureMvcMediator extends Mediator implements IMediator {
public static const NAME:String = "PureMvcMediator"; public function PureMvcMediator(initViewComponent:ViewComponent) { super(NAME, initViewComponent); } // cast view for convenient local use. public function get view():ViewComponent { return super.getViewComponent() as ViewComponent; } // listen for framework notices override public function listNotificationInterests():Array { return [ // DataNote.STUFF_DONE // ]; } // handle framework events override public function handleNotification(notice:INotification):void { switch (notice.getName()) { case DataNote.STUFF_DONE: // do stuff… break; }
}}
pureMVC mediator
package {public class PureMvcMediator extends Mediator implements IMediator {
public static const NAME:String = "PureMvcMediator"; public function PureMvcMediator(initViewComponent:ViewComponent) { super(NAME, initViewComponent); } // cast view for convenient local use. public function get view():ViewComponent { return super.getViewComponent() as ViewComponent; } // listen for framework notices override public function listNotificationInterests():Array { return [ // DataNote.STUFF_DONE // ]; } // handle framework events override public function handleNotification(notice:INotification):void { switch (notice.getName()) { case DataNote.STUFF_DONE: // do stuff… break; }
}}
pureMVC mediator
package {public class PureMvcMediator extends Mediator implements IMediator {
public static const NAME:String = "PureMvcMediator"; public function PureMvcMediator(initViewComponent:ViewComponent) { super(NAME, initViewComponent); } // cast view for convenient local use. public function get view():ViewComponent { return super.getViewComponent() as ViewComponent; } // listen for framework notices override public function listNotificationInterests():Array { return [ // DataNote.STUFF_DONE // ]; } // handle framework events override public function handleNotification(notice:INotification):void { switch (notice.getName()) { case DataNote.STUFF_DONE: // do stuff… break; }
}}
pureMVC mediator
package {public class MvcExpressMediator extends Mediator { [Inject] public var view:ViewComponent; override public function onRegister():void { // listen for framework events addHandler(DataMessage.STUFF_DONE, handleStuffDone); } // handle framework events private function handleStuffDone(params:DataChangeParamsVO):void { view.showStuff(params.dataParam1); }}}
mvcExress mediator
package {public class MvcExpressMediator extends Mediator { [Inject] public var view:ViewComponent; override public function onRegister():void { // listen for framework events addHandler(DataMessage.STUFF_DONE, handleStuffDone); } // handle framework events private function handleStuffDone(params:DataChangeParamsVO):void { view.showStuff(params.dataParam1); }}}
mvcExress mediator
package {public class MvcExpressMediator extends Mediator { [Inject] public var view:ViewComponent; override public function onRegister():void { // listen for framework events addHandler(DataMessage.STUFF_DONE, handleStuffDone); } // handle framework events private function handleStuffDone(params:DataChangeParamsVO):void { view.showStuff(params.dataParam1); }}}
mvcExress mediator
package {public class MvcExpressMediator extends Mediator { [Inject] public var view:ViewComponent; override public function onRegister():void { // listen for framework events addHandler(DataMessage.STUFF_DONE, handleStuffDone); } // handle framework events private function handleStuffDone(params:DataChangeParamsVO):void { view.showStuff(params.dataParam1); }}}
mvcExress mediator
Speed test datamvcExpress pureMVC robotlegs robotlegs 2
Command creation and execution: 0.00087 0.00219 0.00866 0.01894
Proxy inject into command: 0.00037 0.00024 0.00491 0.00247
Mediator create: 0.02100 0.02100 0.05100 0.13600
Mediator remove: 0.01700 0.10300 0.01850 0.05550
Communication 1 to 1: 0.00030 0.00060 0.00153 0.00141
Communication 1 to 10: 0.00073 0.00788 0.00670 0.00629
Communication 1 to 100: 0.00480 0.06897 0.05746 0.05071
1.0 /2.5 /10.0 /21.8
1.0 /0.7 /13.2 /6.6
1.0 /1.0 /2.4 /6.5
1.0 /6.1 /1.1 /3.3
1.0 /2.0 /5.0 /4.6
1.0 /10.9 /9.2 /8.7
1.0 /14.4 /12.0 /10.6
https://github.com/MindScriptAct/as3-mvcFramework-performanceTest
https://github.com/MindScriptAct/as3-mvcFramework-performanceTest
Command runs /1ms
pureMVC robotlegs robotlegs 2 mvcExpress mvcExpress(pooled)
Command with nothing: 495.0 109.3 55.3 1010.1 1754.4
Command with 1 inject: 487.5 70.4 49.6 961.5 1694.9
Command with 2 injects: 458.7 58.6 47.2 724.6 1724.1
Command with 4 injects: 340.1 44.1 42.7 480.8 1783.3
Command performance
Command runs /1ms
pureMVC robotlegs robotlegs 2 mvcExpress mvcExpress(pooled)
Command with nothing: 495.0 109.3 55.3 1010.1 1754.4
Command with 1 inject: 487.5 70.4 49.6 961.5 1694.9
Command with 2 injects: 458.7 58.6 47.2 724.6 1724.1
Command with 4 injects: 340.1 44.1 42.7 480.8 1783.3
Command performance
Command runs /1ms
pureMVC robotlegs robotlegs 2 mvcExpress mvcExpress(pooled)
Command with nothing: 495.0 109.3 55.3 1010.1 1754.4
Command with 1 inject: 487.5 70.4 49.6 961.5 1694.9
Command with 2 injects: 458.7 58.6 47.2 724.6 1724.1
Command with 4 injects: 340.1 44.1 42.7 480.8 1783.3
Command performance
Command runs /1ms
pureMVC robotlegs robotlegs 2 mvcExpress mvcExpress(pooled)
Command with nothing: 495.0 109.3 55.3 1010.1 1754.4
Command with 1 inject: 487.5 70.4 49.6 961.5 1694.9
Command with 2 injects: 458.7 58.6 47.2 724.6 1724.1
Command with 4 injects: 340.1 44.1 42.7 480.8 1783.3
Command performance
Command runs /1ms
pureMVC robotlegs robotlegs 2 mvcExpress mvcExpress(pooled)
Command with nothing: 495.0 109.3 55.3 1010.1 1754.4
Command with 1 inject: 487.5 70.4 49.6 961.5 1694.9
Command with 2 injects: 458.7 58.6 47.2 724.6 1724.1
Command with 4 injects: 340.1 44.1 42.7 480.8 1783.3
Command performance
Command runs /1ms
pureMVC robotlegs robotlegs 2 mvcExpress mvcExpress(pooled)
Command with nothing: 495.0 109.3 55.3 1010.1 1754.4
Command with 1 inject: 487.5 70.4 49.6 961.5 1694.9
Command with 2 injects: 458.7 58.6 47.2 724.6 1724.1
Command with 4 injects: 340.1 44.1 42.7 480.8 1783.3
Command performance
Communication performance
Direct communication:
Indirect communication:
Communication performance
Direct communication:
Indirect communication:
Overview
Overview
Overview
Modular programming in mvcExpress
Modular programmingfeatures
● Aggregation● Communication● Dependencies(data)
● Permission control (v1.4)
Aggregation
mediatorMap.mediate(moduleB);
var moduleB:ModuleB = new ModuleB();
view.addChild(moduleB);
Module communication
Module communication
Module communication
sendScopeMessage("scopeName", "messageType", new ParamObject());
addScopeHandler("scopeName", "messageType", scopedMessageHandrlerFunction);
Module data sharing (data dependencies)
Module data sharing (data dependencies)
Module data sharing (data dependencies)
proxyMap.scopeMap("scopeName", myProxyObject);
[Inject(scope="scopeName")]public var myProxy:MyProxy;
Scope permissions
registerScope(scopeName:String, messageSending:Boolean = true, messageReceiving:Boolean = true, proxieMapping:Boolean = false):void
Dungeon viewer example
Modular programming pitfalls
● Planning is needed
● Good module should be able to stand as application on its own
– Chat window
– Stand alone tutorial● Worst case scenario: extracting
module/reintegrating module refactoring.
MvcExpress live
mvcExpress live
● mvcExpress live = mvcExpress + game engine
– Continuous logic execution– Dynamic animations– Breaking execution in parts. (batching)
● Compatible with mvcExpress
mvcExress live diagram
mvcExress live diagram
mvcExress live diagram
mvcExress live diagram
mvcExress live diagram
mvcExress live diagram
mvcExress live diagram
Process examplepackage com.mindscriptact.testProject.engine {public class GameEngineProcess extends Process {
override protected function onRegister():void { addTask(MoveHeroTask); addTask(MoveEnemiesTask); addTask(HeroCollideEnemiesTask); addTask(EnemySpawnTask); addTask(ShowHeroTask); addTask(ShowEnemiesTask);
addHandler(Message.PAUSE_GAME, handleGamePause); }
private function handleGamePause(isPaused:Boolean):void { if (isPaused) { disableTask(MoveHeroTask); disableTask(MoveEnemiesTask); } else { enableTask(MoveHeroTask); enableTask(MoveEnemiesTask); } }}}
Task example
package com.mindscriptact.testProject.engine.tasks {
public class ShowEnemiesTask extends Task {
[Inject(constName="com.mindscriptact.testProject.constants.ProvideIds.ENEMY_DATAS")]
public var enemyDatas:Vector.<EnemyVO>;
[Inject(constName="com.mindscriptact.testProject.constants.ProvideIds.ENEMY_VIEWS")]
public var enemyImages:Vector.<EnemySprite>;
override public function run():void {for (var i:int = 0; i < enemyDatas.length; i++) {
enemyImages[i].x = enemyDatas[i].x;enemyImages[i].y = enemyDatas[i].y;enemyImages[i].rotation = enemyDatas[i].rotations;
}}
}}
mvcExpress live testingpackage com.mindscriptact.testProject.engine.tasks {
public class ShowEnemiesTask extends Task {
[Inject(constName="com.mindscriptact.testProject.constants.ProvideIds.ENEMY_DATAS")]public var enemyDatas:Vector.<EnemyVO>;
[Inject(constName="com.mindscriptact.testProject.constants.ProvideIds.ENEMY_VIEWS")]public var enemyImages:Vector.<EnemySprite>;
override public function run():void {for (var i:int = 0; i < enemyDatas.length; i++) {
enemyImages[i].x = enemyDatas[i].x;enemyImages[i].y = enemyDatas[i].y;enemyImages[i].rotation = enemyDatas[i].rotations;
}}
}}
[Test]public function showEnemiesTask_enemyViewAndDataCount_isEqual():void {
assert.equals(enemyDatas.length, enemyImages.length, "Enemies data and view count must be the same!");}
[Test(delay="500")]public function showEnemiesTask_enemyViewAndDataPosition_isEqual():void {
for (var i:int = 0; i < enemyDatas.length; i++) {assert.equals(enemyImages[i].x, enemyDatas[i].x, "Enemy x is damaged. enemyId:" + enemyDatas[i].id);assert.equals(enemyImages[i].y, enemyDatas[i].y, "Enemy y is damaged. enemyId:" + enemyDatas[i].id);
}}
Process run speed
● Best case:
– Runs 1000000 empty Task's in 17 ms– 58823 empty tasks in 1 ms
● Worst case:
– 13300 empty tasks in 1 ms
MvcExpress live overview
● Designed with games in mind but can be used in any application than has repeating logic to run.
● Processes and Task's are decoupled
● Convenient communication with MVC
● It is possible to break Model and View decoupling rules, but gives tools to detect it.
● It is fast!
● It just works!
On learning curve
On learning curve
● MVC framework initial learning curve is steep...
● But if you learned one – learning another is easy!
http://mvcexpress.org/documentation/
https://github.com/MindScriptAct/mvcExpress-examples
Also I do workshops.
http://mvcexpress.org/documentation/
https://github.com/MindScriptAct/mvcExpress-examples
Also I do workshops.
MvcExpress logger
Links
http://mvcexpress.org/
https://github.com/MindScriptAct/mvcExpress-frameworkhttps://github.com/MindScriptAct/mvcExpress-exampleshttps://github.com/MindScriptAct/mvcExpress-downloads
http://puremvc.org/
http://www.robotlegs.org/
Twitter : @Deril
Thank you for your time!
http://mvcexpress.org/
https://github.com/MindScriptAct/mvcExpress-frameworkhttps://github.com/MindScriptAct/mvcExpress-exampleshttps://github.com/MindScriptAct/mvcExpress-downloads
http://puremvc.org/
http://www.robotlegs.org/
Twitter : @Deril