2014-02-13 45 views
0

(注意,沒有什麼真正的「錯誤」在這裏與我的代碼(在這個意義上,它的作品),但更想知道它是如何工作的,什麼是引擎蓋下發生)作爲Sprite轉換時,Movieclip會發生什麼?

目前,我有兩個庫,每個庫都有一個對象。一個是「Apple」類,另一個是「Pear」,它們位於不同的外部swf中。

蘋果的基類是影片剪輯的內容明智它是一個影片剪輯:具有幀+動畫

這裏是我用來創建和顯示蘋果MovieClip對象的代碼:

function getClip(inputName, spriteLibrary:Loader):MovieClip { 
    var aClass:Class = spriteLibrary.contentLoaderInfo.applicationDomain.getDefinition(inputName) as Class; 
    return (MovieClip) (new aClass()); 
} 
this.addChild(getClip("Apple", referenceToTheLoadedSwfThatHasAppleInIt)); 

的上面的作品很好,蘋果出現在舞臺上並播放。

但是,梨的基類是一個雪碧(沒有動畫,框架等)。所以上述失敗,因爲該方法應該返回一個MovieClip。

this.addChild(getClip("Pear", referenceToTheLoadedSwfThatHasPearInIt)); 

我想了一會兒,我將不得不有兩個版本的上述方法,一個用於Sprite和一個用於MovieClip。不過,剛看到,我把它改成雪碧,並試圖創建蘋果:

function getClip(inputName, spriteLibrary:Loader):Sprite { 
    var aClass:Class = spriteLibrary.contentLoaderInfo.applicationDomain.getDefinition(inputName) as Class; 
    return (Sprite) (new aClass()); 
} 
this.addChild(getClip("Apple"), referenceToTheLoadedSwfThatHasAppleInIt); 
this.addChild(getClip("Pear"), referenceToTheLoadedSwfThatHasPearInIt); 

現在既會工作,但有趣的是,我發現,即使該方法返回一個雪碧,蘋果似乎仍然正常工作和戲劇它是舞臺上的動畫。我可以將其轉換爲MovieClip並訪問所有與MovieClip相關的屬性等等。

我的問題是,當蘋果「存在」爲雪碧時,它發生在所有與MovieClip相關的「東西」上,並且在使用影片剪輯和精靈時通常會遇到這種情況(通過假裝你只有當你需要它時,纔會有精靈並投射到影片剪輯)

回答

2

A Sprite類提供比MovieClip更多的基本功能,但是可以通過使用Sprite類的功能來操縱所有屬於MovieClip的類。事實上,如果你的唯一目的是做一個addChild(),你的方法可以返回與DisplayObject一樣低的班級。類型轉換不會去除任何功能的類型轉換對象,而是會限制其屬性的可用調用。說,一個DisplayObject具有xy屬性,一個Sprite可用於將對象添加到本身(addChild()方法)其中DisplayObject不具有和MovieClip具有內部動畫和說gotoAndStop()方法其中Sprite沒有。因此,如果您將Apple轉換爲Sprite,則無法撥打參考gotoAndStop(),因爲您告訴程序該參考僅爲Sprite。如果您將ApplePear對象轉換爲DisplayObject,則不能稱其爲addChild()方法來說添加一個健康狀況欄(蘋果有怪異的東西有健康狀況欄,但爲什麼不?),因爲該參考不知道底層對象支持這個功能。但是實際上對任何一個對象都不會發生任何事情,不管你如何對它們進行類型化,你只會限制自己通過接收到的引用來應用更高級的操作。

事實上,通過類型轉換來限制自己的功能是一種很好的做法,因爲這樣可以避免在工作代碼上製造「柺杖」,這可能會破壞它的目的。例如,如果您決定將Apple轉換爲高級Sprite類別(例如,public class Apple extends Sprite {...}),那麼您的代碼不會感到驚訝,因爲該類別具有定製屬性,嵌入式事件偵聽器,可能會改變顏色,但是如果您將新創建的Apple設置爲SpriteDisplayObject,您正在從實例的任何額外功能中抽象出來,只使用其基本接口(類型和類型的屬性和方法)來執行SpriteDisplayObject的打算使用的操作。如果在高級Apple中有一些被覆蓋的屬性,那麼即使從超類描述中解決,它們也​​會按照您在製作Apple類時的意圖工作 - 這實際上是重寫的目的。

簡而言之,不要擔心丟失功能,而是嘗試使用已使用的功能對最不可能的類進行類型轉換。

關於「引擎蓋下發生了什麼」:每個類都有自己的屬性和方法表,如果一個類正在擴展另一個類,那個類的表與超類的一致,並且額外的空間是被關於該類實施的屬性和方法的信息所佔據。如果存在重寫,則重寫的方法的info將替換表中相應方法的信息,而不是超類。每個實例都有一個分配給它的內存塊,如果通過實例引用調用某個方法,則會引用該類的屬性和方法表,然後該表將用於執行正確的代碼。所以,當你調用一個方法或者一個有getter或者setter的屬性時,出現以下情況:

  1. 正確的一組參數,包括指向該實例的「this」被推入堆棧。 Flash編譯器確保了順序的正確性和參數的類型。
  2. 然後,實際上是該實例的適當類的類通過實例的prototype屬性引用。 AS3中的每個班級都有這個屬性。該實例通過先前被推入堆棧的「this」指針訪問。 (從技術上講,它存儲在多個堆棧中,所以參考值與堆棧中的相同)
  3. 然後,從該表返回正確的偏移量(由編譯器確定),即被調用的地址班級的方法。無論是否覆蓋,無論在這裏,因爲在編譯時檢測到不適當的覆蓋,並且在這裏不會發生。
  4. 然後,代碼執行被轉移到返回的地址。該方法的代碼然後解析堆棧中的參數,做更多的數據保護並繼續執行。
+0

我明白了,所以根據我的使用方式,將事情保持在最簡單的形式是件好事。有趣的是你提到了健康酒吧,因爲這是一款遊戲,而我剛剛做的是從主fla中刪除所有嵌入式npc和項目精靈,以便從單獨的swf庫中進行外部加載(NPC在動畫時不會有物品)。有助於瞭解底下發生的事情,也很好地瞭解未來的重點。謝謝。 – mitim

2

將影片剪輯投射到精靈並不會剝奪它的影片剪輯實現;它只是告訴調用代碼(在這種情況下,this.addChild()),「這個對象是一個雪碧;請把它當成這樣。」調用代碼並不知道 - 或者關心 - 它確實是一個MovieClip,因爲只要它是一個DisplayObject(一個Sprite和一個MovieClip派生而來),addChild()方法就會高興地接受它。

由於影片剪輯無論如何,它對調用代碼沒有任何影響。至於Apple對象本身,它仍然是一個MovieClip的核心,所以它將繼續像它自己一樣運行。

作爲比喻,請考慮去雜貨店,購買一些商品,並在櫃檯付款。你是一個在生活的各個方面有着許多不同角色的人,但就收銀員而言,你只是一個購買顧客。這並不會讓你減少一個人的收入,但收銀員不必對你是誰或你做什麼感興趣,而不僅僅是一位顧客購物。

+0

謝謝,你的比喻確實有助於描繪在物體之間的實際交互過程中發生的事情......或者更確切地說人們。 – mitim

1

TL; DR:

你的影片剪輯將保持一個MovieClip,但就是下澆鑄爲雪碧參考將只能訪問方法和可用雪碧變量。

+0

哈哈,我確實傾向於寫很長的帖子/問題,但不確定我用來創建我的對象的方法是否有影響,因此我將它包括在內。 – mitim

+1

你的問題可以很快解釋,也可以用更深入的OOP實踐來解釋,比如多態性和資源使用,以便實際執行演員等。 已經有幾個很長的答案,我的是對於那些懶惰的人,我不知道它是如何工作的) –

2

這裏要理解的最重要的事情是沒有任何事情發生在對象本身,但編譯器對待對象的方式將不同

例如,編譯器會把這個函數作爲Sprite返回的對象,即使我們實際上返回MovieClip

function makeSprite():Sprite 
{ 
    return new MovieClip(); 
} 

var test:MovieClip = makeSprite(); 
// 1118: Implicit coercion of a value with static type flash.display:Sprite 
// to a possibly unrelated type flash.display:MovieClip. 

因此,我們需要在這裏做(因爲你現在明白)是告訴編譯器的結果是實際上通過鑄字一個MovieClip

var test:MovieClip = makeSprite() as MovieClip; 

另一件事採取的通知是,如果你是trace()結果,你會得到[object MovieClip]而不是[object Sprite]

trace(makeSprite()); // [object MovieClip] 

而且使用is來檢查它是否是一個MovieClip將返回true

trace(makeSprite() is MovieClip); // true 

即使你使用了更原始類型test,你的目標真的是一個MovieClip

var test:Object = makeSprite(); 
trace(test); // [object MovieClip] 
+0

我覺得我已經有點混淆了編譯器告訴我的內容了+它是如何處理我的代碼與在運行時在實際運行期間會發生什麼的。但我想我現在明白了。你使用'是'的第二點是什麼,當你找出對象時會發生什麼是有趣的 - 但不知道它可以這樣工作。謝謝。 – mitim

相關問題