写在前面:
最近很长一段时间都在致力于移动互联网游戏的开发,安卓,IOS,也包括服务器,最近把服务器搞完以后,接到上级指示,需要服务器兼容手游和页游。所以我就着手准备制作一个页游客户端的DEMO。
一开是我的技术选型方案是现在很流行的html5+websocket。但是后来实际整合的时候发现,首先是IE浏览器对websocket的支持几乎可以说是没有,再一个就是websocket的握手协议还不同于普通的socket,所以服务器必须改动以适应websocket的协议。弄了2天,也曾经尝试过用Node.Js来做一个中转服务端,最终放弃了。思前想后,最后还是用了AS3 + FlashSocket来写一个页游的客户端Demo来连接我的服务器。一个下午的时间,用AS3实现了我服务器自定义的封包结构,测试连接,收发,一切正常。
网络层就这样完成了,真是好爽。下面想把之前做的一个cocos2d-x的小游戏移植到页游上,跑一跑,也算给上级一个交代。这个想法一有,就开始行动,但是事与愿违,写端游、手游用C++用的久了,猛的一用AS3做客户端,还不是那么顺手,首先面临的就是渲染问题和我的图片精灵集的xml解析类,由于那个小游戏的资源都是用TexturePackger打包的,我是个懒人,所以就在百度找AS3的plist解析类,于是,就找到了我们今天的主角,ND2D AS3游戏引擎。
PS: 页游技术在国内已经很成熟了,本系列笔记只适合刚刚从手游,端游转向AS3学习的朋友,或者想移植自己项目到页游的朋友。
正文:
ND2D的中文资料非常少,但是这真的是一款优秀的引擎,它需要Flash Player 11,使用它你可以轻松的构建一个3D渲染的2D游戏,包括一些绚丽的粒子效果和shader效果也可以通过它来完成。
ND2D是一个基于stage3D的一个高效的渲染引擎,给我的感觉是,这个引擎的作者也曾致力于移动互联网开发的(或许他也是为了移植IOS的游戏到页游呢?),他很多思想都借鉴与cocos2d for iphone,包括World,Scene, Sprite这些结构,非常像cocos2d的整个渲染思想。
先介绍一下ND2D的一些资料讯息:
ND2D官网:http://www.nulldesign.de/
源码下载 https://github.com/nulldesign/nd2d
ND2D文档API http://www.nulldesign.de/nd2d/docs/
下面 看一个些代码,构建一个简单的游戏场景-基于nd2d
ND2D整个工程的入口是一个World2D object, 它继承的是Flash Spirte ,当然了,肯定要继承一个AS3标准的DiplayContainer嘛,不然怎么往舞台上画东西呢。World2D会追踪所有已经显示的Object,所以你构建的所有显示的元素都应该是在你写的一个GameScene 类里面,这个类应当继承Scene2d类,ND2D的帧主循环是mainloop函数,你可以在例子工程里或者接下来的一个小游戏的例子找到它。
/这里写你一开始场景类的构造函数, 继承的是World2d
public function MyGame()
{
super(Context3DRenderMode.AUTO, 60);
}
//this will register an Event, you may override it
override protected function addedToStage (event:Event):void
{
super.addedToStage(event);
//激活你希望Running的Scene, ND2D和cocos2d-x一样,同一时间只运行一个场景
setActiveScene(someScene2DObject);
//start application
start();
}
比如一个小游戏,我们有一个菜单场景,和一个游戏场景,那么我们整体的结构应该是这样的
Main extends World2D
GameScene extends Scene2D
SpriteA...
SpriteB...
MenuScene extends Scene2D
Sprite Group..
下面说一下ND2D的资源载入,页游的资源载入和端游手游有很大区别,端游和手游我们基本上把资源存储在本地,而页游加载资源主要是两种方法:
1.直接将资源打到SWF里面
2.通过http协议,或者socket二进制传输,将资源文件下载到本地,然后再进行加载。
做DEMO嘛,都想急于看到引擎的渲染效率和效果,于是我们暂时采用第一种资源加载方式,熟悉cocos2d-x的朋友都应该知道TexturePackge,一个纹理打包工具,它会相应的生成一个.plist和一个.png(纹理大小端游限制是4096*4096,移动设备限制是2048*2048)
[Embed(source="../assets/frogger.png")]
protected var TextureBitmap:Class;
[Embed(source="../assets/frogger.plist", mimeType="application/octet-stream")]
protected var TextureXML:Class;
public var spriteBatch:Sprite2DBatch;
public var textureAtlas:TextureAtlas;
...
//set up sprite sheet
var texture:Texture2D = Texture2D.textureFromBitmapData(new TextureBitmap().bitmapData);
//create a TextureAtlas
textureAtlas = new TextureAtlas(texture.bitmapWidth, texture.bitmapHeight, new XML(new TextureXML()), 5, false);
//create Sprite2DBatch container
spriteBatch = new Sprite2DBatch(texture);
spriteBatch.setSpriteSheet(textureAtlas);
//add it to your Scene2D container
addChild(spriteBatch);
没错,cocos2d-x中的CCSpriteBatch,在ND2D中就叫做Sprite2DBatch,这里要注意一下,只有png文件才能加载到Sprite2DBatch,到现在为止,我们需要的图片资源元素已经统统被我加到了spriteBatch中。下面就是使用它们,诸如定义坐标,定义位置,定义移动轨迹,写事件,这里就不再赘述了。Sprite2dBatch的唯一意义就是在于渲染上的优化,优化的原理等同于cocos2d-x,尽可能小的减少渲染次数
//add a sprite to a Sprite2DBatch object
var logo:Sprite2D = new Sprite2D ();
//spriteBatch references the Sprite2DBatch object
spriteBatch.addChild(logo);
//logo.png must be inside the source png file and XML atlas you used to create the Batch
logo.setFrameByName("logo.png");
logo.x = screenWidth * 0.5;
logo.y = screenHeight * 0.3;
//add a sprite that does not belong to a sprite batch
[Embed(source="../assets/player.png")]
protected var PlayerBitmap:Class;
...
var sprite2:Sprite2D = new Sprite2D(Texture2D.textureFromBitmapData(new PlayerBitmap().bitmapData));
addChild(sprite2);
sprite2.x = 400;
sprite2.y = 300;
//create a mask
[Embed(source="../assets/spotlight.png")]
protected var SpotlightBitmap:Class;
...
var mask:Sprite2D = new Sprite2D(Texture2D.textureFromBitmapData(new SpotlightBitmap().bitmapData));
mask.x = 400;
mask.y = 300;
//use it to mask the player sprite
sprite2.setMask(mask);
ND2D的Animation和cocos2d-x也很像,但是AS3的语法就没有C++那么舒服了,播放动画的话,首先你需要的是TexutreAtlas object,而这个东西你需要靠plist和png纹理来建立,ND2D已经为我们准备好了对应texturePackage的解析类(泪奔,老子主要是为了它)。
[Embed(source="../assets/frogger.png")]
protected var textureAtlasBitmap:Class;
[Embed(source="../assets/frogger.plist", mimeType="application/octet-stream")]
protected var textureAtlasXML:Class;
...
var texture:Texture2D = Texture2D.textureFromBitmapData(new textureAtlasBitmap().bitmapData);
var atlas:TextureAtlas = new TextureAtlas(texture.bitmapWidth, texture.bitmapHeight, new XML(new textureAtlasXML()), 5, false);
var spriteBatch:Sprite2DBatch = new Sprite2DBatch(texture);
spriteBatch.setSpriteSheet(atlas);
atlas.addAnimation("death", ["death_1.png", "death_2.png", "death_3.png", "death_4.png" ], false);
addChild(spriteBatch);
第一个参数是动画的名字,自己起,你可能以后会用到,剩下的参数是他们的图片名,很好理解。重要的一点是,你必须在创建动画先于创建sprite,这样它才会显示出来。
同样,ND2D里也是支持动画回调的,和cocos2d一样。
到此,基本上一个小游戏的场景就写完了,ND2D引擎的学习才刚刚开始,但是这真的是一个移植手游TO页游的好东西。它很符合cocos2d-x的编程思想,C++程序员转到这个上面应该是很轻松的。
附上一个用ND2D构建的僵尸游戏,真的很赞http://www.bjoernacker.de/flash/28-bratwurst-later-zombie-2-5d-shooter-game/
视频的话自己上Youku找吧,搜索28-bratwurst