2009-08-11 57 views
2

我正在创建一个2d flash游戏(在flex/actionscript 3中编码),在需要时下载资源。目前,我有它的设置是这样的:运行时加载外部资产并在actionscript 3中重新使用预加载的资产?

AssetLoader.as

package 
{ 
    import flash.display.Loader; 
    import flash.net.URLRequest; 

    public class AssetLoader extends Loader 
    { 
     //set vars 
     private var url:String = "http://test.com/client/assets/"; 

     public function AssetLoader(url:String) 
     { 
      Logger.log("AssetLoader request: " + this.url + url); 
      var request:URLRequest = new URLRequest(this.url + url); 
      this.load(request); 
     } 
    } 
} 

然后,在这里我要加载的资产我做到以下几点:

var asset:AssetLoader = new AssetLoader("ships/" + graphicId + ".gif"); 
asset.contentLoaderInfo.addEventListener(Event.COMPLETE, onShipAssetComplete, false, 0, true); 

private function onShipAssetComplete(event:Event):void 
{ 
    var loader:Loader = Loader(event.target.loader); 
     shipImage = Bitmap(loader.content); 
     shipImage.smoothing = true; 
     addChild(shipImage); 
} 

的事情是,这种方法不检查已经下载的资产,所以它会在第二次请求同样的资产时重新下载它们(我认为)。

所以,我需要的是一个数组,其中存储了所有下载的资产,并根据请求检查此资产的名称是否存在于数组中。所以如果它已经被下载,那么来自内存的资源必须被返回而不是被重新下载。

我可以使assetloader一个静态类,但我必须等待事件时,它的完成下载图像火 - 所以我不能简单地让一个静态函数返回相应的图像。任何想法我应该如何做到这一点?

编辑征求意见后企图:

package 
{ 
    import flash.display.Loader; 
    import flash.events.Event; 
    import flash.net.URLRequest; 

    public final class AssetManager 
    { 
     private static var assets:Object = {}; 
     private static var preUrl:String = Settings.ASSETS_PRE_URL; 

     public static function load(postUrl:String):* 
     { 
      if (assets[postUrl]) 
      { //when the asset already exists 
       //continue 
      } 
      else 
      { //the asset still has to be downloaded 
       var request:URLRequest = new URLRequest(preUrl + postUrl); 
       var loader:Loader = new Loader(); 
       loader.load(request); 
       loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
       function(event:Event):void 
       { 
        var loader:Loader = Loader(event.target.loader); 
        assets[postUrl] = loader.content; 
       }, false, 0, true); 
      } 
     } 
    } 
} 

EDIT2:另一种尝试

package 
{ 
    import flash.display.Loader; 
    import flash.events.Event; 
    import flash.events.EventDispatcher; 
    import flash.net.URLRequest; 

    public final class AssetManager 
    { 
     private static var assets:Object = {}; 
     private static var preUrl:String = Settings.ASSETS_PRE_URL; 

     public static function load(postUrl:String):* 
     { 
      if (assets[postUrl]) 
      { //the asset already exists 
       var dispatcher:EventDispatcher = new EventDispatcher(); 
       dispatcher.dispatchEvent(new CustomEvent(CustomEvent.LOAD_COMPLETE, assets[postUrl])); 
      } 
      else 
      { //the asset still has to be downloaded 
       var request:URLRequest = new URLRequest(preUrl + postUrl); 
       var loader:Loader = new Loader(); 
       loader.load(request); 
       loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
       function(event:Event):void 
       { 
        var loader:Loader = Loader(event.target.loader); 
        assets[postUrl] = loader.content; 
        var dispatcher:EventDispatcher = new EventDispatcher(); 
        dispatcher.dispatchEvent(new CustomEvent(CustomEvent.LOAD_COMPLETE, assets[postUrl])); 
       }, false, 0, true); 
      } 
     } 
    } 
} 

然后,我尝试以下方法:

var asset:AssetManager = AssetManager.load("ships/" + graphicId + ".gif"); 
      asset.addEventListener(CustomEvent.LOAD_COMPLETE, onShipAssetComplete, false, 0, true); 

,但得到的错误,“undefin ed方法addEventListener通过类型静态AssetManager的引用“(粗略翻译)。

回答

1

你可以添加一个静态对象(用作与URL的字典资产键和值资产的内容)在AssetLoader类,并在同一时间继续使用在你使用它的方式类马上。

private static var assets:Object = {}; 

不同之处在于如果之前已请求过内容的URL,那么您的类将需要检查该静态对象。如果有,立即发送完整的事件。如果没有,请遵循正常的例程,并且不要忘记使用新加载的资源填充静态对象。



更新:

这是我的意思一个简单的例子。我没有时间来测试这个,但它应该工作。

注意: 您必须调用您创建的AssetLoader实例的loadAsset()方法才能实际加载资产。这与我们正在扩展的Loader类的工作方式一致。

你应该总是添加所有事件侦听器之前调用loadAsset()方法。在你的问题中,你从构造函数中调用了load()方法,并且之后只添加Event.COMPLETE的事件侦听器。这可能会产生奇怪的结果。

下面的代码:

package 
{ 
    import flash.display.Loader; 
    import flash.events.Event; 
    import flash.net.URLRequest; 


    public class AssetLoader extends Loader 
    { 
    private static const BASE_URL:String = 'http://test.com/client/assets/'; 

    public static var storedAssets:Object = {}; 

    private var assetURL:String; 
    private var urlRequest:URLRequest; 
    private var cached:Boolean = false; 


    public function AssetLoader(url:String):void 
    { 
     trace('Loading: ' + url); 
     assetURL = url; 

     if (storedAssets[assetURL] != null) 
     { 
     cached = true; 
     trace('Cached'); 
     } 
     else 
     { 
     trace('Loading uncached asset'); 
     urlRequest = new URLRequest(BASE_URL + assetURL); 
     contentLoaderInfo.addEventListener(Event.COMPLETE, OnAssetLoadComplete); 
     } 
    } 

    public function loadAsset():void 
    { 
     if (cached) 
     loadBytes(storedAssets[assetURL]); 
     else 
     load(urlRequest); 
    } 

    private function OnAssetLoadComplete(event:Event):void 
    { 
     storedAssets[assetURL] = contentLoaderInfo.bytes; 
     trace('Loaded ' + contentLoaderInfo.bytesLoaded + ' bytes'); 
    } 

    } 

} 


更新2:

这里有一个如何使用上面的类:

var assetLdr:AssetLoader = new AssetLoader("ships/" + graphicId + ".gif"); 
assetLdr.contentLoaderInfo.addEventListener(Event.COMPLETE, onShipAssetComplete); 
assetLdr.loadAsset(); 

private function onShipAssetComplete(event:Event):void 
{ 
    var shipImage:Bitmap = Bitmap(event.target.loader.content); 
    // Do stuff with shipImage 
} 
+0

嘿,我不太清楚你想要我做什么。我可以用资产URL和内容创建一个全球图书馆。当一个资产被请求时,我想我可以在图书馆已经找到这个URL的时候启动它。但是,如何让这个事件,然后返回此网址的库内容?我不太明白。 – Tom 2009-08-11 23:02:51

+0

我第一次尝试编辑原始文章。但是,如评论中所解释的,我陷入困境......也许您或其他人有任何建议? – Tom 2009-08-12 13:10:35

+1

Lior可能暗示你有一张包含资源url - >加载资源的地图。就像'assets [url] = loadedContent' – 2009-08-12 13:25:36

1

也许你应该采取看看Bulk Loader。它做你想要做的事情。如果你真的想使用自定义解决方案,那将是一个很好的参考点,但为什么要重新发明轮子? Tyler。

Tyler。

+0

嗯,它的功能似乎有点太多了,可能会导致额外的资源使用和负载 – Tom 2009-08-11 22:32:07

+0

对于我们的游戏开发者,我们已经构建了一个非静态加载器,在加载级别时预先加载每个级别的所有图形。因为我们知道所有加载发生在那里,所以我们知道在访问它们时资产将可用。我们只需将所有的URL存储在一个数组t中母鸡一次加载一个,直到完成,然后发送一个完整的事件。我们还实施了资产“老化”,因此如果资产未用于X级负载,我们会通过它来节省内存资源。 – 2009-08-11 22:45:30

+0

不幸的是我需要在运行时加载大部分资产,所以这不适合我。此外,您推荐的课程似乎用于批量加载,这不是我想要的。不过谢谢。 – Tom 2009-08-11 22:56:20

1

这是你的加载命令的改变来捕捉RESOURCEID

public function load(postUrl:String):* 
{ 
    var index:int; 
    if ((index = assetExists(postUrl)) != -1) 
    { 
     dispatchEvent(new CustomEvent(CustomEvent.LOAD_COMPLETE, asset[postUrl])); 
    } 
    else 
    { 
     //the asset still has to be downloaded 
     var request:URLRequest = new URLRequest(preUrl + postUrl); 
     var loader:Loader = new Loader(); 
     loader.load(request); 
     loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
     function(event:Event) 
     { 
      // NOTE: not sure on scoping here ... 
      // pretty sure you're this will be the Loader 
      // if not just read it off the event like you were before 
      assets[postUrl] = content; 
      dispatchEvent(new CustomEvent(CustomEvent.LOAD_COMPLETE, asset[postUrl])); 
     }, false, 0, true); 
    } 
} 

/* In a new file */ 
public class CustomEvent extends Event 
{ 
    public static const LOAD_COMPLETE:String = "CustomEvent_LoadComplete"; 

    // If you know the type you should use it (e.g. Sprite/DisplayObject) 
    public var content:*; 

    public function CustomEvent(type:String, _content:*) 
    { 
     content = _content; 
     super(type); 
    } 
} 

注意:当你写一个事件,你的后代也应该覆盖toStringclone方法。我也欺骗了构造函数,因为你可能想通过弱引用和类似的东西。

+0

谢谢,更新的第一篇文章。现在我不确定如何继续。认为我需要解雇资产可获得的事件(在这两种情况下)。但如何用静态公共类来做到这一点? – Tom 2009-08-12 14:11:57

+2

您正在继承Loader。加载方法不需要是静态的。 Loader继承自EventDispatcher,因此它可以派发事件。我建议为已加载的内容创建一个带有属性的自定义事件并进行调度。'dispatchEvent(new CustomLoadEvent(Event.COMPLETE,content))' – 2009-08-12 14:36:42

+0

对不起,但什么是CustomLoadEvent?我不知道那个对象。我知道Event对象,但是如何将内容传递给它?如果这个问题没有太多问,你可以举个例子吗?谢谢。 – Tom 2009-08-12 15:11:06