2010年4月12日星期一

一个基于SDL的CPP多媒体框架

这是之前一个尝试产物,命名为SdlView,定位是一个简单的基于SDL的CPP的跨平台多媒体框架。
实现的结构上参考过Qt,PyGame,HGE和PopCapFramework,源码看过ONScripter和sdlbasic‎。
话说好久没Code了,有生疏的感了。话说车库中当时记录下的文档还是看起来充满想法的,算然说仅仅是个开始来着。
先传送吧:http://code.google.com/p/z091204/ ,等页面自然死。
因为CPP修改不方便而且开始时用的自己的脚本引擎也很残,所以后来就尝试写成一个Lua库来自用。

Ok,主题回来。本文是的重点是这个框架结构设计上的想法。
开始前先作些约定,文本必须无BOM的UTF8格式,图片建议png,声音建议ogg。这只是想在可用的前提下,为初步实现少些麻烦而已。
程序通过继承SdlView来实现,SdlView提供init和quit方法,来对所有组件执行对应操作。
View是一个基本的交互单元,可以在几个View中切换出当前活动的,也可以复合使用。
需要重写update(event)和draw(Surface)两个方法。其中根据update的返回确定是否自动调用draw,或者是要结束流程。View的run方法默认定义调用msgloop,而msgloop是按照消息循环的方式使用update和draw。
所用资源通过私有指针成员,可由私有构造和析构函数负责管理,或者定义init和quit方法。
首先是Video模块,模块的全局变量通过Video类成员的保护继承来实现。
用到的封装好类型有矩形Rect,方位Pos(x,y),颜色Color,表面Surface。
使用上提供的类型 精灵Sprite,可以由图片文件创建。负责对一个Surface的引用管理。
为结构方便它继承自一个可以重写update和draw方法,并支持对Pos进行操作的节点类。
同样也派生出了类型 场景Scene,用双向列表来实现的,也是Composite模式的一个运用。
其中draw方法支持相对相对坐标的转化。
一般使用都是对Sprite和Scene的派生,比如使用派生自Sprite的按钮的事件判断:
Pos m = event.mouse();
if (bn.has(m)){
printf("Button actived.\n");
}
一组选项的处理则可以用Scene来处理。
此外定义了 声音类Sound 提供类型 Music Chunk在创建资源对象。
文字的渲染由字体类Font的实例render方法负责,可以得到一个Sprite。
为方便折行,可以指定渲染宽度,然后返回尚未渲染的字符串。
事件处理有三种类型,其中常用的是消息列队msgloop和timerloop。
对消息的使用是通过Event对象,在使用前需要让Event对象处理消息,或者让Timer对象安排延时。注意当前活动且有效的E和T是什么。
实现Event时,定义了两层结构。一层是直接的封装,另一层为方便使用会为正在处理的消息类型使用对应的方法(也提供按键到坐标的转化,isSkip()等)。可根据性能和易用性的方面来使用。
消息的使用流程 init();事件循环:处理事件,绘制,update();quit(); 已经封装在View中了。
此外还提供了类型 效果Effect 是类似Sprite的Surface+Pos的结构,用来实行对Sprite的增强使用,比如更多的融合效果,一些实现好的动画效果也被放置在这里。也可多重继承出EffectSp负责出如 EffectSp(wqy.render(str,color),Pos(54,y)).print(); 这样的效果。

后来用SWIG做了Lua的绑定。因为Lua本身不是基于类继承的语言,SWIG也不是Lua的专用绑定程序。Sprite类型就只被充当了Image类型的实现来使用。也考虑过增加通过类型Type来实现Null对象。
最后,实现的定位是一个自用的基础模块。并不很在意功能的完整性,有用和接口稳定反而更加重要的感觉。其他可考虑的有Box2D以及ImageMagick的接口。而OpenGL自己还了解的不多。
话说Qt+JS也像是不错的方案。
恩……Wiki格式写出来的文档结构分明很漂亮的,不过这里不是。
当然,搜索一下可以发现同类型的完整实现已经很多了。

See Also
http://wiki.gamedev.net/index.php/PopCap
http://www.renpy.org/
http://love2d.org/

没有评论: