2009-08-11 59 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