如何在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!
这有什么不妥?(如果不是 - 为什么?是不是应该可以复制的内存区域表示的显示对象,就像任何其他对象一样?)
你不能原生地复制大多数内部类,但你可能想要查看IExternalizable(http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/utils/IExternalizable.html)
它是序列化AMF内部使用的对象的方法.它强制您的对象创建两个方法,readExternal和writeExternal.想法是writeExternal允许您在ByteArray中打包对象内部状态,然后创建类的新实例,AMF将该ByteArray传递给readExternal方法,您可以在其中重新创建以前的对象内部状态手.调用方法和实例化都是通过ObjectUtil.copy()方法完成的(http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/utils/ObjectUtil.html?filter_flex如果您使用的是Flex SDK,则= 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.):void
(http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html#drawGraphicsData())
如果要将所有命令存储为原始数据(甚至是JSON,或创建内部DTO),则编写IExternalizable方法将命令复制到新Object并使用此方法重新填充Graphics.这将是一个痛苦的写,但意味着你只需要调用copy()方法,你有一个副本,图形和所有,在copy()方法中没有任何自定义代码.您还可以根据命令动态调用图形方法,因此如果需要,您可以在FP9中使用它.这有额外的好处,允许您更改当前不可能的命令.一旦你写了图形,你就会坚持下去.
简短回答:
图形在运行时不是内省的.无论Kirupa的代码在做什么,它都无法知道你绘制的是什么形状,也无法复制或重新绘制它.(文本字段被遗漏可能是一个错误或设计,我不知道,但没有绕过形状.)
答案很长:
DisplayObject不仅仅是一块内存,比如位图或字符串.它是一个对象,具有许多子属性,其中许多也是对象,函数或类等.所以当你说你想要复制一个时,值得问一下究竟是什么意思.子对象(例如Arrays)是应该通过引用复制还是复制?如果任何对象持有对其他显示对象的引用,除了它们的子项列表之外,您如何知道是复制引用还是复制目标?如果某些原始对象正在侦听键盘事件或运行计时器,那么复制品是否可以在不进行注册的情况下工作?等等,等等.
所有这些都是一种冗长的说法,在OOP语言(如AS3)中,没有普遍有意义的方法来复制对象.当然,你可以通过MovieClip树递归,创建新的并试图将属性从原件复制到重复 - 这就是Kirupa的代码可能正在做的事情.但是对于除了琐碎的内容之外的任何事情,正如你所发现的那样,这不会得到你想要的东西.这就是为什么没有内置的方法来做到这一点 - 因为大多数时候它不会做人们所希望的.
最终,这类问题的真正解决方案是仔细研究需要完成的工作,并找到一种方法来实现它而不会复制对象.如果只需要原始的可视副本,则可以考虑每帧将原始图形绘制到位图中.或者最好的方法是构建一个包含与对象相关的所有信息的数据结构,以便您可以复制数据并基于它初始化对象.或许您应该最初创建一个对象池,并维护每个对象,以便在以后需要重复时使用它们.
无论哪种方式,在一天结束时问题是架构,所以解决方案也需要.