使用“文件”保存场景对象位置,以便稍后在AS3中重建

时间:2015-05-08 13:35:32

标签: actionscript-3 flash actionscript air state

我正在尝试使用ActionScript 3中的“文件”功能来保存以下信息:

我在场景中有不同的可拖动显示对象,数量和类型可以有所不同。我想保存金额和位置,然后在以后的会话中加载它们。

我正在努力使用File来保存任何内容,我搜索了Adobe文档并且无法理解如何使用它。

我还没有使用它开发任何代码。

任何帮助都将不胜感激。

谢谢。

5 个答案:

答案 0 :(得分:2)

您正试图直接在文件中写入DisplayObject,由于Flash处理任何对象的默认序列化的方式,Flash引擎会阻止这种情况。为了将DisplayObject保存到外部资源中,您需要在该对象的类和您计划存储的任何类对象上使用IExternalizablewriteExternal的实施应保存从头开始重建所述对象所需的所有数据,readExternal还应采用方法通过执行DisplayObject来恢复所述addChild()的完整性嵌套显示对象,或将它们添加到对象可能包含的其他内部结构中。

注意,其他答案包含使用XML或JSON进行自定义序列化的有效点,并且还包含要求导入的链接,特别是,flash.utils.registerClassAliasflash.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的属性中正确检索xy。因此,必须在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的格式,如XMLJSON,您可以在其中读取和写入所需的Sprites(或其他对象)属性。这样做的一个优点是生成的文件是人类可读/可编辑的文本文件。一个小缺点是您需要指定要保存和恢复的属性,并处理简单的数据类型转换(字符串到int等)。

更强大的方法是使用所谓的Serialization,其中保存和恢复整个对象的状态。这更复杂,虽然不是很难,但对于您的项目需求来说可能有点过头了。有很好的例子和讨论hereherehere

对于您当前的项目和技能级别,我建议您使用XMLJSON这是使用XML的教程:Loading and Processing External XML Files