在 Actionscript 2 中立即引用影片剪辑类实例
Posted
技术标签:
【中文标题】在 Actionscript 2 中立即引用影片剪辑类实例【英文标题】:Referencing movie clip class instances immediately in Actionscript 2 【发布时间】:2010-10-28 03:15:16 【问题描述】:这是一个非常令人沮丧的 Actionscript 2 问题,我遇到的影片剪辑与在时间轴上创建的类相关联,需要立即在代码中引用:
-- 我的库中有一个与类“C”关联的影片剪辑“C”。
-- “C”类扩展了 MovieClip。
-- 我在舞台上有一个带有帧标签“关闭”和“打开”的影片剪辑。此影片剪辑的实例名称为“mc”。
-- 在“on”框架上有一个名为“inst”的类“C”的实例。
-- 类“C”的构造函数包括一个输出“C构造函数!”的跟踪语句让我知道舞台上的实例何时创建。
现在假设我运行这段代码:
mc.gotoAndPlay("on");
var inst_mc:MovieClip = mc.inst;
if (inst_mc)
trace("inst_mc found!");
else
trace("inst_mc NOT FOUND!");
var inst_c:C = C(mc.inst);
if (inst_c)
trace("inst_c found!");
else
trace("inst_c NOT FOUND!");
在当前帧的所有代码执行完毕之前,似乎不会在诸如 C 之类的类下创建任何对象,因为输出将是这样的:
inst_mc found!
inst_c NOT FOUND!
C constructor!
这到底是怎么回事?我已经明确告诉 Flash 创作环境,影片剪辑 C 与 C 类相关联,而 C 类是 MovieClip 派生的。因此,在我的代码中,gotoAndPlay("on") 将创建位于“on”帧上的影片剪辑“inst”。它能够很好地找到实例,但是当我将其视为 C 类时,它会失败。然后构造函数发生在所有这些之后。我该如何解决?我希望一旦您在时间线上更改了某些内容,将立即创建相应的对象——它们确实是,但不是作为它们的显式类类型。我可以引用我的实例,但只能作为 MovieClip。我该怎么解决这个问题?它应该输出:
C constructor!
inst_mc found!
inst_c found!
感谢您的帮助!
* 更新 * 感谢您的回复!不幸的是,我的项目没有简单的修复方法,它现在很大并且不能轻易重组(它也太大而无法转换为 AS3)。我曾考虑将 MC 保留在第 1 帧并隐藏它们,但我认为这会不必要地增加开销。即使 _visible 设置为 false ,是不是还是会消耗资源? (这是一个不同但相关的问题——如果你有一个不可见的复杂、固定的 MC 与根本没有它,性能会有什么不同吗?)
我目前的策略是这样的:
mc.gotoAndPlay("on");
var inst_mc:MovieClip = mc.inst;
var inst_c:C = C(mc.inst);
if (inst_c)
// Even though I moved to the "on" frame,
// the object was already initialized/existed already
// so i can use its class code now
inst_c.do_something_now();
else
// The class is not accessible, so set a boolean flag
// which will get dynamically assigned to the *movie clip*.
// The constructor in class C will look to see if the flag
// has already been set. If so, it calls do_something_now()
// within C's constructor.
// In class C, trigger_do_something_now is a defined as a
// Boolean with no default value.
// It is not set in the constructor.
inst_mc.trigger_do_something_now = true;
这种方法让我很困扰。这是混乱和混乱的。但是,我认为这是一个合理的解决方法。你们有什么感想?谢谢!
【问题讨论】:
【参考方案1】:不幸的是,这就是 AS2 中“面向对象”代码的工作方式。这就是你应该如何可视化它:当时间线播放头在帧 A 上时,并且你调用 gotoAndStop(B)
,播放头会立即前进,并创建任何必要的对象,但你在帧 B 上的任何时间线脚本尚未执行,因为 Flash 仍在完成帧 A 的执行。直到 Flash 内部循环的下一次迭代才处理帧 B。
自从上课只是众所周知的送奶工眼中的闪光的日子以来,事情就是这样。正如您所猜想的那样,对于附加类剪辑,一切都一样 - 当您将播放头移动到帧 B 时,Flash 会在 B 帧上创建所有内容,但它不会运行驻留在 B 帧上的任何脚本 - 这包括构造函数刚刚创建的剪辑 - 直到下一帧。
最简单的解决方法是重新设计您的时间线,以便在第 1 帧中创建有问题的 MC,但在 gotoAndStop 命令之前一直隐藏(或不活动、不在舞台等)。您可以通过在给定帧上的 IDE 中更改其 alpha(等)来做到这一点,或者在执行 gotoAndStop 的同时调用一个 init 方法。 最好的 解决方法是使用 AS3,如果可以的话。您还可以选择其他方法,但我会推荐这两种方法中的一种。
编辑更新: 是的,“您可以采用的其他方法”之一是将参数放入剪辑或其父级中,并让剪辑在初始化时查找它们,但任何最终维护您的代码的人都不会感谢您.但我确实做到了。 ;)
在回答您的附带问题时,带有 _visible=false 的剪辑在舞台范围内会产生非常小的开销。它没有被渲染,但是有一个非常小的命中,我认为这与 Flash 计算它的边界或类似的东西有关。 (我曾经进行过一次测试,你真的需要成千上万的测试才能对其进行测量。)即使这是性能损失也是一个问题,解决方法是将不可见的剪辑移到舞台边界之外。然后,我发现它们不会对处理器造成任何影响,它们只使用脚本内存(如果您延迟它们的初始化直到它们准备好使用,那么内存就很少了)。
请记住,无论剪辑是否可见,事件处理程序都会触发,因此在初始化之前不要让剪辑注册事件。我要做的是使用构造函数中的所有内容创建一个 init() 方法,然后在您本来构造剪辑的地方调用它。
【讨论】:
AS3 并没有让这变得更容易。事实上,我认为使用时间线变得更加困难(没有充分的理由,IMO),因为在您发出 gotoAndPlay 或 gotoAndStop 之后,您甚至无法将实例作为 MovieClip(或 Sprite 或其他)访问.如果你在 AS3 中运行发布的代码,你会得到:inst_mc NOT FOUND!未找到 inst_c! C构造函数!这与语言的对象模型无关,而与 Flash 运行时的工作方式有关。 Juan,这就是 AS3应该 做的,因为 Flash 一次执行一帧,移动播放头并不会改变正在执行的帧。没有人说过您可以从 AS2 移植到 AS3 而无需更改任何内容。但是提问者的问题是,AS2 给了他一个可访问的类对象,它的构造函数还没有被调用,这在一个渴望成为 OO 的平台中是非常误导的。在 AS3 中不会出现这种愚蠢的情况。 fenomas,我明白你的意思。我使用过 AS2 和 AS3,我随时都会选择 AS3。不仅是语言,而且播放器的 API 更好更干净(显示列表,没有更多的无声错误等)。但是,我认为 AS3 让简单的时间线变得更加复杂。尽管这些天我没有做太多时间线的事情,但我相信它有它的位置,在那个特定方面“降级”播放器是一个错误。如果我没记错的话,我认为 Adobe 将这种行为放回 AVM2/FP10 或至少计划这样做(还没有真正检查过,但我记得读过它)。 PS:Adobe 似乎确实将这种行为放回了 FP10。 ***.com/questions/794750/… 感谢大家的详尽回复!我已经用我当前的解决方法更新了帖子。让我知道你的想法。不幸的是,现在将这个大型项目迁移到 AS3 是不可能的......【参考方案2】:首先,让我为只关注这个问题的一个方面表示歉意(在我的 cmets 对 fenomas 的回答中);尽管我已经提出了自己的观点,而且我什至同意将面向对象,或者至少将正式的类语法添加到 AS1 作为事后的想法,称为 AS2——在某些时候,它表明——,我忽略了回答你的实际问题.
重新阅读这个帖子,我认为这一切都归结为“等待一帧”。这是我不得不在 AS2 中多次使用的解决方法,所以我忽略了这里的真正问题似乎很奇怪。
无论如何,您的解决方法可能会奏效,但正如您所说,它很快就会成为维护的噩梦。 Feomas 的选项是另一种有效的解决方法。在这种情况下,如果我可以避免它,我不会那样做,但不是因为性能;相反,因为在您已经布置好很多东西时重新安排很多东西可能是很多工作。
所以,也许您可以尝试一些非常简单的方法,例如:
mc.gotoAndPlay("on");
this.onEnterFrame = function():Void
trace(mc.inst instanceof C);
delete this.onEnterFrame;
;
而且我认为它应该有效。 enterFrame 事件将在您注册后一帧被您的处理程序捕获。此时,您现在移动到的框架已准备就绪,因此您只需清理处理程序并执行您在发出 gotoAndPlay 后通常会执行的操作。
我记得我曾经不得不做一些非常相似的事情(不是完全相同的场景,但归结为等待一帧),所以当时我写了一个非常简单的类来集中这段代码。大致是这样的:
class FrameDelay
function FrameDelay(scope:Object,callback:Function,args:Array)
// get a reference to the current enterFrame handler
// (if any), so we can restore it back when we're done
var oldEnterFrameHandler:Function = _root.onEnterFrame;
_root.onEnterFrame = function():Void
oldEnterFrameHandler();
callback.apply(scope,args);
_root.onEnterFrame = oldEnterFrameHandler;
你会这样使用它:
mc.gotoAndPlay("on");
new FrameDelay(this,onFrameReady,["a","1"]);
function onFrameReady():Void
// arguments (if any), will be available in the arguments array
trace(arguments.length);
trace(mc.inst instanceof C);
trace(this);
你传递一个作用域、一个函数和一个可选的参数数组。最有可能的是,您不需要它们,也可以只让类构造函数进行回调。但在某些情况下,您的回调中可能存在范围问题(这是一个 AS2 问题),因此显式传递范围更安全。
另外,请注意我使用的是 _root.onEnterFrame。虽然我正在对原始处理程序进行“备份”并在完成后将其恢复,但这并不一定意味着代码的其他部分是礼貌的(!)。因此,处理程序可能会被覆盖。如果您认为这可能是一个问题,也许您可以在根目录中动态创建一个movieClip,在您知道它没有被使用的某个深度,并将_root.onEnterFrame 替换为_root.dummy_mc.onEnterFrame。
无论如何,请记住,一个简单的内联 onEnterFrame 就可以完成这项工作,所以也许您甚至不需要为此使用一个类。
【讨论】:
以上是关于在 Actionscript 2 中立即引用影片剪辑类实例的主要内容,如果未能解决你的问题,请参考以下文章
在 flash actionscript 2 中动态访问嵌套的影片剪辑
想要在 Actionscript 2.0 Flash 中生成多个影片剪辑实例