说在前头:楼主之前没有任何flash开发经验,只是从一次尝试中总结自己的理解和经验而已。如果有写的不对的地方,欢迎大家指正。
前一段时间尝试想用flash(as3)重新制作一下之前做的一个游戏,作为从来没有接触过flash开发的我来说,花了一些时间研究现有的一些框架。虽然现在我已经放弃了使用flash来开发(后面会说原因),但我觉得还是有必要总结一下这个过程中对于flash、starling、starling mvc的一些理解。
因为一开始我是使用silverlight开发游戏的,它有一个极大的便利是微软提供了强大好用的Microsoft Blend Expression。可以很好的、所见即所得用它来制作UI。自然而然,我很想在flash的开发环境下找一个替代品。但很遗憾,最后我自己得出的结论是:没有。
1、flex和blend有点像,但flex(后来叫flash builder)貌似某个版本以后就不提供图形编辑器了。并且通过网上大家的讨论得出,flex性能特别差,几乎无法在手机上运行。果断弃坑。
2、flash cs可以制作游戏UI,但给我的感觉是提供的功能特别基础,也不甚符合程序员的逻辑思维。
3、还有一些其他的第三方或者个人提供的UI库、编辑工具,如flexlite等——不敢用,怕有大坑。而且翻了一下代码更新日志,也是好久都没动过了——更加怕。
4、starling貌似是大家比较推崇的flash移动端解决方案,大概看了一下,从原理上来说肯定是性能比传统的flash要好得多。
通过一番调研,决定用starling试试。
很自然的,游戏需要比较好的扩展性的话,我们需要一个好的代码框架,找了一圈找到starling MVC。大概看了一下功能介绍,感觉和j2ee的spring MVC有一点像。
starling MVC是一个IOC框架,提供以下特性:
- 依赖注入(DI)/控制反转(IOC)
- 视图仲裁(View Mediation)
- 事件处理
- 不影响原生的Starling游戏代码
- 简易配置
- 易扩展
- 提供一些实用工具
我到网上翻了一些关于starling MVC编写的游戏例程,怎么说呢,我感觉是没一个靠谱的。。大部分人都是浅尝辄止,而且都是生搬硬套。想把游戏逻辑拼命的塞到starling MVC中,而不是真正的用它来做代码的整理、规划,没有理解MVC、IOC、DI等思想,于是我索性自己开始琢磨。
我整理的starling MVC的调用逻辑关系如下:
1、启动时初始化各个bean(包括model、mediator、controller、view我认为都应该实例化为bean)
2、starling MVC提供方法将bean依赖注入([Inject]等标签)
3、MVC的连接方式为:
- controller中注册EventHandler,接收消息。然后直接调用ViewManager的addView/removeView方法,来修改元素。
- 调用了addView/removeView实际上会被相关的Mediator拦截到,在Mediator中编写界面展示的逻辑。(调用view的修改方法,调用Model的逻辑)
- Model中提供业务逻辑方法
- View中定义界面元素
var stateBackground : ImageLoader = new ImageLoader();stateBackground.source = assets.getTexture("nick");stateBackground.x = 0;stateBackground.y = -12;stateBackground.width = 200;stateBackground.height = 70;stateCanvas.addChild(stateBackground);_nickLabel = ComponentFactory.getSmallFontLabel("初出茅庐", 0xEF5E00, true, 20);_nickLabel.x = 62;_nickLabel.y = -4;stateCanvas.addChild(_nickLabel);_gameModeLabel = ComponentFactory.getSmallFontLabel("难度:普通", 0xFFFFFF, true, 12);_gameModeLabel.x = 61;_gameModeLabel.y = 24;stateCanvas.addChild(_gameModeLabel);_zhujueHead = new ImageLoader();_zhujueHead.x = 4;_zhujueHead.y = -4;_zhujueHead.width = 40;_zhujueHead.height = 49;_zhujueHead.source = assets.getTexture("zhujue");stateCanvas.addChild(_zhujueHead); _descCanvas = new Sprite();_descCanvas.x = 100;_descCanvas.y = 100;_descCanvas.visible = false;this.addChild(_descCanvas);//提示框var descBackground : Scale9Image = ComponentFactory.getScale9Image("info", new Rectangle(7,9,360,87));descBackground.x = 0;descBackground.y = 0;descBackground.width = 377;descBackground.height = 103;descBackground.alpha = 0.8;_descCanvas.addChild(descBackground);_descImage = new ImageLoader();_descImage.x = 14;_descImage.y = 14;_descImage.width = 80;_descImage.height = 80;_descImage.maintainAspectRatio = false;_descCanvas.addChild(_descImage);_descLocationLabel = ComponentFactory.getSmallFontLabel("", 0xffffff, true, 18);_descLocationLabel.x = 104;_descLocationLabel.y = 6;_descLocationLabel.filter = BlurFilter.createDropShadow(4,0.7,0x000000,0.8,0.5,1);_descCanvas.addChild(_descLocationLabel);_descInfoLabel = ComponentFactory.getSmallFontLabel("", 0xffffff, false, 12);_descInfoLabel.x = 104;_descInfoLabel.y = 40;_descInfoLabel.width = 250;_descInfoLabel.height = 56;_descInfoLabel.filter = BlurFilter.createDropShadow(2,0.7,0x000000,0.8,0.5,1);_descCanvas.addChild(_descInfoLabel);
this.initComponents([{type:Scale9Image, source:"UI-kuang", rect:new Rectangle(15,40,315,328), width:500, height:585},{type:RoleUI, id:"roleUI", x:80, id:"roleUI"},{type:Label, text:"当前队伍", color:0xffffff, fontSize:14, width:110, x:25, y:73},{type:ScrollContainer, width:80, height:435, x:25, y:108, id:"teamlist" },{type:ImageLoader, source:"back", width:20, height:20, x:470, y:5, id:"close"},]);
自己感觉好多了……但还是很蛋疼有木有
package cn.hanjiasongshu.jygame.views.components
{import com.creativebottle.starlingmvc.views.ViewManager;import flash.geom.Rectangle;import flash.utils.Dictionary;import cn.hanjiasongshu.jygame.core.assets.Assets;import cn.hanjiasongshu.jygame.views.factorys.ComponentFactory;import feathers.controls.ImageLoader;import feathers.controls.Label;import feathers.controls.ScrollContainer;import feathers.core.FeathersControl;import feathers.display.Scale9Image;import feathers.textures.Scale9Textures;import feathers.dragDrop.DragDropManager;import starling.display.Sprite;import starling.textures.Texture;/*** UI基类* @author cg* */public class BaseUI extends FeathersControl{private static const ANONYMOUS_PREFIX:String = "__";public function BaseUI(){_components = new Dictionary();_autoId = 0;}public function get assets():Assets{return Assets.instance;}/*** 初始化组件 * @param componentsArray* */protected function initComponents(componentsArray:Object):void{this.addComponents(componentsArray, this);}/*** 为一个组件添加孩子 * @param componentsArray* @param parent* */private function addComponents(componentsArray:Object, parent:Sprite):void{for each(var c:Object in componentsArray){if(c.type == null){trace("[error]undefined component type:" + c);continue;}var type:String = c.type;var id:String = "";if(c.id != null){id = c.id;}else{id = String(ANONYMOUS_PREFIX + _autoId + ":" + String(c.type));_autoId++;}var component:Sprite = null;switch(c.type){case Label:var text:String = c.text==null?"":c.text;var color:int = c.color==null?0:c.color;var bold:Boolean = c.bold==null?true:c.bold;var fontSize:int = c.fontSize==null?11:c.fontSize;if(c.align != null && c.align == "center"){component = ComponentFactory.getCenterAlignedFontLabel(text,color,bold,fontSize);}else{component = ComponentFactory.getSmallFontLabel(text,color,bold,fontSize);}break;case ImageLoader:var tmp:ImageLoader = new ImageLoader();tmp.maintainAspectRatio = false;var source:String = c.source==null?"":c.source;tmp.source = c.source==null?"":assets.getTexture(source);component = tmp;break;case Scale9Image:component = ComponentFactory.getScale9Image(c.source, c.rect);break;case ScrollContainer:component = ComponentFactory.generateVerticalScrollContainer(c.layout, c.backgroundSkin);break;case ToolTipUI:component = new ToolTipUI(parent);break;default:var clz:Class = c.type;var instance:Object = new clz();if(instance is Sprite){component = instance as Sprite;}else{trace("[error]invalid component type:" + c.type);}break;}if(component != null){this.setIfExist(c, component, ["x","y","width","height","visible"]);_components[id] = component;parent.addChild(component);if(c.children != null) //遍历孩子组件{this.addComponents(c.children, component);}}}}/*** 通过ID获取组件 * @param id* @return * */public function getComponentById(id:String):Sprite{if(_components[id] == null){trace("[error]get undefined component id:"+id);return null;}return _components[id];}public function getLabel(id:String):Label{return this.getComponentById(id) as Label;}public function getImageLoader(id:String):ImageLoader{return this.getComponentById(id) as ImageLoader;}private function setIfExist(dataSource:Object, obj:Sprite, params:Array):void{for each(var p:String in params){if(dataSource[p]!=null)obj[p]=dataSource[p];}}private var _components:Dictionary;private var _autoId:int;public override function dispose():void{for each(var key:String in _components){var sprite:Sprite = _components[key] as Sprite;sprite.removeFromParent(true);}_components = null;}}
}
你可以修改addComponent函数来自己添加控件类型,支持控件的组合等等。