两学一做网站安徽省,怎么自己做游戏软件,置顶 wordpress,网站建设 模板网站即开即玩是网页游戏相比传统客户端游戏的最大优势。如果说在每台电脑安装上G的客户端是一种资源浪费及时间污染#xff1b;那么Silverlight作为RIA界的新宠儿#xff0c;在继承祖辈优秀血统的前提下拥有更加卓越的性能及更为曼妙的动态表现#xff0c;势将引领网络未来世界进…即开即玩是网页游戏相比传统客户端游戏的最大优势。如果说在每台电脑安装上G的客户端是一种资源浪费及时间污染那么Silverlight作为RIA界的新宠儿在继承祖辈优秀血统的前提下拥有更加卓越的性能及更为曼妙的动态表现势将引领网络未来世界进入那令人神往的低碳空间。 笔者学习Silverlight开发近2年在写第一部Silverlight游戏系列教程时为了尽快的实现目标而将所有素材资源打包进XAP中。与其他Silverlight初学者一样这或许是我们所必须会经历的一个过程。QXGameEngine最终完成时它的体积已经达到了18M有余功能需求满足了预期可是却让大量还未接触过Silverlight的朋友产生巨大困惑难道Silverlight仅仅是镶嵌于网页中的游戏客户端 QXGameEngine作为教程示例再贴切不过但如果说要将之商业化首先就违背了RIA的初衷即开即用。漫长等待是对用户体验的无情扼杀不仅随时可能造成用户流失毫不客气的尊称其为失败品亦不为过。 针对Silverlight资源配置问题国外很多朋友首先想到且用得最多的莫过于独立存储Isolated Storage。比如Dark Ieign -- 最近在网站上看到的Silverlight2D即时战略大作。虽然其等待资源下载过程中我们可以通过欣赏游戏宣传动画短片打发时间但本质却与QXGameEngine如出一辙将所有的资源必须性的一次性下载完不管会不会用到这样的形式仍旧十分糟糕。是的Silverlight才刚起步毕竟Dark Ieign让我们看到的是一款大作风范。历史中新生事物的起源都必然会经历一个适应期不久的将来一旦Silverlight完美动态技术普及开后堪比星际争霸2之类大作终有一天会出现在Silverlight平台上拭目以待 8个多月过去第一部游戏教程全部完成了。其后QXSceneEditor在笔者思考如何实现Silverlight游戏快速开发的同时孕育而生。其搭建于一个兼具静态资源及动态资源混合使用的游戏框架下XAP包存放的不再是一切资源而仅仅是一些常用的小图片、图标及场景、精灵等配置文件相对于前作该场景编辑器动态参数及动态配置的灵活结构可以轻松拓展出任意类型的各式游戏而不仅仅再局限于RPG。 又是3个月第二部教程伴随着3个全新Demo的完成落下帷幕。此时再次重温QXSceneEditor仔细琢磨又一次感到其结构仍不完美一开始就加载所有场景及所有精灵的xml配置信息假想一下如果有100个场景而玩家或许从注册到对游戏失去兴趣也走不到10个场景那剩下的90个场景的配置文件容量不是白下载了林林种种……。随后的第三部课程虽然有了结构性的进步然后更多的与第一部类似着重在于基础学习。而后在中游在线的《WOWO世界》的感悟下触使我决定再次去探求Silverlight-WebGame的极至框架理想中它应该贯穿着“一切动态”“按需加载”的搭建理念秉持“体验至上”“优异性能”的整体特性于是诞生了想要从头来过的全新思路。 这是一次真正的从零开始技术的革新让我决心从游戏的开始制作到游戏的结局不在乎这个结局是喜是悲于是有了这个全新的第四部作品它们将倾注更多关于自己领悟的Silverlight-Web游戏设计思想。同以往一样如果朋友们觉得有不对之处恳请善意指正。这三个系列的诞生与发展不光是我一个人的努力没有大家的支持、建议和批评也不会坚持到今天。 以上抒情。 接下来将进入本节的主要内容Silverlight WebGame中的动态资源配置。 从Javascript的var到F#的lambdaC#在取之精华去其糟粕的同时让自身发展得更为完美趋势中弥漫着“动态”给我们编程带来的无限芳香。“动态”不论在任何场合都是一种优秀表现与“动态”相呼应的是“自适应”从布局的“自适应宽高”到游戏资源的“自适应按需下载”这些均可以从当下诸多优秀的软件架构中得到充分体现。 在Silverlight学习之初大家已意识到动态下载的重要性从最初的探讨dll动态下载、xaml动态加载、xap动态获取到数据传输的序列化与反序列化以及资源的压缩与解压。直到今天笔者在反复尝试下终于完成了个人感觉目前效果还算较好的资源结构布局模式独立于对象的配置布局体系。 何谓独立于对象的配置布局体系我们不妨先看张图 以游戏中的动画为例素材布局以数字代号顺次标识与传统不同的关键在于我为每个动画资源都配备了一个描述该动画信息的Info.xml配置文件以上图0号动画为例该动画的Info.xml信息如下 ?xml version1.0 encodingutf-8 ? Animation Width400 Height400 FrameNum7 Interval140 Format1 ImagesAnimation/0,0-6,png/ 当游戏中某个场合需要演示该动画时我们会首先下载该动画对应的Info.xml并进行解析再将所有参数赋予自定义的如AnimationButton控件从而实现动态呈现。 接下去的问题是我们如何下载该Info.xml配置文件以及解析完成后如何实现队列下载所需的N张图片另外对于已经下载好的图象文件及xml配置文件我们该如何区别对待 大家是否还记得在Silverlight游戏设计(Game Design)这部教程中我为每个Demo都附加有一个后缀为. Tools的项目该项目中除了A*寻路的方法类库外还包含一个资源下载用类Downloader。然而此下载器仅仅实现的是单个图象文件下载为了满足任意文件下载需求且与接下来的队列下载类所兼容我这里的将之进行了如下修改 public sealed class DownloaderEventArgs : EventArgs { public string uri { get; set; } public Stream stream { get; set; } } public delegate void DownLoaderEventHandler(object sender, DownloaderEventArgs e); public sealed class Downloader { /// summary /// 已下载的文件路径字典 /// /summary static Dictionarystring, bool files new Dictionarystring, bool(); /// summary /// 资源正在读取中 /// /summary public event DownLoaderEventHandler Loading; /// summary /// 资源下载完成时触发 /// /summary public event DownLoaderEventHandler Completed; DispatcherTimer timer; /// summary /// 通过WebClient下载资源 /// /summary public void GetResource(string uri) { //假如该路径图片还未下载过 if (!files.ContainsKey(uri)) { WebClient webClient new WebClient(); webClient.OpenReadCompleted (s, e) { //该路径图片已下载完成 files[uri] true; if (Completed ! null) { Completed(this, new DownloaderEventArgs() { uri uri, stream e.Result }); } }; webClient.OpenReadAsync(new Uri(uri, UriKind.Relative), uri); files.Add(uri, false); if (Loading ! null) { Loading(this, new DownloaderEventArgs() { uri uri, stream null }); } } else { //假如该路径图片已下载完成 if (files[uri]) { if (Completed ! null) { Completed(this, new DownloaderEventArgs() { uri uri, stream null }); } } else { if (timer null) { //假如该路径图片正在下载,则需要等待,每隔1秒检测一次是否已下载完成 timer new DispatcherTimer() { Interval TimeSpan.FromSeconds(1) }; timer.Tick (s, e) { if (files[uri]) { if (Completed ! null) { Completed(this, new DownloaderEventArgs() { uri uri, stream null }); } DispatcherTimer t s as DispatcherTimer; t.Stop(); t null; } }; timer.Start(); } if (Loading ! null) { Loading(this, new DownloaderEventArgs() { uri uri, stream null }); } } } } } 此时该类不仅能下载图象文件同时还能将数据流中的Stream作为参数附给Completed事件后面的事情就简单多了在Completed事件中可以直接通过XElement xelement XElement.Load(e.stream)对该xml文件进行加载后续的步骤就不用再多说了吧。 剩下的就是解析完xml配置后该如何队列下载所需的一切图象资源。很多朋友一听到队列、按需就发慌其实我们只要对上面重新编写的Downloader再进一步逻辑封装就OK了这个神奇的DownloadManager类其实也不过如此嘛 public sealed class DownloadManager { public event EventHandler Completed; int uriNum, count; Liststring uris; /// summary /// 根据资源表下载资源 /// /summary /// param nameuris资源地址表/param public void GetResource(Liststring uris) { if (uris.Count 0) { if (Completed ! null) { Completed(this, new EventArgs()); } } else { this.uris uris; uriNum uris.Count; DownloadResource(0); } } private void DownloadResource(int index) { Downloader downloader new Downloader(); downloader.Completed new DownLoaderEventHandler(downloader_Completed); downloader.GetResource(uris[index]); } private void downloader_Completed(object s, DownloaderEventArgs e) { count; if (count uriNum) { DownloadResource(count); } else { if (Completed ! null) { Completed(this, new EventArgs()); } } } } 再回到开头以自定义呈现动画控件AnimationButton为例在控件初始化后我们首先下载对应代号的动画xml配置文件 Downloader downloader new Downloader(); downloader.GetResource(Global.WebPath(string.Format(Animation/{0}/Info.xml, code))); 然后注册Completed事件一旦完成后对配置文件进行解析并取值比如 downloader.Completed (s1, e1) { string key string.Format(Animation{0}, code); if (e1.stream ! null) { Global.PackInfo.Add(key, XElement.Load(e1.stream)); } XElement config Global.PackInfo[key].DescendantsAndSelf(Animation).Single(); this.format Global.FileFormat((Format)((int)config.Attribute(Format))); this.frameNum (int)config.Attribute(FrameNum); this.Width (double)config.Attribute(Width); this.Height (double)config.Attribute(Height); …… Waiting waiting new Waiting(this.Width, this.Height) { Z 999999 }; //下载动画资源 DownloadManager downloadManager new DownloadManager(); downloadManager.Completed (s2, e2) { Heart.Start(); this.Children.Remove(waiting); }; downloadManager.GetResource(Global.GetImageList(config.Attribute(Images).Value)); }; 该事件中最后3行即实现了通过DownloadManager来获取配置文件中”Images”节点的属性值(Attribute(Images).Value)后解析并队列下载所需图片此过程中我们可以先展示一个Waiting动画作为代替当队列下载完成后(downloadManager.Completed)我们再对实际动画进行播放呈现 Heart.Tick (s, e) { if (currentFrame frameNum) { switch (kind) { case AnimationKinds.Once: currentFrame 0; Heart.Stop(); break; case AnimationKinds.OnceToDispose: Heart.Stop(); (this.Parent as Canvas).Children.Remove(this); break; case AnimationKinds.Loop: currentFrame 0; break; } } this.Background new ImageBrush() { ImageSource Global.GetWebImage(string.Format(Animation/{0}/{1}{2}, code, currentFrame, format)) }; currentFrame; }; 最后一个问题是我们应该如何处理下载得到的资源才最合理呢一方面尽量少的占用额外的内存资源另一方面在下次再请求获取时不用重复执行下载而浪费带宽流量。 针对此问题我的解决思路是通过静态字典(Dictionarystring, XElement)缓存xml配置文件通过延迟加载(BitmapCreateOptions.DelayCreation)与浏览器共用图象缓存音乐文件则通过MediaElement直接加载此过程会对加载的视频或音频流进行时时播放用户体验很好而无须我们任何代码干扰。 到此从资源配置布局到所有资源按需队列下载并实现缓存独立于对象的配置布局体系就构建完成了。本文仅以实现自定义动画为例实际游戏开发中无论精灵、魔法还是场景等均完全可以照般此布局体系。我们的最终目标是让Silverlight的XAP包中不存放除代码外任何的额外资源而将所有需要的部件布局于Web中真正实现对一切对象的动态按需下载 看过本文后是否还会有朋友再询问如何对xap进行分包如何对xap进行压缩如何动态下载xaml没有必要了吧。本文构建的游戏架构体系实现了代码与素材的完全分离它将使得就算是一款Silverlight网游巨作其XAP也难超500K客户端更新后用户就算重新下载也仅仅是数秒内的事这才是Silverlight开发Web网游的强势所在 – “动态资源”。 在未来商家必争的手机游戏(手机网游)开发领域动态资源配置或许将成为刻不容缓需要面对的技术问题根据场景按需加载资源不仅节约带宽流量且能更快速的进入游戏体现着良好的用户体验。希望本文的解决方案能为大家指引一个正确的方向识时务者为俊杰让我们携手努力吧Silverlight网游的蓝天在等待着您去开创 本节Demo在线演示地址http://cangod.com