我正在尝试使用ActionScript 3中的“文件”功能来保存以下信息:
我在场景中有不同的可拖动显示对象,数量和类型可以有所不同。我想保存金额和位置,然后在以后的会话中加载它们。
我正在努力使用File来保存任何内容,我搜索了Adobe文档并且无法理解如何使用它。
我还没有使用它开发任何代码。
任何帮助都将不胜感激。
谢谢。
答案 0 :(得分:2)
您正试图直接在文件中写入DisplayObject
,由于Flash处理任何对象的默认序列化的方式,Flash引擎会阻止这种情况。为了将DisplayObject
保存到外部资源中,您需要在该对象的类和您计划存储的任何类对象上使用IExternalizable
。 writeExternal
的实施应保存从头开始重建所述对象所需的所有数据,readExternal
还应采用方法通过执行DisplayObject
来恢复所述addChild()
的完整性嵌套显示对象,或将它们添加到对象可能包含的其他内部结构中。
注意,其他答案包含使用XML或JSON进行自定义序列化的有效点,并且还包含要求导入的链接,特别是,flash.utils.registerClassAlias
和flash.utils.getDefinitionByName
非常需要从中重新创建结构一个序列化的数据块。
一个例子:假设你在Board
类中有一个绘图板,以及一组可以使用鼠标拖动的矩形,它们的大小和颜色不同。矩形是自定义MovieClip
s并且没有自己的类,但每个MovieClip
也分配了color
属性以简化它们的区别。这意味着您只需要在IExternalizable
课程上实施Board
。我们还假设Board
类有一个pieces
数组,其中包含嵌套矩形的所有链接,以及根据作为参数提供的宽度,高度和颜色创建新的正确大小的矩形的方法。 (Board
的数据结构可能有更多要求在您的情况下满足,所以仔细观察)因此,序列化Board
的过程将是从嵌套的MC收集所有数据并填充它为了提供IDataOutput
,恢复Board
实例的过程应检索存储的数据,解析它以查找其中的内容,创建嵌套的MC,就像它们已存储一样,正确定位它们,addChild() to self and rebuild the
件阵列。
public class Board extends Sprite implements IExternalizable {
private var pieces:Array;
public function createRectangle(_width:Number,_height:Number,color:uint):MovieClip {
var mc:MovieClip=new MovieClip();
mc.graphics.beginFill(color);
mc.graphics.drawRect(0,0,_width,_height);
mc.graphics.endFill();
mc.color=color;
pieces.push(mc);
return mc;
}
对数据结构的改进已经可见 - 您需要将传递的_width
和_height
存储在某个地方的MC中,因为该MC的实际width
将与传递的内容不同按默认线条粗细(两侧各为0.5)。但是,可以从MC的属性中正确检索x
和y
。因此,必须在createRectangle
中添加两行。
mc._width=_width;
mc._height=_height;
有了这个,序列化Board
变得更加容易。
public function writeExternal(output:IDataOutput):void {
var pl:int=pieces.length; // cache
output.writeInt(pl); // assuming we keep this array in integral state
for (var i:int=0;i<pl;i++) {
var _mc:MovieClip=pieces[i];
output.writeDouble(_mc.x); // this is usually not rounded when dragging, so saving as double
output.writeDouble(_mc.y);
output.writeDouble(_mc._width);
output.writeDouble(_mc._height);
output.writeInt(_mc._color);
}
// if anything is left about the "Board" itself, write it here
// I'm assuming nothing is required to save
}
要恢复,您需要以IDataInput
中的writeExternal
读取数据的顺序与<{1}}中的数据完全相同,然后处理以重建显示列表已存储。
public function readExternal(input:IDataInput):void {
// by the time this is called, the constructor has been processed
// so "pieces" should already be an instantiated variable (empty array)
var l:int;
var _x:Number;
var _y:Number;
var _width:Number;
var _height:Number;
var _color:uint;
// ^ these are buffers to read data to. We don't yet have objects to read these into
input.readInt(l); // get pieces length
for (var i:int=0;i<l;i++) {
input.readDouble(_x);
input.readDouble(_y);
input.readDouble(_width);
input.readDouble(_height);
input.readInt(_color);
// okay we got all the data representing the rectangle, now make one
var mc:MovieClip=createRectangle(_width,_height,_color);
mc.x=_x;
mc.y=_y;
addChild(mc); // createRectangle does NOT have addchild call
// probably because there are layers for the parts to be added to
// I'm assuming there are no layers here, but you might have some!
// pieces array is populated inside createRectangle, so we leave it alone
}
// read all the data you have stored after storing pieces
}
如果您的嵌套MC有一个也实现IExternalizable
的类,您可以将整个数组保存在一条指令writeObject(pieces)
中,这将使Flash遍历数组,查找所有数据包含并在任何嵌套对象上调用writeObject
,实质上是为数组中的每个实例调用该类的writeExternal
函数。恢复这样的数组应该包括通过遍历数组并在每个恢复的实例上调用addChild()
来重建显示列表。
最后但并非最不重要的是,在对自定义对象进行任何序列化或反序列化之前,应调用registerClassAlias()
。调用它们的最佳位置可能是你的主要对象的构造函数,因为在你的应用程序包含的任何其他代码之前肯定会调用它。
答案 1 :(得分:1)
假设您要保存的所有对象属于同一个父级,您可以按照以下方式执行操作:
首先,创建一个类文件(让我们调用SaveData.as
并将其放在项目目录的根目录中)。这将描述您要保存的数据:
package
{
import flash.geom.Rectangle;
public class SaveData
{
public var bounds:Rectangle; //to save where an object is on the stage
public var classType:Class; //to save what kind of object it is
//you could add in more proterties, like rotation etc
public function SaveData() {
}
}
}
接下来,在保存功能上,执行以下操作:
//this will hold all your data
//a vector is the same as an array only all members must be of the specified type
var itemList:Vector.<SaveData> = new Vector.<SaveData>();
//populate the array/vector with all the children of itemContainer
var tmpItem:SaveData;
//loop through all children of item container
for (var i:int = 0; i < itemContainer.numChildren; i++) {
tmpItem = new SaveData(); //create a new save record for this object
tmpItem.bounds = itemContainer.getChildAt(i).getBounds(itemContainer); //save it's bounds
tmpItem.classType = getDefinitionByName(itemContainer.getChildAt(i)) as Class; //save it's type
itemList.push(tmpItem); //add it to the array
}
//Now you have an array describing all the item on screen
//to automatically serialize/unserialize, you need this line (and you need to register every class nested in SaveData that isn't a primitive type - which would just be Rectangle in this case
registerClassAlias("SaveData", SaveData);
registerClassAlias("flash.geom.Rectangle", Rectangle);
//create a new File to work with
var file:File = File.applicationStorageDirectory; //or whatever directory you want
file.resolvePath("saveData.data"); //or whatever you want to call it
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeObject(itemList); //write the array to this file
fileStream.close();
现在,将其加载回来:
var itemContainer:Sprite = new Sprite(); //however you initialize this
addChild(itemContainer);
var file:File = File.applicationStorageDirectory;
file.resolvePath("saveData.data");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var itemList:Vector.<SaveData> = fileStream.readObject() as Vector.<SaveData>;
fileStream.close();
//now that you've read in the array of all items from before, you need to recreate them:
var tmpItem:DisplayObject;
var tmpClass:Class;
//loop through all items in the array, and create a object
for (var i:int = 0; i < itemList.length; i++) {
tmpClass = itemList[i].classType; //The type of item
tmpItem = new tmpClass() as DisplayObject; //create the item
//now move the item to it's former position and scale
tmpItem.x = itemList[i].x;
tmpItem.y = itemList[i].y;
tmpItem.width = itemList[i].width;
tmpItem.height = itemList[i].height;
//add the item back to the parent
itemContainer.addChild(tmpItem);
}
如果您不确定进口商品,请点击此处:
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.registerClassAlias;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
答案 2 :(得分:0)
var bytes:ByteStream;
var filename:String = "mySaveFile.sav";
//[...] //initialize byte stream with your data
//get a reference to where you want to save the file
//(in this example, in the application storage directory,
//which is fine if you don't need to move the save file between computers
var outFile:File = File.applicationStorageDirectory;
outFile = outFile.resolvePath(fileName);
//create a file output stream, which writes the byte stream to the file
var outStream:FileStream = new FileStream();
outStream.open(outFile, FileMode.WRITE);
outStream.writeBytes(bytes, 0, bytes.length);
outStream.close();
//to load the file:
var inFile:File = File.applicationStorageDirectory;
inFile = inFile.resolvePath(fileName);
bytes = new ByteArray();
var inStream:FileStream = new FileStream();
inStream.open(inFile, FileMode.READ);
inStream.readBytes(bytes);
inStream.close();
答案 3 :(得分:0)
我通常使用SharedObject,通过将对象的位置,比例,旋转等等数量保存为数组(通常是多维数组)。
测试了此示例:
首先制作一个影片剪辑,在动作脚本链接中将其命名为“mc” 添加你喜欢的任何图形 (此MovieClip将是以后保存的对象) 然后添加以下脚本
////////// get random values for each object
var speed:Number ;
var yPosition:Number ;
var size:Number ;
this.width = size;
this.height = size;
this.y = yPosition ;
//// Moving the MovieClip from Left to right
function moving(e:Event):void
{
this.x += speed ;
if(this.x > 550)
{
this.removeEventListener(Event.ENTER_FRAME,moving);
MovieClip(parent).removeChild(this);
}
}
this.addEventListener(Event.ENTER_FRAME,moving);
在项目的根阶段添加:
import flash.events.MouseEvent;
import flash.display.MovieClip;
var num:int = 0 ;
var mmc:MovieClip ;
var mySharedObj:SharedObject = SharedObject.getLocal("SavingStatus"); //// SharedObject to save info
function init()
{
if (!mySharedObj.data.savedArray)
{
///// first run No datat saved
this.addEventListener(Event.ENTER_FRAME,addingmcs)
}else {
///// Laoding previusly saved data
loading();
}
}
init() ;
/////////////// adding MovieClips to stage /////
function addingmcs(e:Event):void
{
num +=1 ;
if(num > 20){
num = 0 ;
mmc = new mc ;
mmc.speed = 2 + (5 * Math.random()) ;
mmc.yPosition = 500 * Math.random() ;
mmc.size = 50 + 10 * Math.random() ;
this.addChild(mmc);
}
}
///////////////////////////////////////////
///////////////////////////////////////////////
var obj:* ; //// to hold children MovieClips of the stage
var savingArr:Array = new Array ; //// the array to be saved , Contains all info of the children
////////////// Save all MovieClips with their parameters ////////////
function saving(e:MouseEvent):void
{
this.removeEventListener(Event.ENTER_FRAME,addingmcs)
for (var i:int=0;i<this.numChildren;i++)
{
if (this.getChildAt(i)is MovieClip) { ///// add all MovieClips of the stage to the array with their info (position - size - speed ... etc)
obj = this.getChildAt(i);
savingArr.push([obj , obj.x , obj.y , obj.speed , obj.size]); //// add the info in 3 dimentional array
obj.speed = 0 ;
}
}
////////////////saving array externally
mySharedObj.data.savedArray = savingArr ;
mySharedObj.flush ();
}
save_btn.addEventListener(MouseEvent.CLICK,saving)
////////////// Load all saved parameters ////////////
load_btn.addEventListener(MouseEvent.CLICK,loading)
function loading(e:MouseEvent =null):void
{
savingArr = mySharedObj.data.savedArray ;
for (var i:int=0;i<savingArr.length ; i++)
{
mmc = new mc ;
mmc.x = savingArr[i][1] ; ///// Get saved x
mmc.yPosition = savingArr[i][2] ; ///// Get saved y
mmc.speed = savingArr[i][3] ; ///// Get saved speed
mmc.size = savingArr[i][4] ; ///// Get saved size
addChild(mmc);
}
this.addEventListener(Event.ENTER_FRAME,addingmcs) ;
}
答案 4 :(得分:0)
你已经有了一些答案,但是根据你的问题,也许你错过了更大的背景。
因此File
类表示磁盘上文件的路径,FileStream
类允许读取和写入该文件的数据。这些都很容易使用,网上有很多例子。以下是Adobe的一个教程:Reading and writing files
但是要写什么数据以及格式和数据类型是什么?这些是更重要,更有趣的问题。
最简单的方法是使用基于text
的格式,如XML
或JSON
,您可以在其中读取和写入所需的Sprites
(或其他对象)属性。这样做的一个优点是生成的文件是人类可读/可编辑的文本文件。一个小缺点是您需要指定要保存和恢复的属性,并处理简单的数据类型转换(字符串到int等)。
更强大的方法是使用所谓的Serialization
,其中保存和恢复整个对象的状态。这更复杂,虽然不是很难,但对于您的项目需求来说可能有点过头了。有很好的例子和讨论here,here和here。
对于您当前的项目和技能级别,我建议您使用XML
或JSON
这是使用XML的教程:Loading and Processing External XML Files