actionscript 3 - programar - Usando ''Archivo'' para guardar las ubicaciones de objetos de escenas para reconstruir más tarde en AS3
comandos de actionscript (5)
Está intentando escribir un objeto DisplayObject
en el archivo directamente, esto es impedido por el motor Flash debido a la forma en que Flash maneja la serialización predeterminada de cualquier objeto. Para guardar un DisplayObject
en el recurso externo, necesita emplear IExternalizable
en la clase de ese objeto y cualquier clase de objetos que planee almacenar también. La implementación de writeExternal
debe guardar todos los datos necesarios para reconstruir dicho objeto desde cero, y readExternal
también debe emplear métodos para restaurar la integridad de dicho DisplayObject
al realizar addChild()
en objetos de visualización anidados, o agregarlos a otras estructuras internas que el objeto podría Contiene.
Tenga en cuenta que otras respuestas contienen puntos válidos para realizar una serialización personalizada con XML o JSON, y también contienen enlaces que requieren importación, en particular, flash.utils.registerClassAlias
y flash.utils.getDefinitionByName
son muy necesarios para recrear la estructura a partir de datos serializados. pedazo.
Un ejemplo: digamos que tiene un tablero de dibujo en una clase de Board
y un conjunto de rectángulos que puede arrastrar con el mouse, que difieren en tamaño y color. Los rectángulos son MovieClip
personalizados y no tienen una clase propia, pero a cada MovieClip
también se le asigna una propiedad de color
para simplificar su distinción. Esto significa que debe implementar IExternalizable
en la clase Board
solamente. Supongamos también que la clase Board
tiene una matriz de pieces
que contiene todos los enlaces a rectángulos anidados, y un método para crear un nuevo rectángulo de tamaño adecuado en función del ancho, la altura y el color proporcionados como parámetros. (Puede haber más requisitos para que la estructura de datos de la Board
reúna en su caso, así que tenga cuidado). Por lo tanto, el proceso de serialización de la Board
consistirá en recopilar todos los datos de los MC anidados y IDataOutput
en orden en IDataOutput
suministrado, y el El proceso de restauración de una instancia de la Board
debería recuperar los datos almacenados, analizarlos para encontrar qué es lo que está, crear los MC anidados para que sean los mismos que se almacenaron, colocarlos correctamente, addChild() to self and rebuild the
matriz de piezas. .
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;
}
Ya está visible un refinamiento de la estructura de datos: necesita almacenar el _width
y la _height
_width
_height
en el MC en alguna parte, porque el width
real de ese MC diferirá de lo que pasa con el espesor de línea predeterminado (1, 0.5 en cada lado). y
se recuperan correctamente de las propiedades de MC, sin embargo. Por lo tanto, es necesario agregar ambas líneas en createRectangle
.
mc._width=_width;
mc._height=_height;
Con esto, serializar la Board
vuelve más fácil.
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
}
Para restaurar, necesita leer los datos de IDataInput
en el mismo orden en que fue escrito en writeExternal
y luego procesar para reconstruir la lista de visualización que hemos almacenado.
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
}
En caso de que sus MC anidados tengan una clase que también implemente IExternalizable
, puede guardar toda la matriz en una sola instrucción, writeObject(pieces)
, esto hará que Flash recorra la matriz, encuentre todos los datos que contiene y llame a writeObject
en cualquier objeto anidado , llamando esencialmente a la función writeExternal
esa clase para cada una de las instancias de la matriz. La restauración de dicha matriz debe incluir la reconstrucción de la lista de visualización recorriendo la matriz y llamando a addChild()
en cada una de las instancias restauradas.
Y por último pero no menos importante, se debe llamar a registerClassAlias()
antes de hacer cualquier serialización o deserialización de objetos personalizados. El mejor lugar para llamar a estos es probablemente el constructor de su objeto principal, ya que seguramente se llamará antes que cualquier otro código que contenga su aplicación.
Estoy intentando usar la función ''Archivo'' en ActionScript 3 para guardar la siguiente información:
Tengo diferentes objetos de visualización arrastrables en la escena, la cantidad y el tipo pueden variar. Quiero guardar la cantidad y su posición y luego volver a cargarlos en una sesión futura.
Estoy luchando por usar File para guardar cualquier cosa, he buscado en la documentación de Adobe y no puedo entender cómo usarlo.
Todavía no he desarrollado ningún código que lo use.
Cualquier ayuda sería apreciada.
Gracias.
Suponiendo que todos sus objetos para guardar pertenecen al mismo padre, podría hacer algo en esta línea:
Primero, cree un archivo de clase (llamemos a SaveData.as
y póngalo en la raíz del directorio de su proyecto). Esto describirá los datos que quiere guardar:
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() {
}
}
}
A continuación, en su función de guardar, haga algo como esto:
//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();
Ahora, para volver a cargarlo:
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);
}
Si no está seguro de las importaciones, aquí están:
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.registerClassAlias;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
Usualmente uso SharedObject, al guardar el número de objetos con sus ubicaciones, escala, rotación, etc., como una matriz (generalmente una matriz multidimensional).
este ejemplo está probado:
primero haga un clip de película dándole "mc" como nombre en el Enlace de ActionScript agregue los gráficos que desee (este MovieClip será los objetos que se guardarán más adelante) y luego agregue el siguiente script
////////// 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);
en la etapa raíz del proyecto, agregue:
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) ;
}
Ya tiene algunas respuestas aquí, pero a partir de su pregunta, tal vez le falta el contexto más amplio.
Entonces la clase File
representa una ruta a un archivo en el disco y la clase FileStream
permite leer y escribir datos en ese archivo. Estos son fáciles de usar y hay muchos ejemplos en la web. Aquí hay un tutorial de Adobe: Lectura y escritura de archivos
Pero, ¿qué datos escribir y cuál es el formato y el tipo de datos? Esas son las preguntas más importantes y más interesantes.
El enfoque más simple es usar un formato basado en text
como XML
o JSON
donde usted lee y escribe las propiedades de Sprites
(u otros objetos) que desee. Una ventaja de esto es que el archivo resultante es un archivo de texto legible / editable humano. Una desventaja menor es que debe especificar qué propiedades guardar y restaurar, y tratar con las conversiones simples de tipo de datos (cadena a int, etc.).
Un enfoque más robusto es usar lo que se llama Serialization
donde se guarda y restaura el estado de un objeto completo. Esto es más complicado y, aunque no es difícil, es probablemente excesivo para las necesidades de su proyecto. Hay buenos ejemplos y discusiones aquí , aquí y aquí .
Para su proyecto actual y nivel de habilidad, le sugiero usar XML
o JSON
Aquí hay un tutorial usando XML: carga y procesamiento de archivos XML externos
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();