Monday, February 7, 2011

Side Project: Loading and Saving local files

For a side project I'm working on, I need to make a map editor, since my data will be structured in a way that's not really convenient when using DAME or whatever. That, and it's a good learning experience.
In any case, I need to be able to load and save .xml files that are stored locally on my harddrive. Apparently, this used to be a huge pain in the neck to do with Flash, and I should probably be doing this sort of project in AIR anyway, but it turns out there's a fairly way to do this.
NOTE: You have to be using Flash Player 10 for this to work.

 If you've been following along with Project Jumper, a lot of this stuff is going to look unfamiliar. This is working in native ActionScript, there's no comfortable shell of flixel to protect us.


package com.chipacabra.Mapedit 
{
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.net.FileReference;
    import flash.utils.ByteArray;
    import org.flixel.FlxState;
    
    /**
     * ...
     * @author David Bell
     */
    public class EditorState extends FlxState 
    {
        protected var _mapXML:XML;
        
        private var fr:FileReference;  
        
        override public function create():void 
        {
            super.create();

            //saveXML();  // I can uncomment one of these to make sure that it's working
           // loadXML();  // but in reality I'd call these functions from something like a button click
        }
        
        override public function update():void 
        {
            super.update();
        }
        
        private function loadXML():void
        {
            fr = new FileReference();
            // Tell Flash to watch for a SELECT event, then call onSelect when it does
            fr.addEventListener(Event.SELECT, onSelect); 
            fr.browse();  // this opens the file browser, then throws out a SELECT event when it does
        }
        private function onSelect(e:Event):void
        {
            fr.addEventListener(Event.COMPLETE, onLoad);
            fr.load();
        }
        
        private function onLoad(e:Event):void
        {
            _mapXML = new XML(e.target.data);
            trace(_mapXML);
        }
        private function saveXML():void
        {
            var ba:ByteArray = new ByteArray();
            ba.writeUTFBytes(_mapXML);
            fr=new FileReference();
            fr.addEventListener(Event.SELECT, _onSaveSelect);
            fr.addEventListener(Event.CANCEL, _onSaveCancel);
            
            fr.save(ba, "filename.xml");
        }
        // These callback functions are placeholders, they can be used to tell the program if the file was actually saved or not
        private function _onSaveSelect(e:Event):void  
        {
            trace('save select');
        }
        private function _onLoadCancel(e:Event):void
        {
            trace('save cancel');
        }
    }
}
Saving a file is actually the more straightforward process, for some reason. All you have to do is turn your XML object into a ByteArray with ByteArray.writeUTFBytes()  and then use FileReference.save() to write the file.

Loading a file is a little more complex, and you have to do it in a couple steps. First, you have to use FileReference.browse(), which will pop up a file dialog for the user to choose a file to load. The program will just keep on running while that window is up, though, so you have to be able to tell it when it's done. That's what the FileReference.addEventListener() thing is for. You tell it to watch out for a particular kind of event, and to execute a particular callback function when that event happens. So once the user has browsed to the file he wants to load, a SELECT event happens and we can move on to onSelect.

In onSelect, we actually load the file into the FileReference. Again, Flash will just keep on doing its thing while the file is loading, so if we try to write it to our XML object right away, we might have problems. So we wait until it's done loading, and move on to onLoad.

onLoad is where we finally put the data into our XML object. The thing about callback functions is that all you really have to work with is the Event. e.target is whatever object called addEventListener. Since we ran fr.addEventListener, that means e.target is referring to fr. FileReference.data is the information we want, so all together e.target.data means the data on our FileReference fr. Phew.

No comments:

Post a Comment