关于使用SharedObject来缓存游戏图片或者swf文件资源到客户端本地的研究
目前市面上已经有很多游戏采用了把图片缓存到玩家客户端的做法,这种方法有利有弊,因为并不是所有的玩家都希望自己的电脑的某个角落被放入过多的缓存文件,久而久之造成电脑性能下降;但是总的来说这种技术还是好的:第一,webgame的总体资源也是有限的,不会有太大的容量占用,而且对于程序来说一般只缓存一些核心资源,比如使用很频繁的资源以及需要下载较长时间的大背景大图片或者容量稍大的swf文件等;第二,可以大幅度提升玩家第二次进入游戏的速度,某种意义上可以提升游戏体验度;
好了,废话少说,下面直接说说怎么使用SharedObject来做到把图片或者swf文件缓存到客户端,并在第二次进入程序的时候直接使用缓存的数据还原成想要的原始图片或者swf文件;主要思想是:通过URLStream把显示对象加载进来获得其ByteArra的原始数据,然后通过shareObject把二进制保存到客户端的本地,那么下次进入程序的时候直接可以通过ShareObject获得上次保存的二进制数据,有了二进制数据,只需要通过Loader.loadByte()函数就可以把二进制数据转换成DisplayObject对象;
1.首先我们使用SharedObject来写一个Cookie类:Cookie.as的代码如下:
- ////////////////////////////////////////////////////////////////////////////////
- // WEBGAME Confidential
- // Copyright 2011. All rights reserved.
- //
- // Cookie.as
- // Summary // TODO Auto-generated summary stub
- // Version 1.0
- // Author txiejun
- // Created Nov 4, 2011 10:46:36 PM
- ////////////////////////////////////////////////////////////////////////////////
- package aurora.store
- {
- import flash.events.NetStatusEvent;
- import flash.net.SharedObject;
- import flash.net.SharedObjectFlushStatus;
- import flash.utils.getQualifiedClassName;
- /**
- *
- * @author txiejun
- * @contact txiejun@126.com
- * @created Nov 4, 2011 10:46:36 PM
- */
- public class Cookie
- {
- private var _name:String = null;
- private var _path:String = null;
- private var _shdobj:SharedObject;
- private var flushStatus:String = null;
- /**
- * minDiskSpace KB 空间的存储量 小于 minDiskSpace的数量将不会有提示框弹出
- */
- public var minDiskSpace:int = 0;
- public function Cookie(name:String,path:String=null,minDiskSpace:int=0)
- {
- _name = name;
- _path = path;
- this.minDiskSpace = minDiskSpace;
- _shdobj = SharedObject.getLocal(name,_path);
- }
- private function onFlushStatus(event:NetStatusEvent):void
- {
- switch (event.info.code)
- {
- case "SharedObject.Flush.Failed":
- trace(getQualifiedClassName(this)+".onFlushStatus() Error: Failed write SharedObject to disk.");
- break;
- }
- _shdobj.removeEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
- }
- private function flushValue():void
- {
- flushStatus =null;
- try
- {
- flushStatus = _shdobj.flush(minDiskSpace);
- }
- catch (error:Error)
- {
- trace(getQualifiedClassName(this)+".setCookie() Error: Could not write SharedObject to disk.");
- }
- if(flushStatus != null)
- {
- switch(flushStatus)
- {
- case SharedObjectFlushStatus.PENDING:
- trace(getQualifiedClassName(this)+".setCookie() Requesting permission to save value.");
- _shdobj.addEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
- break;
- }
- }
- }
- public function getName():String
- {
- return _name;
- }
- public function getPath():String
- {
- return _path;
- }
- /**
- * 如果value==null 意味着删除此key
- * 如果此Key已经有值了,则原来的值被替换,并返回原来的值
- * @param key
- * @param value
- * @return
- *
- */
- public function setData(key:String,value:*):*
- {
- if(key == null)
- {
- throw new ArgumentError("cannot put a value with undefined or null key!");
- return undefined;
- }
- else if(value == null)
- {
- return remove(key);
- }
- else
- {
- var oldValue:* = getData(key);
- _shdobj.data[key]=value;
- flushValue();
- return oldValue;
- }
- }
- public function getData(key:String):*
- {
- if(!hasKey(key))
- {
- return undefined;
- }
- else
- {
- return _shdobj.data[key];
- }
- }
- public function remove(key:*):*
- {
- if(!hasKey(key))
- {
- return null;
- }
- var temp:* = _shdobj.data[key];
- delete _shdobj.data[key];
- return temp;
- }
- public function hasData(key:String):Boolean
- {
- if(!hasKey(key))
- {
- return false;
- }
- else
- {
- return _shdobj.data[key]!=null;
- }
- }
- public function hasKey(key:*):Boolean
- {
- return _shdobj.data.hasOwnProperty(key);
- }
- /**
- * 清除所有数据并从磁盘删除共享对象
- *
- */
- public function clear():void
- {
- _shdobj.clear();
- }
- }
- }
2.通过上面的cookie.as类可以实现像普通浏览器的cookie那样的功能 在本地写入或者读出数据,一般是二进制数据,int,String,Object,xml等格式;这是一个工具类;
下面再贡献一个BitmapUtil.as工具类 主要作用是用来把二进制byteArray数据装换成DisplayObject显示对象;或者把一张Bitmap转换成二进制格式的数据;
BitmapUtil.as代码如下:
- ////////////////////////////////////////////////////////////////////////////////
- // WEBGAME Confidential
- // Copyright 2011. All rights reserved.
- //
- // BitmapUtil.as
- // Summary // TODO Auto-generated summary stub
- // Version 1.0
- // Author txiejun
- // Created Nov 4, 2011 1:57:07 PM
- ////////////////////////////////////////////////////////////////////////////////
- package aurora.graphic
- {
- import flash.display.Bitmap;
- import flash.display.BitmapData;
- import flash.display.DisplayObject;
- import flash.display.Loader;
- import flash.display.LoaderInfo;
- import flash.display.Sprite;
- import flash.events.Event;
- import flash.events.IOErrorEvent;
- import flash.geom.Matrix;
- import flash.utils.ByteArray;
- import flash.utils.getQualifiedClassName;
- /**
- *
- * @author txiejun
- * @contact txiejun@126.com
- * @created Nov 4, 2011 1:57:07 PM
- */
- public class BitmapUtil
- {
- public function BitmapUtil()
- {
- }
- /**
- * 把 ByteArray装换成DisplayObject
- * @param byteArray
- * @param callBack
- *
- */
- public static function toDisplayObject(byteArray:ByteArray,callBack:Function):void
- {
- if(byteArray==null)
- {
- if(callBack!=null)
- {
- callBack.call(null,null);
- }
- return;
- }
- var loader:Loader = new Loader();
- var onCompleteHandler:Function = function(event:Event):void
- {
- var loaderInfo:LoaderInfo = event.currentTarget as LoaderInfo;
- var content:DisplayObject = loaderInfo.content;
- loaderInfo.removeEventListener(Event.COMPLETE, onCompleteHandler);
- loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onIoErrorHandler);
- if(callBack!=null)
- {
- callBack.call(null,content);
- }
- loader = null;
- }
- var onIoErrorHandler:Function = function(event:IOErrorEvent):void
- {
- var loaderInfo:LoaderInfo = event.currentTarget as LoaderInfo;
- loaderInfo.removeEventListener(Event.COMPLETE, onCompleteHandler);
- loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onIoErrorHandler);
- trace(getQualifiedClassName(this)+".toDisplayObject() :"+event.text);
- if(callBack!=null)
- {
- callBack.call(null,null);
- }
- }
- loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
- loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIoErrorHandler);
- loader.loadBytes(byteArray);
- }
- }
- }
这两个工具类写好了以后,就可以开始写主程序了;
ShareObjectTest.as文件如下:
- ////////////////////////////////////////////////////////////////////////////////
- // WEBGAME Confidential
- // Copyright 2011. All rights reserved.
- //
- // ShareObjectTest.as
- // Summary // TODO Auto-generated summary stub
- // Version 1.0
- // Author txiejun
- // Created Nov 5, 2011 12:31:10 AM
- ////////////////////////////////////////////////////////////////////////////////
- package
- {
- import aurora.graphic.BitmapUtil;
- import aurora.store.Cookie;
- import flash.display.DisplayObject;
- import flash.display.Sprite;
- import flash.display.StageAlign;
- import flash.display.StageScaleMode;
- import flash.events.Event;
- import flash.events.IOErrorEvent;
- import flash.net.URLRequest;
- import flash.net.URLStream;
- import flash.utils.ByteArray;
- /**
- *
- * @author txiejun
- * @contact txiejun@126.com
- * @created Nov 5, 2011 12:31:10 AM
- */
- public class ShareObjectTest extends Sprite
- {
- private var assests:Array = ["mc_1.swf","img_1.png"];
- private var cookie:Cookie ;
- private var index:int = 1;
- public function ShareObjectTest()
- {
- super();
- if(stage)
- {
- stage.align = StageAlign.TOP_LEFT;
- stage.scaleMode = StageScaleMode.NO_SCALE;
- stage.stageFocusRect = false;
- }
- cookie = new Cookie("ShareObjectTest");
- // cookie.clear();
- loadAssest(assests[index]);
- }
- private function loadAssest(url:String):void
- {
- //检查是否已经加载过资源
- if(cookie.hasData(url))
- {
- //获得缓存的二进制数据
- var byteArray:ByteArray = cookie.getData(url);
- //转换成显示对象
- BitmapUtil.toDisplayObject(byteArray,onLoaded);
- trace("url",url,"already loaded");
- }
- else
- {
- //加载二进制数据
- var urlstream:URLStream = new URLStream();
- urlstream.addEventListener(Event.COMPLETE,onStreamComplete);
- urlstream.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
- urlstream.load(new URLRequest(url));
- trace("url",url,"need load");
- }
- }
- private function onLoaded(content:DisplayObject):void
- {
- this.addChild(content);
- content.x = index*100;
- content.y = index*50;
- trace("onLoaded ",assests[index]);
- }
- private function onStreamComplete(event:Event):void
- {
- var urlstream:URLStream = event.currentTarget as URLStream;
- urlstream.removeEventListener(Event.COMPLETE,onStreamComplete);
- urlstream.removeEventListener(IOErrorEvent.IO_ERROR,onIOError);
- var byteArray:ByteArray = new ByteArray();
- urlstream.readBytes(byteArray);
- //转换成显示对象
- BitmapUtil.toDisplayObject(byteArray,onLoaded);
- //保存二进制数据到本地客户端
- cookie.setData(assests[index],byteArray);
- trace("cookie.setData",assests[index]);
- }
- private function onIOError(event:IOErrorEvent):void
- {
- var urlstream:URLStream = event.currentTarget as URLStream;
- urlstream.removeEventListener(Event.COMPLETE,onStreamComplete);
- urlstream.removeEventListener(IOErrorEvent.IO_ERROR,onIOError);
- }
- }
- }
通过上面的三个类就可以运行起来,这里还需要准备两张资源:分别是mc_1.swf和img_1.png 确定放置到正确的路径下面,然后运行程序:这儿可以通过ShareObjectTest里面的index来改变究竟要加载那种类型的资源以供你测试,你可以看到当你第一次运行这个程序的时候,他的执行结果trace类似于下面:
- url img_1.png need load
- cookie.setData img_1.png
- onLoaded img_1.png
但是第二次以后再运行的时候,得到的trace结果是:
- url img_1.png already loaded
- onLoaded img_1.png
可以看出来,第二次是使用的缓存到客户端的二进制数据了,从而我们想要的效果已经达到!