将Movieclip作为精灵投射时会发生什么?

时间:2014-02-13 05:25:14

标签: actionscript-3 flash

(请注意,我的代码(从某种意义上说它有效)并没有什么“错误”,但更多的是想知道它是如何工作的以及在幕后发生的事情) < / p>

目前我有两个库,每个库都有一个对象。一个设置为“Apple”类,另一个设置为“Pear”,它们位于单独的外部swfs中。

Apple的基类是MovieClip,因为内容方面它是一个movieclip:有帧+动画

以下是我用来创建和显示Apple 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));

上述工作正常,Apple出现在舞台上并播放。

然而,Pear的基类是Sprite(没有动画,帧等)。所以上面的失败,因为该方法应该返回一个MovieClip。

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

我想了一会儿我必须有两个版本的上述方法,一个用于Sprite,一个用于MovieClip。但只是看,我把它改成了Sprite并试图创建Apple:

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);

现在两者都有效,但有趣的是,我发现即使该方法返回一个Sprite,Apple仍然可以正常工作并在舞台上播放它的动画。我可以将它转换为MovieClip并访问所有与MovieClip相关的属性,等等。

我的问题是,当Apple作为Sprite“存在”时,所有与MovieClip相关的“东西”都发生了什么事情,这在使用MovieClips和Sprites时实际上是正常的事情(假装你只是只有在需要的时候才有精灵并投射到MovieClip?)

4 个答案:

答案 0 :(得分:2)

将一个MovieClip强制转换为Sprite不会剥夺它的MovieClip实现;它只是告诉调用代码(在这种情况下,this.addChild())“这个对象是一个精灵;请将其视为这样。”调用代码不知道 - 或者不关心 - 它实际上是一个MovieClip,因为只要它是一个DisplayObject(一个Sprite,又是一个MovieClip,派生自),addChild()方法会很乐意接受它

由于MovieClip 无论如何都是一个Sprite,它对调用代码没有任何影响。至于Apple对象本身,它仍然是一个内心的MovieClip,因此将继续像它自己一样运行。

作为一个类比,想想去杂货店买一些商品,然后在柜台付款。你是一个在生活的各个方面有许多不同角色的人,但就收银员而言,你只是一个顾客进行购买。这并不能使你成为一个人,但收银员不必对你是谁或你做什么感兴趣,除了购买顾客之外。

答案 1 :(得分:2)

Sprite类提供比MovieClip更多的基本功能,但可以使用Sprite类的功能操作MovieClip的所有内容。实际上,如果您的唯一目的是执行DisplayObject,则您的方法可以返回与addChild()一样低的类。类型转换不会剥离任何功能的类型转换对象,而是限制对其属性的可用调用。比如,DisplayObject具有xy属性,可以使用Sprite向自身添加对象(addChild()方法){{1 }}没有,DisplayObject有内部动画和MovieClip没有的gotoAndStop()方法。因此,如果您将Sprite类型转换为Apple,则无法拨打参考Sprite,因为您已告知程序该参考是只是gotoAndStop()。如果您将SpriteApple对象强制转换为Pear,则无法调用其DisplayObject方法来添加健康栏(对于拥有健康栏的苹果来说很奇怪,但为什么不呢?),因为引用不知道底层对象支持这个功能。但实际上任何一个对象都不会发生任何事情,无论你如何对它们进行类型转换,你都会限制自己通过接收引用来应用更高级的操作。

实际上,通过类型转换来限制自己的功能是一种很好的做法,因为您可以免受制作&#34;拐杖&#34;工作代码可能会破坏其目的。比如说,如果您决定将addChild()转换为具有定制属性,嵌入式事件监听器,颜色更改的高级Apple类(例如,Sprite),您的代码就不会感到惊讶,但是如果你将新创建的public class Apple extends Sprite {...}类型转换为AppleSprite,那么你将从实例的任何额外功能中抽象出来并仅使用其基本接口(类型化类的属性和方法) )执行DisplayObjectSprite旨在执行的操作。如果在高级DisplayObject中有一些被覆盖的属性,它们将在制作Apple类时按预期工作,即使从超类描述中解决 - 这实际上是覆盖的目的。

简而言之,不要担心失去功能,但尝试使用已使用的功能进行类型转换为最少的类。

关于&#34;幕后发生的事情&#34;:每个类都有自己的属性和方法表,如果一个类正在扩展另一个类,那么该类的表与超类#39相同;直到最后,额外的空间占用了类所实现的属性和方法的信息。如果有覆盖,则重写方法的信息将替换表中相应方法的信息,而不是超类。每个实例都有一个分配给它的内存块,有一个对类的属性和方法表的引用,如果通过实例引用调用方法,则该表用于执行正确的代码。因此,当您调用方法或分配了getter或setter的属性时,会发生以下情况:

  1. 正确的参数集,包括&#34;这个&#34;指向该实例的指针被推入堆栈。 Flash编译器确保了顺序的正确性和参数的类型。
  2. 然后,通过实例的Apple属性引用实际上该实例的正确类的类。 AS3中的每个班级都有此属性。该实例通过&#34;此&#34;指针先前被推入堆栈。 (从技术上讲,它不仅仅存储在堆栈中,因此引用与堆栈中的引用相同)
  3. 然后,从该表返回正确的偏移量(由编译器确定),即该类的被调用方法的地址。是否重写,无论如何,因为在编译时检测到不正确的覆盖,并且不会在此处发生。
  4. 然后,代码执行被转移到返回的地址。然后,该方法的代码解析堆栈中的参数,进行更多的数据保护并继续实现。

答案 2 :(得分: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]

答案 3 :(得分:1)

TL; DR:

您的MovieClip将保留一个MovieClip,但是下载到Sprite的引用将只能访问Sprite可用的方法和变量。