AS3:无法复制带有内容的DisplayObjects?

时间:2010-10-12 09:26:32

标签: flash actionscript-3 object copy

如何在AS3中保留其内容(图形,添加的显示对象等)的同时复制显示对象(精灵,动画片段等)? Kirupa最常提出的解决方案(http://www.kirupa.com/forum/showpost.php?p=1939827&postcount=172)似乎不会复制任何图形或子显示对象:

// create a sprite
var s:Sprite = new Sprite();
// add a text field
var tf:TextField = new TextField();
tf.text = "nisse";
s.addChild(tf);
// draw something
s.graphics.lineStyle(1, 0x00FF00);
s.graphics.drawCircle(10, 10, 10);
s.x=100;
// add it to parent
this.addChild(s);       

// create a copy using Kirupas duplicate display object solution    
var sCopy:Sprite = duplicateDisplayObject(s, true) as Sprite;
sCopy.x = 200; 
// confirem that the copy exists:
trace(sCopy);
// add to parent
this.addChild(sCopy); // <- works, but the original textfield and graphics are gone!

这有什么不妥? (如果不是 - 为什么?是不是应该可以复制的内存区域表示的显示对象,就像任何其他对象一样?)

5 个答案:

答案 0 :(得分:6)

您无法原生复制大多数内部类,但您可能希望查看IExternalizable(http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/utils/IExternalizable.html

这是序列化AMF内部使用的对象的方法。它强制您的对象创建两个方法,readExternal和writeExternal。想法是writeExternal允许您在ByteArray中打包对象内部状态,然后创建类的新实例,AMF将该ByteArray传递给readExternal方法,您可以在其中重新创建以前的对象内部状态手。如果您正在使用Flex SDK,则通过ObjectUtil.copy()方法(http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/utils/ObjectUtil.html?filter_flex=4.1&filter_flashplayer=10.1&filter_air=2#copy())完成对方法和实例化的调用,否则,复制实现如下:

function copy(value:*):*{
  var buffer:ByteArray = new ByteArray();
  buffer.writeObject(value);
  buffer.position = 0;
  var result:Object = buffer.readObject();
  return result;
}

正如你在这里看到的那样,它只是ByteArray的readObject和writeObject方法实际上进行了序列化,对ObjectUtil类没有实际需要。

您可能还需要为要复制的类注册一个类别名,以便AMF知道要创建的对象,否则您只需从另一端获取通用对象:

registerClassAlias("com.example.ExampleClass", com.example.ExampleClass);

应该注意的是,您不能在构造函数中使用此方法要复制的对象中的必需参数,并且ByteArray的readObject将检查对象以查看它是否实现了IExternalizable,否则它将只复制其公共属性。这就是为什么大多数内置类都无法复制的原因。

从显示对象中复制图形,可以使用几种方法:

从FP 10开始,Graphics还有另一种有用的方法。

public function copyFrom(sourceGraphics:Graphics):void

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html#copyFrom()

因此,一旦复制了对象,就可以手动复制图形。只需将其放入copy()方法即可。只需检查它是否扩展Sprite或MovieClip,然后调用copyFrom()。这将是最容易写的。

这是另一种新方法。

public function drawGraphicsData(graphicsData:Vector.<IGraphicsData>):void

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html#drawGraphicsData()

如果要将所有命令存储为原始数据(甚至是JSON,或创建内部DTO),则编写IExternalizable方法将命令复制到新Object并使用此方法重新填充Graphics。这将是一个痛苦的写,但意味着你只需要调用copy()方法,你有一个副本,图形和所有,在copy()方法中没有任何自定义代码。您还可以根据命令动态调用图形方法,因此如果需要,您可以在FP9中使用它。这有额外的好处,允许您更改当前不可能的命令。一旦你写了图形,你就会坚持下去。

答案 1 :(得分:6)

简答:

图形在运行时是不可内省的。无论Kirupa的代码在做什么,它都无法知道你绘制的是什么形状,也无法复制或重新绘制它。 (文本字段被遗漏可能是一个错误或设计,我不知道,但没有绕过形状。)

答案很长:

DisplayObject不仅仅是一块内存,比如位图或字符串。它是一个对象,具有许多子属性,其中许多也是对象,函数或类等。所以当你说你想要复制一个时,值得问一下究竟是什么意思。子对象(例如Arrays)是应该通过引用复制还是复制?如果任何对象持有对其他显示对象的引用,除了它们的子项列表之外,您如何知道是复制引用还是复制目标?如果某些原始对象正在侦听键盘事件或运行计时器,那么复制品是否可以在不进行注册的情况下工作?等等,等等。

所有这些都是一种冗长的说法,在OOP语言(如AS3)中,没有普遍有意义的方法来复制对象。当然,你可以通过MovieClip树递归,创建新的并试图将属性从原件复制到重复 - 这就是Kirupa的代码可能正在做的事情。但是对于除了琐碎的内容之外的任何事情,正如你所发现的那样,这不会得到你想要的东西。这就是为什么没有内置的方法来做到这一点 - 因为大多数时候它不会做人们所希望的。

最终,这类问题的真正解决方案是仔细研究需要完成的工作,并找到一种方法来实现它而不会复制对象。如果只需要原始的可视副本,则可以考虑每帧将原始图形绘制到位图中。或者最好的方法是构建一个包含与对象相关的所有信息的数据结构,以便您可以复制数据并基于它初始化对象。或许您应该最初创建一个对象池,并维护每个对象,以便在以后需要重复时使用它们。

无论哪种方式,在一天结束时问题是架构问题,因此解决方案也需要。

答案 2 :(得分:2)

那是因为AS3试图成为一种面向对象的语言,而你正在尝试做的事情的OOP方法就是创建一个带有clone方法的类():) 我认为这将是最灵活,无错误且易于阅读的复制对象的方式。

答案 3 :(得分:1)

您无法制作精确副本,但可以轻松创建代理位图。这在大多数情况下对我有用(填充,缩略图等)

参见BitmapData的draw()方法。

答案 4 :(得分:0)

var newObject:DisplayObject;
newObject = originalObject;

addChild(newObject);

我就是这样做的。它适用于所有类型的显示对象(mc,sprite,textField等)