通过简单的 ResourceManager 管理 XNA 中的资源,WPXNA(二)
平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛。在这里分享一下经验,仅为了和各位朋友交流经验。平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXNA 吧,最后请高手绕道而行吧,以免浪费时间。(为了突出重点和减少篇幅,有些示例代码可能不够严谨。)
资源的类型
在一些简单的 2D 游戏设计中,我们通常用到的资源是一些字体,图像和声音。所以这里就不涉及视频和模型这些内容了,要制作视频和 3D 模型往往需要花费很多时间。
这里,平方通过枚举类型 ResourceType 来区分不同的资源:
internal enum ResourceType { Image, Font, Sound, Music, }在上面的代码中,Image 表示图像资源,Font 表示字体资源。Sound 和 Music 都表示声音资源,不同的是 Music 通过 MediaPlayer 类播放(一般是 mp3 文件),而 Sound 一般指一些小的 wav 文件。
标识资源
平方创建了一个 Resource 结构来标识一个资源,他有三个公开的字段,Name 是资源的名称,这个名称不能和其他资源重复。Type 是资源的类型,也就是上面提到的 ResourceType。Path 是资源的访问路径,也就是资源文件在项目中的位置,如下图所示:
internal struct Resource { internal readonly string Name; internal readonly string Path; internal readonly ResourceType Type; internal Resource ( string name, ResourceType type, string path ) { if ( string.IsNullOrEmpty ( name ) || string.IsNullOrEmpty ( path ) ) throw new ArgumentNullException ( "name, path", "name, path can't be null" ); this.Name = name; this.Type = type; this.Path = path; } }因为,只有正确的载入资源,游戏才能正常运行,所以在 Resource 类的构造函数中,平方对参数作了一些检查。
管理资源
然后,我们可以通过 ResourceManager 来管理资源。
在构造函数中,我们接受一个 Resource 结构数组,他们也就是需要管理的资源。
internal readonly IList<Resource> Resources; internal ResourceManager ( IList<Resource> resources ) { this.Resources = null == resources ? new Resource[] { } : resources; }当然,ResourceManager 本身并不能够载入资源,所以我们需要使用 ContentManager 类:
private ContentManager contentManager; internal World World; private readonly Dictionary<string, Texture2D> textures = new Dictionary<string, Texture2D> ( ); private readonly Dictionary<string, SpriteFont> fonts = new Dictionary<string, SpriteFont> ( ); private readonly Dictionary<string, SoundEffectInstance> sounds = new Dictionary<string, SoundEffectInstance> ( ); private readonly Dictionary<string, Song> music = new Dictionary<string, Song> ( ); public void LoadContent ( ) { if ( null == this.contentManager ) this.contentManager = new ContentManager ( this.World.Services, contentDirectory ); try { foreach ( Resource resource in this.Resources ) switch ( resource.Type ) { case ResourceType.Image: this.textures.Add ( resource.Name, this.contentManager.Load<Texture2D> ( resolution + resource.Path ) ); break; case ResourceType.Font: this.fonts.Add ( resource.Name, this.contentManager.Load<SpriteFont> ( resource.Path ) ); break; case ResourceType.Sound: this.sounds.Add ( resource.Name, this.contentManager.Load<SoundEffect> ( resource.Path ).CreateInstance ( ) ); break; case ResourceType.Music: this.music.Add ( resource.Name, this.contentManager.Load<Song> ( resource.Path ) ); break; } } catch { } }调用 ResourceManager 的 LoadContent 方法来载入资源,在 LoadContent 方法中,我们会创建一个新的 ContentManager 对象,并通过他的 Load 方法载入我们事先接受的资源。
要创建 ContentManager,我们还需要设置 ResourceManager 的 World 字段(你也可以将他修改为属性)。所以,在调用 LoadContent 之前,你需要确保 World 字段不为空。
当你觉得这些资源已经没有用了的时候,调用 UnloadContent 方法来释放资源:
public void UnloadContent ( ) { foreach ( Texture2D texture in this.textures.Values ) texture.Dispose ( ); foreach ( SoundEffectInstance sound in this.sounds.Values ) sound.Dispose ( ); foreach ( Song song in this.music.Values ) song.Dispose ( ); this.textures.Clear ( ); this.fonts.Clear ( ); this.sounds.Clear ( ); this.music.Clear ( ); if ( !this.Resources.IsReadOnly ) this.Resources.Clear ( ); if ( null != this.contentManager ) this.contentManager.Unload ( ); }在上面的代码中,我们先对所有的资源调用了 Dispose 方法,然后调用了 ContentManager 的 Unload 方法。
使用资源
最后,我们在 World 类中具体的使用一下 ResourceManager 类。
private readonly ResourceManager resourceManager; public World ( Color backgroundColor ) : base ( ) { // ... this.resourceManager = new ResourceManager ( new Resource[] { new Resource ( "bird", ResourceType.Image, @"image\bird" ), new Resource ( "click", ResourceType.Sound, @"sound\click" ) } ); this.resourceManager.World = this; }在 World 的构造函数中,我们创建了一个 ResourceManager,并指出我们需要一个图片和一个波形文件。
protected override void OnNavigatedTo ( NavigationEventArgs e ) { // ... this.resourceManager.LoadContent ( ); base.OnNavigatedTo ( e ); }当页面载入之后,我们调用 LoadContent 方法来载入图片和声音。之后,我们在 OnUpdate 和 OnDraw 方法中使用他们。
private void OnUpdate ( object sender, GameTimerEventArgs e ) { this.resourceManager.GetSound ( "click" ).Play ( ); } private void OnDraw ( object sender, GameTimerEventArgs e ) { this.GraphicsDevice.Clear ( this.BackgroundColor ); this.spiritBatch.Begin ( ); this.spiritBatch.Draw ( this.resourceManager.GetTexture ( "bird" ), new Vector2 ( 20, 20 ), Color.White ); this.spiritBatch.End ( ); }通过 ResourceManager 的 GetTexture 和 GetSound 方法可以获取指定的图片和声音,只需要传递资源的名称即可。
最后,你还需要在一个适合的位置调用 ResourceManager 的 UnloadContent 方法。
本期视频 http://v.youku.com/v_show/id_XNTYwOTA2ODgw.html
项目地址 http://wp-xna.googlecode.com/
更多内容 WPXNA
平方开发的游戏 http://zoyobar.lofter.com/
QQ 群 213685539
欢迎平方在其他位置发布的同一文章:http://www.wpgame.info/post/decc4_6329f7
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架