actionscript 3 - استخدام "ملف" لحفظ مواقع كائنات المشهد لإعادة البناء لاحقا في AS3




actionscript-3 flash (4)

على افتراض أن كل ما تبذلونه من الأشياء لحفظ تنتمي إلى نفس الوالد، هل يمكن دوسوميثينغ على طول هذه الخطوط:

أولا، إنشاء ملف فئة (دعنا ندعو 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;

أنا أحاول استخدام وظيفة "ملف" في أكتيونسكريبت 3 لحفظ المعلومات التالية:

لدي كائنات عرض قابلة للسحب متفاوتة في المشهد، وكمية ونوع يمكن أن تختلف. أريد أن حفظ المبلغ وموقفهم ومن ثم تحميلها مرة أخرى في جلسة مقبلة.

أنا تكافح لاستخدام ملف لحفظ أي شيء، لقد بحثت وثائق أدوبي ولا يمكن الحصول على رأسي جولة كيفية استخدامها.

لم أكن قد وضعت بعد أي رمز استخدامه.

سيكون موضع تقدير أي مساعدة.

شكرا لكم.


كنت تحاول كتابة DisplayObject في الملف مباشرة، وهذا منعت من قبل محرك فلاش بسبب الطريقة فلاش يعالج التسلسل الافتراضي لأي كائن. من أجل حفظ DisplayObject في المورد الخارجي، تحتاج إلى توظيف IExternalizable على فئة هذا الكائن وأي فئة من الكائنات سوف تخطط لتخزين كذلك. يجب أن writeExternal تنفيذ writeExternal حفظ كافة البيانات المطلوبة لإعادة بناء الكائن المذكور من الصفر، و readExternal يجب أن توظف أيضا أساليب لاستعادة سلامة addChild() عن طريق أداء addChild() على كائنات العرض المتداخلة أو إضافتها إلى الهياكل الداخلية الأخرى التي الكائن قد يحتوي.

ملاحظة، إجابات أخرى تحتوي على نقاط صالحة للقيام تسلسل مخصص مع شمل أو جسون، وتحتوي أيضا على روابط يتطلب استيراد، على وجه الخصوص، flash.utils.registerClassAlias و flash.utils.getDefinitionByName هي بحاجة ماسة لإعادة بنية من البيانات المتسلسلة قطعة.

مثال: لنفترض أن لديك لوحة رسم في فئة Board ، ومجموعة من المستطيلات التي يمكنك سحبها باستخدام الماوس، والتي تختلف حسب الحجم واللون. المستطيلات هي العرف MovieClip s وليس لديهم فئة خاصة بهم، ولكن يتم تعيين كل MovieClip أيضا خاصية color لتبسيط التمييز بينهما. وهذا يعني أنك تحتاج إلى تنفيذ IExternalizable على Board الطبقة فقط. لنفترض أيضا أن فئة Board تحتوي على صفيف pieces يحتوي على كافة الروابط إلى مستطيلات متداخلة، وطريقة لإنشاء مستطيل جديد بحجم صحيح استنادا إلى العرض والارتفاع واللون الموفر كمعلمات. (قد يكون هناك المزيد من المتطلبات لهيكل بيانات Board للقاء في قضيتك، لذلك مشاهدة عن كثب) لذلك، فإن عملية تسلسل Board يكون لجمع كل البيانات من مكس المتداخلة والأشياء من أجل IDataOutput الموردة، و عملية استعادة مثيل Board يجب استرداد البيانات المخزنة، تحليله للعثور على ما هو المكان، إنشاء مكس متداخلة أن تكون هي نفسها كما تم تخزينها، ووضعها بشكل صحيح، 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 في ماك في مكان ما، لأن width الفعلي لهذا ماك سوف تختلف عن ما تم تمريره من قبل سمك الخط الافتراضي (1، 0.5 على جانبي). 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 ومن ثم عملية لإعادة بناء قائمة العرض قمنا بتخزينها.

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
}

في حالة ماك المتداخلة لديك فئة التي تقوم أيضا بتنفيذ IExternalizable ، يمكنك حفظ مجموعة كاملة في تعليمات واحدة، writeObject(pieces) ، وهذا سيجعل فلاش المشي من خلال صفيف، والعثور على كافة البيانات التي تحتوي عليها وندعو writeObject على أي كائن متداخلة ، داعيا بشكل أساسي إلى writeExternal الدالة writeExternal لكل من المثال في المصفوفة. يجب أن يتضمن استعادة هذه المصفوفة إعادة بناء قائمة العرض من خلال السير في الصفيف واستدعاء addChild() على كل من الحالات المستعادة.

وأخيرا وليس آخرا، يجب أن registerClassAlias() قبل القيام بأي تسلسل أو إزالة تسلسل الكائنات المخصصة. أفضل مكان لاستدعاء هذه هي على الارجح منشئ الكائن الرئيسي الخاص بك، وهذا بالتأكيد سيتم استدعاؤها قبل أي رمز آخر يحتوي التطبيق الخاص بك.


وعادة ما تستخدم شاردوبجيكت، عن طريق حفظ عدد الكائنات مع مواقعها، والحجم، والتناوب، .. الخ كمصفيف (عادة مجموعة متعددة الأبعاد).

يتم اختبار هذا المثال:

أولا جعل مقطع الفيلم يعطيها "ماك" كاسم في أكتيونسكريبت رابط إضافة أي الرسومات التي تريدها (وهذا موفيكليب ستكون الكائنات ليتم حفظها في وقت لاحق) ثم إضافة البرنامج النصي التالي

////////// 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) ;
}

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();