silverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存

在上篇中,我们实现了一个带有池化、并发连接限制能力的资源下载器,虽然这个下载器能够使我们的游戏动态加载资源并在加载完毕/失败后调用回调方法。但是还是缺乏一些智能。比如我要加载一个game_role_petegg.zip的资源包,如我们有需求:

1.对已经下载过的资源不再重复下载。

2.下载过的资源要缓存,一方面存在内存中,一方面存在isolatedstorage中。

实现这些功能会极大的提高用户体验,所我们有必要设计一个带有缓存控制能力的资源管理器。

复用已有的DownloadDelegater

搞开发的嘛,不可能每一个需求都单独写一片代码,这要将对象的职责分离清楚,复用还是很容易的。

我们定义需求接口:

public   interface  IWebClientResourceService 
    { 
        
void  Load(Uri uri, DownloadResultEventHandler callback); 
        
void  PutIsolatedStorageToMemoryCache(Uri uri); 
        
void  PutMemoryCacheToIsolatedStorage(Uri uri); 
        
void  RemoveCache(Uri uri); 
    }

 

 

Load方法会下载指定uri的资源,如果之前已经在下载过就不会重复下载。

PutIsolatedStorageToMemoryCache将隔离存储中的数据加载到内存中。

PutMemoryCacheToIsolatedStorage将内存数据保存到隔离存储。

下面通过组合的方式复用之前的DownloadDelegater。

image

image

ExpandedBlockStart.gif WebClientResourceService
namespace  Sopaco.Silverlight.Insfrastructure.Net.DownloadActivator
{
    
public   class  WebClientResourceService : Sopaco.Silverlight.Insfrastructure.Net.DownloadActivator.IWebClientResourceService
    {
        
public   static   readonly  WebClientResourceService Instance;
        
static  WebClientResourceService()
        {
            Instance 
=   new  WebClientResourceService();
        }
        
private  Dictionary < Uri, DownloadTask >  _resourceCacher  =   new  Dictionary < Uri, DownloadTask > ();
        
private  DownloadDelegater _downloadDelegater  =   new  DownloadDelegater();

        
private   object  _locker_ResourceCacher  =   new   object ();

        
public   void  Load(Uri uri, DownloadResultEventHandler callback)
        {
            
#region  检查是否已经有缓存
            
lock  (_locker_ResourceCacher)
            {
                
if  (_resourceCacher.ContainsKey(uri))
                {
                    
if  (callback  !=   null )
                    {
                        var task 
=  _resourceCacher[uri];
                        callback(task.CloneStream, task.Status);
                    }
                    
return ;
                }
                _resourceCacher[uri] 
=   new  DownloadTask()
                {
                    Uri 
=  uri,
                    Stream 
=   null ,
                    Status 
=  DownloadStatus.UnStarted
                };
            }
            
#endregion
            
#region  使用下载器下载
            _downloadDelegater.Download(uri, (stream, status) 
=>  
                    {
                        onResultArrive(uri, status, stream);
                        
if (callback  !=   null )
                            callback(stream, status);
                    });
            
if  (_resourceCacher[uri].Status  ==  DownloadStatus.UnStarted) // 防止过快下载而使状态不同步
            {
                _resourceCacher[uri].Status 
=  DownloadStatus.Running;
            }
            
#endregion
        }
        
///   <summary>
        
///  移除缓存
        
///  未防止缓存内容过大导致内存持续消耗,应该适当调用此方法移出缓存(或者存放在隔离存储中?)
        
///   </summary>
         public   void  RemoveCache(Uri uri)
        {
            
lock  (_locker_ResourceCacher)
            {
                
if  (_resourceCacher.ContainsKey(uri))
                {
                    var cacheObj 
=  _resourceCacher[uri];
                    
if (_resourceCacher.Remove(uri))
                    {
                        cacheObj.Dispose();
                    }
                    
else
                    {
                        System.Diagnostics.Debug.WriteLine(
" 移除资源异常:无法移除资源@ "   +  System.Reflection.MethodInfo.GetCurrentMethod().ToString());
                    }
                }
            }
        }
        
///   <summary>
        
///  将一个资源缓存到隔离存储中
        
///   </summary>
        
///   <param name="uri"></param>
         public   void  PutMemoryCacheToIsolatedStorage(Uri uri)
        {
            
if (_resourceCacher.ContainsKey(uri))
            {
                IsolateStorageRespository.Instance.AddWithOverwrite(uri.ToString(), _resourceCacher[uri]);
            }
        }
        
///   <summary>
        
///  从隔离存储中将一个资源缓存起来
        
///   </summary>
        
///   <param name="uri"></param>
         public   void  PutIsolatedStorageToMemoryCache(Uri uri)
        {
            
if  (_resourceCacher.ContainsKey(uri))
            {
                var cache 
=  IsolateStorageRespository.Instance.Get < DownloadTask > (uri.ToString());
                
if (cache  !=   null )
                {
                    _resourceCacher[uri] 
=  cache;
                }
            }
        }
        
private   void  onResultArrive(Uri uri, DownloadStatus status, MemoryStream stream)
        {
            _resourceCacher[uri].Status 
=  status;
            _resourceCacher[uri].Stream 
=  stream;
        }
    }
}

 

 

进一步使用

上面的WebClientResourceService功能还是有些“大一统”,我们可以进一步针对一些特定资源进行应用。

示例需求:对于图片资源包和一些零散的没有放到资源包里的图片资源,一旦下载下来将其放到隔离存储中,下次再需要下载此图片时就直接从隔离存储中取得(如果资源有更新的话将隔离存储中的数据清除就ok)。

ExpandedBlockStart.gif GameImageResService
namespace  Sopaco.Silverlight.GameFramewrok.GameRes
{
    
///   <summary>
    
///  应用WebClientResourceService定制的一个游戏资源服务模块
    
///   </summary>
     public   class  GameImageResService
    {
        
#region  make it a singleton
        
public   static   readonly  GameImageResService Instance;
        
static  GameImageResService()
        {
            Instance 
=   new  GameImageResService();
        }
        
public  GameImageResService()
        {

        }
        
#endregion
        
private   static   readonly   string  IMG_ZIP_XML  =   " resconfig.xml " ;
        
private  WebClientResourceService _resourceService  =  WebClientResourceService.Instance;
        
private  Dictionary < Uri, BitmapImage >  _imageCache  =   new  Dictionary < Uri, BitmapImage > ();
        
private  Dictionary < string , BitmapImage >  _namedImageCache  =   new  Dictionary < string , BitmapImage > ();
        
///   <summary>
        
///  图片资源
        
///   </summary>
         public   void  GetBitmapImage(Uri uri, Action < BitmapImage >  callback)
        {
            
if (_imageCache.ContainsKey(uri))
            {
                callback(_imageCache[uri]);
                
return ;
            }
            _resourceService.Load(uri, (stream, status) 
=>  
                {
                    
if (status  ==  DownloadStatus.Completed)
                    {
                        var image 
=   new  BitmapImage();
                        image.SetSource(stream);
                        _imageCache[uri] 
=  image;
                        _resourceService.PutMemoryCacheToIsolatedStorage(uri);
// 图片资源由GameResService托管,将WebClientResourceService中的缓存持久化
                        callback.ExecuteSecurity(image);
                    }
                    
else
                    {
#if  DEBUG
                        
throw   new  Exception( " error in resource downloading " );
#endif
                    }
                });
        }
        
///   <summary>
        
///  载入一个zip资源包中的图片资源
        
///   </summary>
         /* 配置文件格式
         * resconfig.xml
         * <?……?>
         * <AppRoot>
         * <ImgResSection><Image key="……" uri="……" /></ImgResSection>
         * </AppRoot>
         * #endregion
         
*/
        
public   void  GetBitmapImageInZip(Uri uri, Action onZipLoaded, Action onResourcesLoad)
        {
            _resourceService.Load(uri, (stream, status) 
=>
            {
                
if (status  !=  DownloadStatus.Completed)
                {
#if  DEBUG
                    
throw   new  Exception( " error in download resource " );
#endif
                }
                onZipLoaded.ExecuteSecurity();
                StreamResourceInfo info 
=   new  StreamResourceInfo(stream,  null );
                
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;
                                }
                            }
                        }
                    }
                }
                onResourcesLoad.ExecuteSecurity();
                
#region  zip图片资源包由GameResService托管,将WebClientResourceService中的缓存持久化
                _resourceService.PutMemoryCacheToIsolatedStorage(uri);
                
#endregion
            });
        }
        
public  BitmapImage GetImageByUri(Uri uri)
        {
            
if  ( ! _imageCache.ContainsKey(uri))
                
return   null ;
            
return  _imageCache[uri];
        }
        
public  BitmapImage GetImageBySpecialName( string  key)
        {
            
if ( ! _namedImageCache.ContainsKey(key))
                
return   null ;
            
return  _namedImageCache[key]; 
        }
    }
}

 

 

本文源码下载

 最后祝大家圣诞快乐Merry Christmas!

转载于:https://www.cnblogs.com/wJiang/archive/2010/12/24/1916302.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值