代码改变世界

silverlight游戏设计(二)资源管理篇(补充)--图片帧序列资源包解析与图片资源处理

2010-12-26 17:05 姜 萌@cnblogs 阅读(...) 评论(...) 编辑 收藏

通过在上篇文章中构建的资源管理器和应用的demo,我们已经能够将游戏资源高效的下载过来并进行缓存。那么在资源管理这一块剩下的就是我们定义自己的资源文件结构和解析资源了。本文像大家展示图片资源包的组织和解析,以及涉及一些有用技巧。

StreamResourceInfo

一个mmorp 游戏的资源是非常多且杂的。比如单说玩家职业就可能有5、6种,每种又分性别,对于一个精灵而言,至少要准备是5个方向的帧序列动画图片(比如上,下,左,左上,左下。对于右边,右上和右下用前几种直接翻转即可),而动作上还能细分出站立、跑、战斗、死亡……。所以我们需要对资源进行归并、打包。这样不仅便于项目文件管理,而且还能减少文件尺寸(不过对图片并不明显)。

System. Windows.Resources这个命名空间提供了对silverlight资源进行处理的类型。里面有个StreamResourceInfo类,ok,这就是我们用来处理资源的利器。

StreamResourceInfo能够解析的是一个zip文件(xap其实就是zip,所以同样能解析xap),通过GameImageResService抓起目标资源包,得到一个stream,就可以构造StreamResourceInfo对象,进一步对于资源包里的文件我们都可以通过其URI得到相应的流对象,比如下:

 

StreamResourceInfo info = new StreamResourceInfo(stream, null); 
                
using (var reader = new StreamReader(Application.GetResourceStream(info, new Uri(IMG_ZIP_XML, UriKind.Relative)).Stream)) 
                {
……

 

 

图片帧序列资源包以及图片包配置文件

StreamResourceInfo是我们解析资源包的基础,接下来定义动画图片资源包的结构:

image

图片文件名既是帧序号,resconfig.xml的文件中定义每一个图片的中心点偏移等信息。

<ResRoot xmlns="http://www.sopaco.com/webgame/demo">
    
<ImgResSection>
    
<Image centerX="……"  centerY="……" …… />
    
<Image centerX="……"centerY="……" …… /> 

</ImgResSection>

</ResRoot>

silverlight中解析xml

.net中解析xml的方式有很多,不仅提供了流式和DOM解析的api,还有linq2xml。固然后两种方式解析xml最为简单方便,但是需要添加额外的程序集引用(System.Xml.Linq.dll是100+KB),使整个项目大了不少,对于身材本来就瘦小webgame来讲已经很大了,所以我们还是选取流式读取(当然具体情况要结合您自身的项目)

 

解析xml
using (var reader = new StreamReader(Application.GetResourceStream(info, new Uri(IMG_ZIP_XML, UriKind.Relative)).Stream))
                {
                    var xmlReader 
= XmlReader.Create(reader);
                    
while(xmlReader.Read())
                    {
                        
if(xmlReader.IsStartElement("ImgResSection"))
                        {
                            
while(xmlReader.Read())
                            {
                                
if(xmlReader.IsStartElement("Image"))
                                {
                                    xmlReader.MoveToAttribute(
"key");
                                    xmlReader.ReadAttributeValue();
                                    
string imgKey = xmlReader.Value;
                                    xmlReader.MoveToAttribute(
"uri");
                                    xmlReader.ReadAttributeValue();
                                    var targetUri 
= new Uri(xmlReader.Value, UriKind.RelativeOrAbsolute);
                                    var bitmapStream 
= Application.GetResourceStream(info, targetUri).Stream;
                                    var image 
= new BitmapImage();
                                    image.SetSource(bitmapStream);
                                    _namedImageCache[imgKey] 
= image;
                                }
                            }
                        }
                    }
                }

 

 

一些有用的技巧

 得到对一个图片进行指定的transform变换后的副本,原理就是借助WriteableBitmap。

GenerateBitmap
public static WriteableBitmap GenerateBitmap(ImageSource imgSource, Transform transform)
        {
            var imgSrc 
= (BitmapImage)imgSource;
            Image img 
= new Image()
            {
                Source 
= imgSource
            };
            img.RenderTransformOrigin 
= new Point(0.50.5);
            WriteableBitmap wb 
= new WriteableBitmap((int)imgSrc.PixelWidth, (int)imgSrc.PixelHeight);
            wb.Render(img, transform);
            wb.Invalidate();
            
return wb;
        }

 

 由此我们可以借助silverlight中的RotateTransform、TranslateTranform、ScaleTransform等进一步打造我们所需要的功能:

切割图片

CropBitmap
public static ImageSource CropBitmap(ImageSource imgSrc, int offsetX, int offsetY, int width, int height)
        { 
            var wb 
= new WriteableBitmap(width, height);
            var transform 
= new TranslateTransform()
            {
                X 
= -offsetX, 
                Y 
= -offsetY
            };
            
return generateBitmap(wb, transform);
        }

 

 

得到一个图片进行角度旋转后的副本

Rotate
public static ImageSource Rotate(ImageSource imgSource, int angle)
        {
            var transform 
= new RotateTransform() { CenterX = 0.5, CenterY = 0.5, Angle = angle };
            
return generateBitmap(imgSource, transform);
        }

 

 

得到一个图片进行水平翻转后的副本

Inverse
public static ImageSource Inverse(ImageSource imgSource)
        {
            var imgSrc 
= (BitmapImage)imgSource;
            TransformGroup group 
= new TransformGroup();
            group.Children.Add(
new ScaleTransform() { CenterX = 0.5, CenterY = 0.5, ScaleX = -1, ScaleY = 1 });
            group.Children.Add(
new TranslateTransform() { X = imgSrc.PixelWidth });
            
return generateBitmap(imgSource, group);
        }

 

 

像UI线程投递委托

 public static void InvokeSecurity(this DependencyObject obj, Action action)

        {
            if (obj.CheckAccess())
            {
                action();
            }
            
else
            {
                obj.Dispatcher.BeginInvoke(action);
            }
        }