R.R.Karter Editor

by Cheshir forked from alone in a cave (diff: 656)
♥0 | Line 464 | Modified 2015-01-16 22:30:19 | MIT License | (replaced)
play

ActionScript3 source code

/**
 * Copyright Cheshir ( http://wonderfl.net/user/Cheshir )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/wbMq
 */

// Если это похоже на FTL, то это потому, что FTL мне нравится.
// If this sounds like FTL, then it's because I like FTL.
package {
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
    import flash.display.Shape;
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import flash.geom.Point;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.events.Event;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextField;
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        private static var tracetext:TextField = new TextField();
        
        private var load:MyLoader;
        private var externalData:Array = ['Rojer.png','spaceTruck1.png','spTrIns1.png','simpleDoor.png','armoredDoor.png']; // думаю здесь я пожалуй укажу .xml а внутри уже контент уровня
        
        private var mapHolder:Sprite;    // Здесь я буду собирать новые уровни и сюда буду загружать старые
                
        public function FlashTest() {
            // write as3 code here...
            drawBack();
            tracetext.textColor = 0xf0fff0;
            
            mapHolder = new Sprite();
            addChild(mapHolder);
            
            load = new MyLoader(stage);    // Создаем мульти загрузчик
            load.addEventListener(MyLoader.ALL_LOADED, initApp);    // Ожидаем пока загрузится пакет
            load.loadAll(externalData);    // Загружаем массив данных
            // It is not finished ! --- December 23, 2014
                  
            tracetext.autoSize = TextFieldAutoSize.LEFT;    // Просто текст для дебага
            tracetext.y = 330;
            stage.addChild(tracetext);
            
            //stage.addEventListener(MouseEvent.MOUSE_DOWN, stDr);
            //stage.addEventListener(MouseEvent.MOUSE_UP, spDr);
        }
        private function stDr(e:MouseEvent):void{mapHolder.startDrag();}
        private function spDr(e:MouseEvent):void{mapHolder.stopDrag();}
        
        private function initApp(e:Event):void {
            // после загрузки всего контента выполняется эта функция...
            var model:Model = new Model();
            var controll:Controller = new Controller(model);
            // по идее модель и контроллеры можно создавать и раньше, но представление только теперь.
            var view:View = new View(model, controll, stage);
            
            stage.addChild(tracetext);    // replace after view...
            
            var ship:TileClip = new TileClip(471,509,load.loaded_D['spaceTruck1.png']);
            ship.x = -16; ship.y = -11;
            ship.nameTile = 'spaceTruck1.png';
            var inside:TileClip = new TileClip(328,168,load.loaded_D['spTrIns1.png']);
            inside.x = 28; inside.y = 156; //inside.alpha = 0.3;
            inside.nameTile = 'spTrIns.png';
            var player:TileClip = new TileClip(32,32,load.loaded_D['Rojer.png']);
            player.x = 192; player.y = 160;
            player.frameDelay = [40,30];
            player.nameTile = 'Rojer.png';
            
            // Взаимодействие с запертыми дверями ( вскрыть-интелект, выломать-сила, открыть-ключ/кнопка )
            var doorSimple:TileClip = new TileClip(23,6,load.loaded_D['armoredDoor.png']);
            var testDoor:Door = new Door(doorSimple);
            testDoor.x = 209; testDoor.y = 224;
            
            mapHolder.addChild(ship);
            mapHolder.addChild(inside);
            mapHolder.addChild(player);
            mapHolder.addChild(testDoor);
            
            var levelCr:LevelCreator = new LevelCreator(mapHolder);    // Передадим держатель карты, чтобы распарсить его потом и сохранить XML
        }
        
        private static var numLog:Number = 0;
        public static function log(v:Object):void{
            numLog++;
            if(numLog%5 == 0){
                tracetext.text = '';
            }
            tracetext.appendText('\n'+v.toString());
        }
        
        private var stars:Shape;
        private function drawBack():void{
            this.graphics.beginFill(0x222233);
            this.graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight);
            this.graphics.endFill();
            stars = new Shape();
            stars.filters = [new GlowFilter(Math.random()*0xffffff+0xcccccc)];
            for(var i:int = 0; i<300; i++){
                stars.graphics.beginFill(0xffffff);
                stars.graphics.drawCircle(Math.random()*stage.stageWidth,Math.random()*stage.stageHeight,Math.random()*.8);
            }
            addChild(stars);
        }
    }
}
import flash.text.TextField;
import flash.display.SimpleButton;
import flash.display.Shape;
import flash.net.FileReference;
import flash.display.AVM1Movie;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.display.LoaderInfo;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.system.SecurityDomain;
import flash.system.LoaderContext;
import flash.utils.Dictionary;
import flash.geom.Matrix;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.Stage;
import flash.ui.Keyboard;
import flash.geom.Point;
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.display.Sprite;

Class {
    class Model extends EventDispatcher {
        
        public function Model() {
            // Модель - хранит данные о мире.
        }
    }
}

Class {
    class View extends Sprite {
        private var model:Model;
        private var controller:Controller;
        
        public function View(aModel:Model, oController:Controller,
                                target:Stage)
        {    // Представление - получает данные из модели и отображает на экране
            this.model = aModel;
            this.controller = oController;

            target.addChild(this);
        }
    }
}

Class {
    class Controller {
        private var model:Model;
        
        public function Controller(aModel:Model) 
        {   // Контроллер меняет данные в модели
            this.model = aModel;
        }
    }
}

Class {    // Нужен класс, чтобы возвращал XML-ку с уровнем
    class LevelCreator extends Sprite{    // Вообще это скорее Editor
       // private var tiles:Array = [];    зачем мне массив если потом все равно парстить mapHolder ?
        private var tiles:uint = 0;
        private var stg:Sprite;
        private var dragged:TileDO;    // Сейчас перетаскивается
        private var needConnect:TileDO;
        private var DrawConnectMode:Boolean = false;
        public function LevelCreator(st:Sprite):void {    // У меня есть объект MapHolder - на который я добавляю все что есть на уровне...
            st.addChild(this);
            stg = st;                                    // в принципе я могу пропарсить этот объект и собрать XML для сохранения...
            var tileCreator:Sprite = new Sprite();
            tileCreator.graphics.beginFill(0xaaaaaa,0.6);
            tileCreator.graphics.lineStyle(1,0xaaaaaa);
            tileCreator.graphics.drawRoundRect(400,340,50,100,4);
            this.addChild(tileCreator);
            
            st.addEventListener(MouseEvent.CLICK, newTileFunc);
            
            var xmlTileExportBtn:Sprite = LevelCreator.getButton(390,410,'xml export',0xffaaaa);
            this.addChild(xmlTileExportBtn);

            var toggleStateBtn:Sprite = LevelCreator.getButton(380,386,'togg connect',0xaaaaff);
            this.addChild(toggleStateBtn);
            
            toggleStateBtn.addEventListener(MouseEvent.CLICK, toggleState);
            xmlTileExportBtn.addEventListener(MouseEvent.CLICK, saveXML);
        }
        // Создание простых квадратов с текстом
        public static function getButton(nX:Number, nY:Number, text:String='simpleButton', color:uint=0xaaffaa):Sprite{
            var upState:Sprite = new Sprite();
            upState.graphics.beginFill(color,0.6);
            upState.graphics.lineStyle(1,color);
            var tf:TextField = new TextField();
            tf.text = text;
            tf.autoSize = 'left';
            tf.mouseEnabled = false;
            upState.addChild(tf);
            upState.graphics.drawRoundRect(-5,0,tf.width+10,tf.height,5);
            upState.graphics.endFill();
            upState.buttonMode = true;
            upState.x = nX; upState.y = nY;
            return upState;
        }

        private function saveXML(e:MouseEvent):void {
            var endXML:XML = new XML(<level>
            <graphics></graphics>
            <logick></logick>
            </level>);
            var graphicsI:uint = 0;
            var tileI:uint = 0;
            var analize:Object;
            for(var i:int=0; i<stg.numChildren; i++){    // Все, что будет добавленно на карту - включая объеты логики, сейчас содержится на stg
                analize = stg.getChildAt(i);    
                if(analize is TileClip){
                    endXML.graphics.clip[graphicsI] = TileClip(analize).nameTile;
                    endXML.graphics.clip[graphicsI].@x = analize.x;
                    endXML.graphics.clip[graphicsI].@y = analize.y;
                    graphicsI++;
                } else if(analize is TileDO){  
                    FlashTest.log(stg.getChildAt(i)+' at num '+i);
                    endXML.logick.tile[tileI] = tileI;
                    endXML.logick.tile[tileI].@x = analize.x;
                    endXML.logick.tile[tileI].@y = analize.y;
                    endXML.logick.tile[tileI].@links = analize.links;
                    tileI++;
                    //endXML.logick.tile.@y = stg.getChildAt(i).y;
                }
            }
            var fr:FileReference = new FileReference();
            fr.save(endXML, 'newLevel.xml');
            FlashTest.log(endXML);
        }
        private function toggleState(e:MouseEvent):void{ 
            this.DrawConnectMode = !this.DrawConnectMode;
            if(!DrawConnectMode)
                needConnect = null;
        }
        // нужно еще как то научится делать связи между элементами...
        private function newTileFunc(e:MouseEvent):void{    // Ну по идее здесь мы создаем новый тайл и позволяем перетаскивать его
            if(e.currentTarget is TileDO){
                stg.removeChild(e.currentTarget as TileDO);
                //e.currentTarget = null;
                return;
            }
            var tile:TileDO = new TileDO(Math.floor(mouseX/32)*32,Math.floor(mouseY/32)*32,tiles);     
            tile.links = [];
         //   tile.addEventListener(MouseEvent.MOUSE_UP, dropDragged);
            stg.addChild(tile);
            tiles++;
         //   dragged = tile;
         //   tiles.push( tile );
        }
        /*
        private function pickUpDragged(e:MouseEvent):void{    // Повторно перетаскиваем старый тайл
            dragged = TileDO(e.currentTarget);
            // Если мы рисуем связи, тогда к этому тайлу связь проведена
            if(DrawConnectMode){
                needConnect.addLink(dragged); 
            }
        }
        /*
        private function dropDragged(e:MouseEvent):void{
            dragged = null;    // Отпускаем перетаскиваемый тайл
            if(DrawConnectMode)
                needConnect = TileDO(e.currentTarget);
            e.currentTarget.addEventListener(MouseEvent.MOUSE_DOWN,pickUpDragged); // Разрешаем повтороно перетаскивать
            FlashTest.log('total tiles is: '+tiles.length);
        }
        /*
        private function moveDragged(e:Event):void{
            if(dragged && !DrawConnectMode){    // если есть что перетаскивать, то перетаскиваем ))
            dragged.x = Math.floor(mouseX/32)*32;
            dragged.y = Math.floor(mouseY/32)*32;
            }
        } */
    }
}
Class {
    class TileDO extends Sprite {
        public var id:uint;
        public var links:Array = [];
        public function TileDO(x:Number,y:Number,id:uint){
            this.x = x;  this.y = y;  this.id = id;
            this.graphics.beginFill(0xaaffaa,0.6);
            this.graphics.lineStyle(1,0x33aa33);
            this.graphics.drawRoundRect(0,0,31,31,2);
        }
        public function addLink(tile:TileDO):void{
            if(tile == this) return;    // связь с самим собой это как то неправильно
            for(var i:int=0; i<links.length; i++){
                if(links[i]==tile.id)
                    return;    // хм... тонкий момент (!) эта функиця выполняется 3! раза
            }
            links.push(tile.id);
            tile.addLink(this);
            this.graphics.moveTo(16,16);    // а это уже для наглядности
            this.graphics.lineStyle(1);
            this.graphics.lineTo( tile.x - this.x+16, tile.y - this.y+16 );    //нужно что-то вроде global to local и
        }
    }
}

Class {    // Логический объект который потом будет хранится в модели... (после загрузки Xml и инициализации уровня)
    class TileVO extends Point{
        public var neighbors:Vector.<TileVO>;    // а вот запись соседей будет внешняя // координат тоже
        private var myID:uint;
        public function TileVO(id:uint){
            this.myID = id;
            neighbors = new Vector.<TileVO>();
        }
        public function get id():uint { return myID; } // only read Id
    }
}

// help classes

Class {    // Так получилось что загружать можно только картинки... я попробовал загрузить xml
    class MyLoader extends EventDispatcher {    // не вышло (( это надо решить
        
        public static const ALL_LOADED:String = 'allLoaded';
        
        public var placeToLoad:String = 'http://cheshir.zabix.net/footlocker/RojerKarter/';
        public var loaded_D:Dictionary = new Dictionary();
            
        // to correct name
        private var WonderflFIX:String = 'http://swf.wonderfl.net/[[IM';  // this wonderfl add before my url...
        
        private var adresses:Array = []; // download all that is in this array    // Probably worth doing tileset...
        private var loaded:int = 0;    // count loaded elements
        
        private var loadedContents:Array = [];    // animate progress loading...
        private var loadSprite:Sprite = new Sprite();
        
        private var setFeedBack:View;
        private var lastId:uint = 0;
        
        private var stageLink:Stage;
        
        public function MyLoader(stageToLoad:Stage){
            stageLink = stageToLoad;
            stageLink.addChild(loadSprite);
        }
        
        public function loadAll(newAdresses:Array):void{
            this.adresses = newAdresses;
            FlashTest.log('start load...');
            var nowAdress:String = '';
            var context:LoaderContext = new LoaderContext();
            context.checkPolicyFile = true;
            context.securityDomain = SecurityDomain.currentDomain;
            for(var i:int=0; i<adresses.length; i++ ){
                FlashTest.log('new adress num '+(i+1));
                nowAdress = adresses[i];
                var url:URLRequest = new URLRequest(placeToLoad+nowAdress);
                var img:Loader = new Loader();
                img.contentLoaderInfo.addEventListener(Event.COMPLETE, loadedBit);
                img.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressLoad);
                loadedContents.push(img.contentLoaderInfo);
                img.load(url, context);
            }
        }
        
        private function progressLoad(e:ProgressEvent):void{
            var percent:Number = 0;//(e.currentTarget as LoaderInfo).bytesLoaded / (e.currentTarget as LoaderInfo).bytesTotal * 100;
            var lX:Number = 20;
            var lY:Number = 20;
            loadSprite.graphics.clear();    // clear graphitcs before draw...
            for(var i:int=0; i < loadedContents.length; i++){       // draw each loaded progress
                percent = (loadedContents[i] as LoaderInfo).bytesLoaded /(loadedContents[i] as LoaderInfo).bytesTotal * 100;
                loadSprite.graphics.lineStyle(1,0x75D07B, 0.8); 
                loadSprite.graphics.drawRect(lX,lY,102,5);           
                loadSprite.graphics.lineStyle(0);
                loadSprite.graphics.beginFill(0x9DD075,0.8);
                loadSprite.graphics.drawRect(lX+1,lY+1,percent,3);
                lY += 12;
            }
        }

        
        private function loadedBit(e:Event):void{    // 
            var bitmap:Bitmap = e.target.content;    // i want BitmapData
            // i need only original name... 
            var nameOfLoaded:String = e.target.url.toString().slice(WonderflFIX.length+placeToLoad.length);
            FlashTest.log('I have '+nameOfLoaded);
            // i want safe loaded to dictionary use original name...
            loaded_D[nameOfLoaded] = bitmap.bitmapData;
            loaded++;

            if(loaded == adresses.length){
                dispatchEvent(new Event(MyLoader.ALL_LOADED,true)); // why not?
                loadSprite.graphics.clear();
            }

        }
    }
}

Class {
    class Door extends Sprite {
        public var isOpen:Boolean = false;
        public var isLocked:Boolean = false;
        public var tilesConect:Array = [];
        private var doorClip:TileClip;
        public function Door(doorClip:TileClip) {
            this.doorClip = doorClip;
            doorClip.stop();
            doorClip.currentFrame = 0;
            doorClip.loop = false;
            this.buttonMode = true;
            doorClip.x = -doorClip.width/2;
            doorClip.y = -doorClip.height/2;
            addChild(doorClip);
            this.addEventListener(MouseEvent.CLICK, open_close);
            this.addEventListener(MouseEvent.MOUSE_OVER, lock_unlock);
        }
        public function lock_unlock(e:MouseEvent=null):void{
            isLocked = !isLocked;
            doorClip.currentState++;
            if(isLocked && isOpen){
                doorClip.inverse = true;
                doorClip.play();
                isOpen = false;    // Если дверь оказалась заперта и открыта одновременно, надо это исправить
                removeConnect();
            }    // Если я запер дверь, то она закрывается
        }
        public function open_close(e:MouseEvent=null):void{
            if(!isLocked){    // Дверь реагирует только если не заперта
                doorClip.inverse = isOpen;    // Если дверь открыта, значит ее нужно закрыть - инверсировать анимацию
                doorClip.play();                // воспроизвести анимацию
                isOpen = !isOpen;                // записать что дверь закрыта и наоборот
                if(isOpen){
                    setConnect();    // Если дверь открылась тогда нужны связи
                } else {
                    removeConnect();    // Если дверь закрылась тогда связи не нужны
                }
            }
        }
        private function setConnect():void {    // Когда дверь открывается она должна установить между двумя тайлами
            // между которых она находится - связь, чтобы можно было произвести поиск пути сквозь открытые двери
        }
        private function removeConnect():void {    // Когда дверь закрывается она должна убрать связь
            
        }
    }
}

Class {
    interface AlphaChanger { /*
        function alphaFading():void;
        function alphaIgnition():void; */
    }
}


Class{
    class TileClip extends Bitmap implements AlphaChanger
    {
        public var demoMode:Boolean = false;
        public var randomDelay:Boolean = false;
        public var inverse:Boolean = false;     // Если мне нужно проиграть видео в обратном направлении
        public var loop:Boolean =  true;        // Если анимация должна быть цикличной, по умолчанию ДА
        
        public var nameTile:String = 'simple TileClip';
        
        private var delays:Array = [];    // yes... when i change delays -- current delay must change also to delays[0]
        
        private var currentDelay:uint = 0;
        
        private var widthFrame:Number;
        private var heightFrame:Number;
        private var bitData:BitmapData;
        
        private var currFrame:uint = 0;
        private var totalFrame:uint = 0;
        private var currState:uint = 0;
        private var totalState:uint = 0;
        
        private var matrix:Matrix;
        
        // Create TileClip from bitmap Data
        public function TileClip(widthFrame:Number, heightFrame:Number, bitData:BitmapData, scale:Number = 1)
        {   // для парсинга может стоит сохранять имя клипа?
            this.widthFrame = widthFrame;
            this.heightFrame = heightFrame;
            this.bitData = bitData;            // Safe data to draw
            matrix = new Matrix();        // Init Matrix transform
            totalFrame = uint(bitData.width / widthFrame);    // Calculate frames
            totalState = uint(bitData.height / heightFrame);    // Calculate states
            this.bitmapData = new BitmapData(widthFrame, heightFrame, true, 0);    // This is 'wiew window' of my clip
            super();
            currentFrame = 0;
            this.width = widthFrame * scale;
            this.height = heightFrame * scale;
            if(totalFrame>1){
                play();
            }
        }
        public function set frameDelay(val:Array):void
        {
            delays = val;
            currentDelay = delays[0];
        }
        public function set currentFrame(num:uint):void
        {
            if (num < totalFrame)    // Elementary update as looped video "currentFrame+=1"
            {
                this.currFrame = num;
            } else {
                if(loop){
                    this.currFrame = 0;
                } else {
                    this.stop();
                }
                if(demoMode){currentState++;}
            }
            setCurrentFrame();
        }
        public function get currentFrame():uint
        {
            return this.currFrame;
        }
        public function set currentState(num:uint):void
        {
            if (num < totalState)
            {
                this.currState = num;
            } else {
                this.currState = 0;
            }
            setCurrentFrame();
        }
        public function get currentState():uint
        {
            return this.currState;
        }
        public function play():void
        {
            this.addEventListener(Event.ENTER_FRAME, update);
        }
        public function stop():void
        {
            this.removeEventListener(Event.ENTER_FRAME, update);
        }
        public function update(e:Event):void
        {
            //currentFrame++;    // Maybe i must add delays to each frame?
            /* How can I add delays to frames... Delay can be a good idea becouse my sheep slightly twitch.
                I like a meditative thing ... */
            if(currentDelay <= 0){
               if(inverse){
                   currentFrame--;
               } else {
                   currentFrame++;
               }
               currentDelay = (randomDelay) ? uint(delays[currentFrame]*Math.random()) : uint(delays[currentFrame]);
            //   I like random and it make my animation not so repetitive...
            //    FlashTest.myConsole.clear();
            //    FlashTest.myConsole.log('next frame delay '+currentDelay);
            } else {
                currentDelay--;
            }
        }
        
        private function setCurrentFrame():void    // DRY    (don't repeat yourself)
        {
            matrix.tx = -this.currFrame * widthFrame;    // positioning data
            matrix.ty = -this.currState * heightFrame;
            this.bitmapData.fillRect(this.bitmapData.rect, 0);    // clear 'wiew window'
            this.bitmapData.draw(bitData, matrix);
        }
    }
}