forked from: Clouds and snow + MovementMeters + (todo:SE)

by Glidias forked from Clouds and snow + SE (diff: 698)
Added movement up control and speedometer reading with 1st deriative.
__
It was a tricky task to scroll seamless mountains.

Unfortunately the volumetric lighting effect is
a bit of a CPU hog, but it looks nice if your
hardware can pull it off.
繋ぎ目のない山を無限スクロールさせるのにちょっと悩みました。
クリックでどうなってるのかネタバレします。
架線柱のティアリングがひどいなあ……。
import net.hires.debug.Stats;
♥0 | Line 1046 | Modified 2017-03-07 14:52:33 | MIT License
play

ActionScript3 source code

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

// forked from yonatan's Clouds and snow
// forked from cjcat2266's Super Express Desert Sunset + Rain (Stardust ver.)
// forked from yonatan's Super Express Desert Sunset

// forked from k0rin's Super Express
// It was a tricky task to scroll seamless mountains.
// Click to see how it works.

// Unfortunately the volumetric lighting effect is
// a bit of a CPU hog, but it looks nice if your
// hardware can pull it off.

// 繋ぎ目のない山を無限スクロールさせるのにちょっと悩みました。
// クリックでどうなってるのかネタバレします。

// 架線柱のティアリングがひどいなあ……。

package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import com.bit101.components.*;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.media.SoundLoaderContext;
    import flash.media.SoundTransform;
    import flash.net.URLRequest;
    import flash.text.ime.CompositionAttributeRange;
    import flash.ui.Keyboard;
    import flash.utils.Timer;
    // import net.hires.debug.Stats;
    import idv.cjcat.stardust.twoD.emitters.Emitter2D;
    
    [SWF(width = "465", height = "465", frameRate = "40")]
    public class Main extends Sprite
    {
        public static const WIDTH:Number = 465;
        public static const HEIGHT:Number = 465;
        
        private var debug:Boolean = false;
        private var sun:SunLight;
        private var entities:Vector.<Entity> = new Vector.<Entity>();
        private var renderedScene:BitmapData = new BitmapData(WIDTH, HEIGHT);
        private var scene:Sprite = new Sprite;
        
        private var emitter:RainEmitter;
        private var soundRun:Sound;
        private var soundSL:Sound;
        private var soundRunChannel:SoundChannel;
        
        
        
        public static const CLOUD_NUM:int = 50;
        public static const ERROR_SEEDS:Array = [346, 514, 1155, 1519, 1690, 1977, 2327, 2337, 2399, 2860, 2999, 3099, 4777, 4952, 5673, 6265, 7185, 7259, 7371, 7383, 7717, 7847, 8032, 8350, 8676, 8963, 8997, 9080, 9403, 9615, 9685];
        public var loading:LoadingScene;
        private var labelCurSpeed:Label;
        private var labelMaxSpeed:Label;

        /**perlinNoiseに使うとまずいシード値(画像に穴があくかもしれない)*/
        public function Main():void
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            loading = new LoadingScene();
            addChild(loading);
            addEventListener(Event.ENTER_FRAME, onLoading);
        }

        // cloud constants
        public static const FOCUS:Number = 500;
        public static const MAX_Z:Number = 4000;
        public static const MIN_Z:Number = 250;

        private function onLoading(...arg):void {
            for (var i:int = 0; i < 3; i++) {
                if(Clouds.bmps.length >= CLOUD_NUM){
                    start();
                    break;
                }
                var seed:int = Math.random() * 10000 + 1;
                if (ERROR_SEEDS.indexOf(seed) >= 0) seed++;
                var ct:Number = (Math.random() < 0.2)? Math.random() * 0.3 : Math.random() * 1.5;
                var z:Number = MAX_Z - (MAX_Z-MIN_Z)/CLOUD_NUM*(Clouds.bmps.length);
                var w:Number = 400/(z/FOCUS);
                var h:Number = 200/(z/FOCUS);
                var bmp:Bitmap = new Bitmap(Painter.createCloud(w, h, seed, ct, Color.cloudBase, Color.cloudLight, Color.cloudShadow));
                bmp.x = Math.random() * (Main.WIDTH + bmp.width) - bmp.width;
                bmp.y = HEIGHT*0.6 - HEIGHT*0.5 * FOCUS/z;
                Clouds.bmps.push(bmp);
                loading.setProgress(Clouds.bmps.length / CLOUD_NUM);
            }
        }

        public function start():void
        {
            removeEventListener(Event.ENTER_FRAME, onLoading);
            removeChild(loading);
            stage.quality = StageQuality.MEDIUM;
            // 空を描画
            var matrix:Matrix = new Matrix();
            matrix.createGradientBox(WIDTH, HEIGHT, Math.PI / 2);
            graphics.beginGradientFill(GradientType.LINEAR, [0x51484A, 0x96644E], null, [0, 128], matrix);
            graphics.drawRect(0, 0, WIDTH, HEIGHT);
            graphics.endFill();

            var clouds:Clouds = new Clouds;
            entities.push(scene.addChild(clouds));
            
            var fogR:Number = 0x40;
            var fogG:Number = 0x35;
            var fogB:Number = 0x2c;
            
            var mountainR:Number = 0x17;
            var mountainG:Number = 0x13;
            var mountainB:Number = 0x15;

            const NUMBER_OF_MOUNTAINS:int = 4;
            
            for (var i:int = 0; i < NUMBER_OF_MOUNTAINS; i++) {
                var blend:Number = i / (NUMBER_OF_MOUNTAINS - 1);
                
                var _r:Number = lerp(fogR, mountainR, blend);
                var _g:Number = lerp(fogG, mountainG, blend);
                var _b:Number = lerp(fogB, mountainB, blend);
                
                var baseHeight:Number = HEIGHT * 0.55 + i * 25;
                var color:uint = (_r << 16) | (_g << 8) | _b;
                
                var mountain:Mountain = new Mountain(-Math.pow(i + 1, 2), baseHeight, color);
                entities.push(scene.addChild(mountain));
            }
            
            entities.push(scene.addChild(new PoleAndWire()));
            entities.push(scene.addChild(new Tunnel()));
            
            //insert emitter
            emitter = new RainEmitter(scene);
            
            addChild(scene);
            addChild(sun = new SunLight(renderedScene));
            
            var outline:Shape = new Shape();
            var g:Graphics = outline.graphics;
            g.lineStyle(1, 0x808080);
            g.drawRect( -1, -1, WIDTH + 2, HEIGHT + 2);
            addChild(outline);
            
            restoreFilters(debug);
            
          //  playSound();
            
            //stage.addEventListener(MouseEvent.CLICK, clickHandler);
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            // addChild(new Stats);
            
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            
            new PushButton(this, 5, 5, "Move on..", pumpGasHandler);
            var hBox:VBox =  new VBox(this, 120, 10);
            uiOptions = hBox;
            var lbl:Label;
            lbl = new Label(hBox, 0, 0, "MaxSpeed"); lbl.blendMode = "invert";
            var hSlider:HSlider;
            hSlider = new HSlider(hBox, 0, 0, onMaxSpeedChange);
            hSlider.minimum = 1;
            hSlider.maximum = 5;
            hSlider.width = 15 * 5;
            hSlider.value = model.getMaxSpeed();
            
            lbl = new Label(hBox, 0,0, "AccelTimeSpan"); lbl.blendMode = "invert";
            _accelTimeSpanner = hSlider = new HSlider(hBox, 0, 0, onAccelTimeSpanChange);
            hSlider.minimum = 1;
            hSlider.maximum = 5;
            hSlider.width = 15 * 5;
            hSlider.value = 1;
            
            lbl = new Label(hBox, 0,0, "BrakeTimeSpan"); lbl.blendMode = "invert";
            _accelTimeSpanner2 = hSlider = new HSlider(hBox, 0, 0, onAccelTimeSpanChange);
            hSlider.minimum = 1;
            hSlider.maximum = 5;
            hSlider.width = 15 * 5;
            hSlider.value = 1;
            
            lbl = new Label(hBox, 0, 0, "Ease");
            var cb:ComboBox = new ComboBox(hBox, 0, 0, "", ["Linear", "Quadratic", "Cubic", "Quartic", "Quintic"]);
            cb.addEventListener(Event.SELECT, onComboEaseSelect);
            model.setupEasingFunctions( cb.selectedIndex=2 );
            
            model.setPickupTimespans(1, 1);
            
            var disp:VBox = new VBox(this, 5, 20);
            labelCurSpeed = new Label(disp);
            new Label(disp, 0, 0, "/");
            labelMaxSpeed = new Label(disp);
            
        }
        
        private var _accelTimeSpanner:HSlider;
        private var _accelTimeSpanner2:HSlider;
        
        private function onMaxSpeedChange(e:Event):void {
            var hSlider:HSlider = e.target as HSlider;
            model.setMaxSpeed( hSlider.value);
        }
        private function onAccelTimeSpanChange(e:Event):void {
            model.setPickupTimespans(_accelTimeSpanner.value, _accelTimeSpanner2.value);
        }
        private function onComboEaseSelect(e:Event):void {
                var targ:ComboBox = e.target as ComboBox;
            model.setupEasingFunctions( targ.selectedIndex );
        }
        
        
        private function pumpGasHandler(e:Event=null):void {
             model.travelTo( int(model.targetDest + 1 ) );
        }
        
        private function onKeyDown(e:KeyboardEvent):void 
        {
            if (e.keyCode == Keyboard.G) {
                
                model.travelTo( int(model.targetDest + 1 ) );
            }
        }
        
        private function clickHandler(e:MouseEvent):void 
        {
            debug = !debug;
            
            var matrix:Matrix = new Matrix();
            if (debug) {
                // transformで表示領域外を確認。お手軽でいいと思う。
                matrix.scale(0.2, 0.2);
                matrix.translate(WIDTH * 0.4, HEIGHT * 0.4);
            }
            transform.matrix = matrix;
            
            restoreFilters(debug);
        }
        
        private function restoreFilters(debug:Boolean):void
        {
            for each (var entity:Entity in entities)
            {
                entity.restoreFilter(debug);
            }
        }
        
        
        private var model:SceneModel = new SceneModel();
        private var _needToRender:Boolean = false;
        private var _curLoc:Number = 0;
        private var unitTimeLength:Number = GameSettings.SHARED_FPS;
        private var uiOptions:Sprite;
        
        private function enterFrameHandler(e:Event):void 
        {
            
            model.update();
            
            if (model.movingState != BGTrainState.STOPPED) {
                uiOptions.mouseChildren = false;
                uiOptions.visible = false;
            }
            else {
                uiOptions.mouseChildren = true;
                uiOptions.visible = true;
            }
            
           // if (_needToRender || model.movingState != BGTrainState.STOPPED) {  // perform necessary render updates
            _needToRender = model.movingState != BGTrainState.STOPPED;
            
            
            var tarLoc:Number = model.currentPosition;
            
            var diff:Number = (tarLoc - _curLoc)*unitTimeLength;
            
            
            for each (var entity:Entity in entities)
            {
                entity.update(diff);
            }
            
          
            
            renderedScene.fillRect(renderedScene.rect, 0);
            renderedScene.draw(scene);
            sun.update(diff);
            
            /*
            if (soundRunChannel && soundRunChannel.position >= 14025)
            {
                soundRunChannel.stop();
                soundRunChannel = soundRun.play(3169);
                trace(soundRunChannel.position);
            }
            */
                    labelCurSpeed.text = "" + model.getCurrentVelocity();
                    labelMaxSpeed.text = "" + model.getMaxSpeed();
                emitter.steppedBasedOnSpeeds(model.getCurrentVelocity(), model.getMaxSpeed() );
                sun.update(diff);
                _curLoc = tarLoc;
            
          //  else {
            //    _needToRender = false;
            //    sun.update(0);
            //    emitter.step();
        //    }
        
            
          
        }
        
        private function playSound():void
        {
            var context:SoundLoaderContext = new SoundLoaderContext(1000, true);
            soundRun = new Sound(new URLRequest("http://paq.s346.xrea.com/wonderfl/sound/sl_run.mp3"), context);
            soundSL = new Sound(new URLRequest("http://paq.s346.xrea.com/wonderfl/sound/sl.mp3"), context);
            soundRun.addEventListener(Event.COMPLETE, function():void {
                soundRun.removeEventListener(Event.COMPLETE, arguments.callee);
                soundRunChannel = soundRun.play(0);
            });
            soundSL.addEventListener(Event.COMPLETE, function():void {
                soundSL.removeEventListener(Event.COMPLETE, arguments.callee);
                var timer:Timer = new Timer(3000);
                timer.addEventListener(TimerEvent.TIMER, function():void {
                    timer.removeEventListener(TimerEvent.TIMER, arguments.callee);
                    timer = null;
                    soundSL.play();
                });
                timer.start();
            });
        }
    }
}

import flash.display.*;
import flash.filters.*;
import flash.geom.*;
import idv.cjcat.stardust.common.actions.Die;
import idv.cjcat.stardust.common.actions.triggers.ActionTrigger;
import idv.cjcat.stardust.common.clocks.SteadyClock;
import idv.cjcat.stardust.common.initializers.Scale;
import idv.cjcat.stardust.common.math.UniformRandom;
import idv.cjcat.stardust.twoD.actions.Gravity;
import idv.cjcat.stardust.twoD.actions.Move;
import idv.cjcat.stardust.twoD.actions.Oriented;
import idv.cjcat.stardust.twoD.actions.RandomDrift;
import idv.cjcat.stardust.twoD.actions.triggers.ZoneTrigger;
import idv.cjcat.stardust.twoD.emitters.Emitter2D;
import idv.cjcat.stardust.twoD.fields.UniformField;
import idv.cjcat.stardust.twoD.handlers.DisplayObjectHandler;
import idv.cjcat.stardust.twoD.initializers.DisplayObjectClass;
import idv.cjcat.stardust.twoD.initializers.Position;
import idv.cjcat.stardust.twoD.initializers.Velocity;
import idv.cjcat.stardust.twoD.zones.LazySectorZone;
import idv.cjcat.stardust.twoD.zones.RectZone;
import idv.cjcat.stardust.twoD.zones.Zone;

class Rain extends Shape {
    
    public function Rain() {
        graphics.beginFill(0x303030);
        graphics.drawRect( -1, -15, 2, 30);
        
        blendMode = BlendMode.ADD;
        filters = [new BlurFilter(20, 0)];
    }
}

class RainEmitter extends Emitter2D {
    public var uniField:UniformField;
    public function RainEmitter(container:DisplayObjectContainer) {
        super(new SteadyClock(2));
        
        //initializers
        addInitializer(new DisplayObjectClass(Rain));
        addInitializer(new Position(new RectZone(500, -50, 1, 500)));
        addInitializer(new Scale(new UniformRandom(1, 0.7)));
        
        var lazyRectZone:LazySectorZone = new LazySectorZone();
        lazyRectZone.direction.set(-1, 0);
        lazyRectZone.directionVar = 20;
        lazyRectZone.radius = 25;
        lazyRectZone.radiusVar = 15;
        addInitializer(new Velocity(lazyRectZone));
        
        //actions
        addAction(new Move());
        addAction(new Oriented());
        addAction(new RandomDrift(4, 4));
        
        //gravity
        var gravity:Gravity = new Gravity();
        gravity.addField(uniField = new UniformField(0, 1));
        addAction(gravity);
        
        //death zone
        var deathZone:Zone = new RectZone( -50, -50, 600, 600);
        var zoneTrigger:ActionTrigger = new ZoneTrigger(deathZone);
        zoneTrigger.inverted = true;
        zoneTrigger.addAction(new Die());
        addAction(zoneTrigger);
        
        //particle handler
        particleHandler = new DisplayObjectHandler(container);
    }
    
    public function steppedBasedOnSpeeds(speed:Number, maxSpeed:Number):void  {
        uniField.x =  -speed;
        step();
    }
}

class Entity extends Sprite
{
    public function update(dt:Number):void { };
    public function restoreFilter(debug:Boolean):void { };
}

class SunLight extends Entity {
    public static const FXW:int = 0x100;
    public static const FXH:int = 0x100;

    private var src:BitmapData = new BitmapData(FXW, FXH, true, 0);
    private var dst:BitmapData = new BitmapData(FXW, FXH, true, 0);
    private var sun:Shape = new Shape;
    private var obstruction:Bitmap;
    private var scaleDown:Matrix = new Matrix;
    private var scaleUp:Matrix = new Matrix;
    private var mtx:Matrix = new Matrix;
    private var canvas:Bitmap = new Bitmap(dst);
    private var blur:BlurFilter = new BlurFilter(5, 5, 1);
    
    public function SunLight(obstruction:BitmapData) {
        this.blendMode = "add";
        this.obstruction = new Bitmap(obstruction);
        var m:Matrix = new Matrix;
        m.createGradientBox(FXW, FXH, 0, 0, 0);
        sun.graphics.beginGradientFill("radial", [0x0C0a08, 0x0a0806, 0x060504, 0x020201, 0], [1, 1, 1, 1, 1], [0, 10, 34, 64, 255], m);
        sun.graphics.drawRect(0, 0, FXW, FXH);
        sun.graphics.endFill();
        sun.cacheAsBitmap = true;
        
        scaleDown.scale(FXW/Main.WIDTH, FXH/Main.HEIGHT);
        scaleUp.scale(Main.WIDTH/FXW, Main.HEIGHT/FXH);

        addChild(canvas);
        transform.matrix = scaleUp;
    }

    public override function update(dt:Number):void {
        src.lock();
        dst.lock();
        src.fillRect(src.rect, 0);
        src.draw(sun);
        src.draw(obstruction, scaleDown, null, "erase");
        canvas.bitmapData = process(src);
        src.unlock();
        dst.unlock();
    }
    
    private function process(src:BitmapData):BitmapData {
        var dst:BitmapData = this.dst;
        mtx.identity();
        mtx.translate(-FXW/34, -FXH/34);
        mtx.scale(17/16, 17/16);
        var cnt:int = 5;
        var tmp:BitmapData;
        while(cnt--) {
            mtx.concat(mtx);
            dst.copyPixels(src, src.rect, src.rect.topLeft);
            dst.draw(src, mtx, null, "add");
            dst.applyFilter(dst, dst.rect, dst.rect.topLeft, blur);
            tmp = src;
            src = dst;
            dst = tmp;
        }
        return src;
    }
}

class Mountain extends Entity
{
    private var heightMap:Vector.<Number> = new Vector.<Number>();
    private const SEGMENT_LENGTH:Number = 10;
    
    private var baseHeight:Number;
    private var color:uint;
    private var speed:Number;
    
    function Mountain(speed:Number, baseHeight:Number, color:uint)
    {
        this.baseHeight = baseHeight;
        this.color = color;
        this.speed = speed;
        
        generateHeightMap();
        createShape();
    }
    
    public override function update(dt:Number):void
    {
        x += speed*dt;
        if (x < -(width - Main.WIDTH)) {
            var removeSegmentNumber:int = (width - Main.WIDTH) / SEGMENT_LENGTH;
            heightMap.splice(0, removeSegmentNumber);
            x += removeSegmentNumber * SEGMENT_LENGTH;
            
            generateHeightMap();
            createShape();
        }
    }
    
    private function generateHeightMap():void
    {
        // 再帰で分割していく
        divide(baseHeight, baseHeight, 0, 200);
        
        function divide(left:Number, right:Number, depth:int, offset:Number):void
        {
            if (depth < 6) {
                var half:Number = (left + right) / 2 + rnd( -offset / 2, offset / 2);
                
                divide(left, half, depth + 1, offset / 2);
                divide(half, right, depth + 1, offset / 2);
            } else {
                // 十分に分割したら順番に書き出し
                heightMap.push(left);
            }
        }
    }
    
    private function createShape():void
    {
        var g:Graphics = graphics;
        
        g.clear();
        g.beginFill(color);
        g.moveTo(0, Main.HEIGHT);
        for (var i:int = 0; i < heightMap.length; i++) {
            g.lineTo(i * SEGMENT_LENGTH, heightMap[i]);
        }
        g.lineTo((i - 1) * SEGMENT_LENGTH, Main.HEIGHT);
        g.endFill();
        
        // デバッグ表示
        g.lineStyle(1, color);
        g.moveTo(0, heightMap[0]);
        g.lineTo(0, Main.HEIGHT * 2);
    }
}

class Clouds extends Entity {
    public static var bmps:Array = [];

    public function Clouds() {
        for each(var bmp:Bitmap in bmps) addChild(bmp);
    }

    public override function update(dt:Number):void {
        for each(var bmp:Bitmap in bmps) {
            bmp.x -= bmp.width * 0.001*dt;
            if(bmp.x + bmp.width < 0) {
                bmp.x = Main.WIDTH;
            }
        }
    }
}

const SPEED:Number = 80;

class PoleAndWire extends Entity
{
    private const SPACING:Number = Main.WIDTH * 5;
    
    private const POLE_THICK:Number = 40;
    private const WIRE_TOP:Number = 20;
    private const WIRE_BOTTOM:Number = 100;
    
    function PoleAndWire()
    {
        var g:Graphics = graphics;
        
        g.beginFill(0x332222);
        g.drawRect(-POLE_THICK / 2, 0, POLE_THICK, Main.HEIGHT);
        g.endFill();
        
        g.lineStyle(1, 0x221111);
        g.moveTo(POLE_THICK / 2, WIRE_TOP);
        g.curveTo(SPACING / 2, WIRE_BOTTOM, SPACING - POLE_THICK, WIRE_TOP);
        g.moveTo(-POLE_THICK / 2, WIRE_TOP);
        g.curveTo(-SPACING / 2, WIRE_BOTTOM, -SPACING + POLE_THICK, WIRE_TOP);
        
        x = (SPACING + Main.WIDTH) / 2;
    }
    
    public override function update(dt:Number):void
    {
        x -= SPEED*dt;
        if (x < (-SPACING + Main.WIDTH) / 2) {
            x += SPACING;
        }
    }
    
    public override function restoreFilter(debug:Boolean):void
    {
        filters = debug ? null : [ new BlurFilter(80, 0, 1) ];
    }
}

class Tunnel extends Entity
{
    // |ENTRANCE|SPACE|LIGHT|SPACE|ENTRANCE|
    // ^ origin
    
    private const LIGHT:Number = 100;
    private const SPACE:Number = Main.WIDTH * 1.4;
    private const ENTRANCE:Number = Main.WIDTH * 1.5;
    private const WIDTH:Number = LIGHT + SPACE * 2 + ENTRANCE * 2;
    
    private const ENTRANCE_COLOR:uint = 0x896857 >>> 1 & 0x7f7f7f;
    private const DARKNESS_COLOR:uint = 0x0A0908;
    private const LIGHT_COLOR:uint = 0xFFF0E0;
    
    private var lightCount:int;
    private var light:Shape;
    
    function Tunnel()
    {
        var g:Graphics = graphics;
        
        var matrix:Matrix = new Matrix();
        matrix.createGradientBox(ENTRANCE, Main.HEIGHT);
        g.beginGradientFill(GradientType.LINEAR, [ENTRANCE_COLOR, DARKNESS_COLOR], null, [0, 255], matrix);
        g.drawRect(0, 0, ENTRANCE, Main.HEIGHT);
        matrix.createGradientBox(ENTRANCE, Main.HEIGHT, 0, WIDTH - ENTRANCE, 0);
        g.beginGradientFill(GradientType.LINEAR, [DARKNESS_COLOR, ENTRANCE_COLOR], null, [0, 255], matrix);
        g.drawRect(WIDTH - ENTRANCE, 0, ENTRANCE, Main.HEIGHT);
        g.endFill();
        
        g.beginFill(DARKNESS_COLOR);
        g.drawRect(ENTRANCE, 0, LIGHT + SPACE * 2, Main.HEIGHT);
        g.endFill();
        
        light = new Shape();
        light.graphics.beginFill(LIGHT_COLOR);
        light.graphics.drawRect(WIDTH / 2, Main.HEIGHT * 0.55, LIGHT, 20);
        light.graphics.endFill();
        addChild(light);
        
        prepareNextTunnel();
        
        // 最初のトンネルまでは定距離にする。 - distance to 1st tunnel
        x = SPEED * 1800;
    }
    
    public override function update(dt:Number):void
    {
        x -= SPEED*dt;
        if (x < -(WIDTH - ENTRANCE - Main.WIDTH)) {
            if (--lightCount >= 0) {
                // ライトをループ
                x += SPACE * 2 + LIGHT - Main.WIDTH;
                trace(length);
            }
        }
        if (x < -WIDTH * 2) {
            prepareNextTunnel();
        }
    }
    
    public override function restoreFilter(debug:Boolean):void
    {
        filters = debug ? null : [ new BlurFilter(80, 0, 1) ];
        light.filters = debug ? null : [ new GlowFilter(0xFF8000, 1, 50, 50, 3, 4) ];
    }
    
    private function prepareNextTunnel():void
    {
        x = SPEED * rnd(1300, 4000);
        lightCount = rnd(6, 50);
    }
}

// 線形補間
function lerp(n0:Number, n1:Number, p:Number):Number
{
    return n0 * (1 - p) + n1 * p;
}

// [min, max)の乱数を取得
function rnd(min:Number, max:Number):Number
{
    return min + Math.random() * (max - min);
    //  return lerp(min, max, Math.random());
}

// copy-pasta from tencho's Sea of Clouds...

class Color {
    /**雲の色*/
    static public var cloudBase:uint = 0x725040;
    /**雲のハイライト色*/
    static public var cloudLight:uint = 0xFDDFC9;
    /**雲の影の色*/
    static public var cloudShadow:uint = 0x38231E;
}

class LoadingScene extends Sprite {
    private var _lineWidth:Number = 200;
    private var _loadedLine:Sprite;
    public function LoadingScene() {
        var bg:Sprite = addChild(Painter.createGradientRect(Main.WIDTH, Main.HEIGHT, [0x000000], [1])) as Sprite;
        var baseLine:Sprite = addChild(Painter.createGradientRect(_lineWidth, 2, [0x444444], [1])) as Sprite;
        _loadedLine = addChild(Painter.createGradientRect(_lineWidth, 2, [0x7DA3C8], [1])) as Sprite;
        baseLine.x = _loadedLine.x = int((Main.WIDTH - _lineWidth) / 2);
        baseLine.y = _loadedLine.y = int((Main.HEIGHT - baseLine.height) / 2);
        setProgress(0);
    }
    public function setProgress(per:Number):void {
        _loadedLine.width = _lineWidth * per;
    }
}

class Painter {
    /**
    * 雲画像生成
    * @param    width    幅
    * @param    height    高さ
    * @param    seed    ランダムシード値
    * @param    contrast    コントラスト0~
    * @param    color    ベースの色
    * @param    light    明るい色
    * @param    shadow    暗い色
    */
    static public function createCloud(width:int, height:int, seed:int, contrast:Number = 1, color:uint = 0xFFFFFF, light:uint = 0xFFFFFF, shadow:uint = 0xDDDDDD):BitmapData {
        var gradiation:Sprite = new Sprite();
        var drawMatrix:Matrix = new Matrix();
        drawMatrix.createGradientBox(width, height);
        gradiation.graphics.beginGradientFill("radial", [0x000000, 0x000000], [0, 1], [0, 255], drawMatrix);
        gradiation.graphics.drawRect(0, 0, width, height);
        gradiation.graphics.endFill();
        var alphaBmp:BitmapData = new BitmapData(width, height);
        alphaBmp.perlinNoise(width / 3, height / 2.5, 5, seed, false, true, 1|2|4, true);
        var zoom:Number = 1 + (contrast - 0.1) / (contrast + 0.9);
        if (contrast < 0.1) zoom = 1;
        if (contrast > 2.0) zoom = 2;
        var ctMatrix:Array = [contrast + 1, 0, 0, 0, -128 * contrast, 0, contrast + 1, 0, 0, -128 * contrast, 0, 0, contrast + 1, 0, -128 * contrast, 0, 0, 0, 1, 0];
        alphaBmp.draw(gradiation, new Matrix(zoom, 0, 0, zoom, -(zoom - 1) / 2 * width, -(zoom - 1) / 2 * height));
        alphaBmp.applyFilter(alphaBmp, alphaBmp.rect, new Point(), new ColorMatrixFilter(ctMatrix));
        var image:BitmapData = new BitmapData(width, height, true, 0xFF << 24 | color);
        image.copyChannel(alphaBmp, alphaBmp.rect, new Point(), 4, 8);
        image.applyFilter(image, image.rect, new Point(), new GlowFilter(light, 1, 4, 4, 1, 3, true));
        var bevelSize:Number = Math.min(width, height) / 30;
        image.applyFilter(image, image.rect, new Point(), new BevelFilter(bevelSize, 45, light, 1, shadow, 1, bevelSize/5, bevelSize/5, 1, 3));
        var image2:BitmapData = new BitmapData(width, height, true, 0);
        image2.draw(Painter.createGradientRect(width, height, [light, color, shadow], [1, 0.2, 1], null, 90), null, null, BlendMode.MULTIPLY);
        image2.copyChannel(alphaBmp, alphaBmp.rect, new Point(), 4, 8);
        image.draw(image2, null, null, BlendMode.MULTIPLY);
        alphaBmp.dispose();
        return image;
    }
    /**
    * グラデーションスプライト生成
    */
    static public function createGradientRect(width:Number, height:Number, colors:Array, alphas:Array, ratios:Array = null, rotation:Number = 0):Sprite {
        var i:int, rts:Array = new Array();
        if(ratios == null) for (i = 0; i < colors.length; i++) rts.push(int(255 * i / (colors.length - 1)));
        else for (i = 0; i < ratios.length; i++) rts[i] = Math.round(ratios[i] * 255);
        var sp:Sprite = new Sprite();
        var mtx:Matrix = new Matrix();
        mtx.createGradientBox(width, height, Math.PI / 180 * rotation, 0, 0);
        if (colors.length == 1 && alphas.length == 1) sp.graphics.beginFill(colors[0], alphas[0]);
        else sp.graphics.beginGradientFill("linear", colors, alphas, rts, mtx);
        sp.graphics.drawRect(0, 0, width, height);
        sp.graphics.endFill();
        return sp;
    }
}

import flash.utils.getTimer;



 class Std {
        static public function _is(v : *,t : *) : Boolean {
            try {
                if(t == Object) return true;
                return v is t;
            }
            catch( e : * ){
            };
            return false;
        }
        
        static public function instance(value : *,c : Class) : * {
            return value as c;
        }
        
        static public function string(s : *) : String {
            return ""+s;
        }
        
        static public function _int(x : Number) : int {
            return int(x);
        }
        
        static public function _parseInt(x : String) : * {
            var v : * = parseInt(x);
            if(isNaN(v)) return null;
            return v;
        }
        
        static public function _parseFloat(x : String) : Number {
            return parseFloat(x);
        }
        
        static public function random(x : int) : int {
            if(x <= 0) return 0;
            else return Math.floor(Math.random() * x);
            return 0;
        }
        
    }


     class enum {
        public var tag : String;
        public var index : int;
        public var params : Array;
        public function toString() : String { return enum_to_string(this); }
        static protected var IN_E : int = 0;
        static public function enum_to_string(e : *) : String {
            if(e.params == null) return e.tag;
            var pstr : Array = [];
            if(IN_E > 15) pstr.push("...");
            else {
                IN_E++;
                {
                    var _g : int = 0;
                    var _g1 : Array = e.params;
                    while(_g < _g1.length) {
                        var p : * = _g1[_g];
                        ++_g;
                        pstr.push(""+p);
                    }
                };
                IN_E--;
            };
            return e.tag + "(" + pstr.join(",") + ")";
        }
    }
    
    



     final class BGTrainState extends enum {
        public static const __isenum : Boolean = true;
        public function BGTrainState( t : String, index : int, p : Array = null ) : void { this.tag = t; this.index = index; this.params = p; }
        public static function ACCEL(wontSpeed : Boolean) : BGTrainState { return new BGTrainState("ACCEL",1,[wontSpeed]); }
        public static function BRAKING(wontSpeed : Boolean) : BGTrainState { return new BGTrainState("BRAKING",3,[wontSpeed]); }
        public static var SPEEDING : BGTrainState = new BGTrainState("SPEEDING",2);
        public static var STOPPED : BGTrainState = new BGTrainState("STOPPED",0);
        public static var __constructs__ : Array = ["STOPPED","ACCEL","SPEEDING","BRAKING"];
    }



interface IBGTrain {
        function get_currentPosition() : Number ;
        function get_targetDest() : Number ;
        function resetTo(index : int) : void ;
        function travelTo(index : int) : void ;
        function stopAt(index : int) : void ;
        function missStopAt(index : int) : void ;
        function setMaxSpeed(maxSpeed : Number) : void ;
        function setPickupTimespans(accelSpan : Number,brakeSpan : Number) : void ;
        function setupEasingFunctions(powerIndex : int) : void ;
        function update() : void ;
        function setCruisingSpeed(speed : Number) : void ;
        function getCurrentVelocity():Number;
        function getMaxSpeed():Number;
    }


     class SceneModel implements IBGTrain{
        public function SceneModel() : void {
            this.calcPickupTime();
            this.setPickupTimespans(3,3);
        }
        public function getCurrentVelocity():Number {
            return _curVelocity;
        }
        protected var _curLoc : Number = 0;
        protected var _targetDest : Number = 0;
        public function get targetDest() : Number { return get_targetDest(); }
        public function set targetDest( __v : Number ) : void { $targetDest = __v; }
        protected var $targetDest : Number;
        public function get_targetDest() : Number {
            return this._targetDest;
        }
        public function getMaxSpeed():Number {
            return _maxSpeed;
        }
        
        protected var _reseting : Boolean = true;
        protected var _cruisingSpeed : Number = 1;
        protected var _maxSpeed : Number = 3;
        protected var _isStarted : Boolean = false;
        protected var _startIndex : Number = -1;
        protected var _tweenProgress : Number = 0;
        protected var _tweenDuration : Number = 0;
        protected var _pickupTime : Number;
        protected var _pickupTimeDiff : Number;
        protected var _pickupTimeDistCovered : Number;
        protected function calcPickupTime() : void {
            this._pickupTime = (this.easeFuncs.deriativeGetX)(this._maxSpeed);
            this._pickupTimeDistCovered = (this.easeFuncs.distCovered)(this._pickupTime);
            this._pickupTimeDiff = this._pickupTime - this._pickupTimeDistCovered / this._maxSpeed;
        }
        
        public var easeFuncs : EaseFunctions = EaseFunctions.create(2);
        public function setupEasingFunctions(powerIndex : int) : void {
            this.easeFuncs = EaseFunctions.create(powerIndex);
            this.calcPickupTime();
        }
        
        protected var pickupTimeSpan : Number = 1;
        protected var pickdownTimeSpan : Number = 1;
        protected var pickupAndDownMidpointRatio : Number = .5;
        public function setPickupTimespans(accelSpan : Number,brakeSpan : Number) : void {
            this.pickupTimeSpan = accelSpan;
            this.pickdownTimeSpan = brakeSpan;
            this.pickupAndDownMidpointRatio = this.pickupTimeSpan / (this.pickupTimeSpan + this.pickdownTimeSpan);
        }
        
        protected function get pickupUnitTimeLength() : Number { return get_pickupUnitTimeLength(); }
        protected function set pickupUnitTimeLength( __v : Number ) : void { $pickupUnitTimeLength = __v; }
        protected var $pickupUnitTimeLength : Number;
        public function get_pickupUnitTimeLength() : Number {
            return this.pickupTimeSpan * 60;
        }
        
        protected function get pickdownUnitTimeLength() : Number { return get_pickdownUnitTimeLength(); }
        protected function set pickdownUnitTimeLength( __v : Number ) : void { $pickdownUnitTimeLength = __v; }
        protected var $pickdownUnitTimeLength : Number;
        public function get_pickdownUnitTimeLength() : Number {
            return this.pickdownTimeSpan * 60;
        }
        
        protected function get pickupTimeDur() : Number { return get_pickupTimeDur(); }
        protected function set pickupTimeDur( __v : Number ) : void { $pickupTimeDur = __v; }
        protected var $pickupTimeDur : Number;
        public function get_pickupTimeDur() : Number {
            return this._pickupTime * 60 * this.pickupTimeSpan;
        }
        
        protected function get pickdownTimeDur() : Number { return get_pickdownTimeDur(); }
        protected function set pickdownTimeDur( __v : Number ) : void { $pickdownTimeDur = __v; }
        protected var $pickdownTimeDur : Number;
        public function get_pickdownTimeDur() : Number {
            return this._pickupTime * 60 * this.pickdownTimeSpan;
        }
        
        protected function get totalPickupAndDownTimeDur() : Number { return get_totalPickupAndDownTimeDur(); }
        protected function set totalPickupAndDownTimeDur( __v : Number ) : void { $totalPickupAndDownTimeDur = __v; }
        protected var $totalPickupAndDownTimeDur : Number;
        public function get_totalPickupAndDownTimeDur() : Number {
            return this.get_pickupTimeDur() + this.get_pickdownTimeDur();
        }
        
        public function isBlendAccelBrake() : Boolean {
            return this._pickupTimeDistCovered * this.pickupTimeSpan + this._pickupTimeDistCovered * this.pickdownTimeSpan >= this._targetDest - this._startIndex;
        }
        
        public function isBlendAccelBrake2() : Boolean {
            return this.get_totalPickupAndDownTimeDur() >= this._tweenDuration;
        }
        
        public function resetTo(index : int) : void {
            this._reseting = true;
            this._targetDest = index;
        }
        
        protected var _forceStop : Boolean = false;
        protected var _curVelocity:Number;
        public function get currentPosition() : Number { return get_currentPosition(); }
        public function set currentPosition( __v : Number ) : void { $currentPosition = __v; }
        protected var $currentPosition : Number;
        public function get_currentPosition() : Number {
            return this._curLoc;
        }
        
        protected var _startTime : Number = -1;
        public function travelTo(index : int) : void {
            if(!this._isStarted) {
                this._targetDest = index;
                this._isStarted = true;
                var tarIndex : Number = Std._int(this._curLoc);
                this._startTime = getTimer() / 1000;
                this._startIndex = tarIndex;
                this._tweenProgress = 0;
                this._tweenDuration = (index - this._startIndex) * 60 / this._maxSpeed + this._pickupTimeDiff * this.pickupTimeSpan * 60 + this._pickupTimeDiff * this.pickdownTimeSpan * 60;
            }
            else {
                if(this._braking) {
                    var tarLoc : Number = this._tweenProgress - this._tweenDuration + this.get_pickdownUnitTimeLength();
                    var xRatio : Number = tarLoc /= this.get_pickdownUnitTimeLength();
                    tarLoc = (this.easeFuncs.distCovered_Out)(tarLoc);
                    tarLoc *= this.pickdownTimeSpan;
                    tarLoc += this._targetDest - this.pickdownTimeSpan;
                    this._curLoc = tarLoc;
                    xRatio = 1 - xRatio;
                    var tarIndex1 : Number = tarLoc -= (this.easeFuncs.distCovered)(xRatio) * this.pickupTimeSpan;
                    this._startIndex = tarLoc;
                    this._tweenProgress = xRatio * this.get_pickupUnitTimeLength();
                    this._startTime = getTimer()/1000 - this._tweenProgress / 60;
                    this._targetDest = index;
                }
                else {
                    this._targetDest = index;
                    
                };
                this._tweenDuration = (index - this._startIndex) * 60 / this._maxSpeed + this._pickupTimeDiff * this.pickupTimeSpan * 60 + this._pickupTimeDiff * this.pickdownTimeSpan * 60;
            };
            if(this.isBlendAccelBrake()) {
                var y : Number = this._targetDest - this._startIndex;
                this._tweenDuration = (this.easeFuncs.distCoveredGetX)(y / this.pickupTimeSpan * this.pickupAndDownMidpointRatio) * 60 * this.pickupTimeSpan + (this.easeFuncs.distCoveredGetX)(y / this.pickdownTimeSpan * (1 - this.pickupAndDownMidpointRatio)) * 60 * this.pickdownTimeSpan;
            }
        }
        
        public function stopAt(index : int) : void {
            this._targetDest = index;
        }
        
        public function missStopAt(index : int) : void {
            if(this._curLoc <= index + .75) this._targetDest = index + .75;
            else this._targetDest = index;
        }
        
        public function setMaxSpeed(maxSpeed : Number) : void {
            this._maxSpeed = maxSpeed;
            this.calcPickupTime();
        }
        
        public function setCruisingSpeed(speed : Number) : void {
            this._cruisingSpeed = speed;
        }
        
        public var movingState : BGTrainState = BGTrainState.STOPPED;
        protected var _braking : Boolean = true;
        public function update() : void {
            if(this._isStarted) {
                this._tweenProgress = (getTimer()/1000 - this._startTime) * 60;
                if(this._tweenProgress > this._tweenDuration) this._tweenProgress = this._tweenDuration;
                this._braking = false;
                var tarLoc : Number = 0;
                var exceed : Boolean = this.isBlendAccelBrake();
                var exceed2 : Boolean = this.isBlendAccelBrake2();
                
                var exceedBreaking : Boolean = false;
                if(exceed) exceedBreaking = this._tweenProgress >= this._tweenDuration * this.pickupAndDownMidpointRatio;
                if(exceed && !exceedBreaking || !exceed && this._tweenProgress < this.get_pickupTimeDur()) {
                
                    tarLoc = this._tweenProgress / this.get_pickupUnitTimeLength();
                    _curVelocity = this.easeFuncs.deriative(tarLoc);
                    tarLoc = (this.easeFuncs.distCovered)(tarLoc);
                    tarLoc *= this.pickupTimeSpan;
                    tarLoc += this._startIndex;
                    this.movingState = BGTrainState.ACCEL(exceed);
                }
                else if(exceed && exceedBreaking || !exceed && this._tweenProgress >= this._tweenDuration - this.get_pickdownTimeDur()) {
                    this._braking = true;
                    tarLoc = this._tweenProgress - this._tweenDuration + this.get_pickdownUnitTimeLength();
                    tarLoc /= this.get_pickdownUnitTimeLength();
                    _curVelocity =  easeFuncs.deriative_Out(tarLoc);
                    tarLoc = (this.easeFuncs.distCovered_Out)(tarLoc);
                
                  
                    
                    tarLoc *= this.pickdownTimeSpan;
                    tarLoc += this._targetDest - this.pickdownTimeSpan;
                    this.movingState = BGTrainState.BRAKING(exceed);
                }
                else if(!exceed) {
                    tarLoc = CSMath.lerp(this._startIndex + this._pickupTimeDistCovered * this.pickupTimeSpan,this._targetDest - this._pickupTimeDistCovered * this.pickdownTimeSpan,(this._tweenProgress - this.get_pickupTimeDur()) / (this._tweenDuration - this.get_totalPickupAndDownTimeDur()));
                    this.movingState = BGTrainState.SPEEDING;
                    this._curVelocity = this._maxSpeed;
                }
                this._curLoc = tarLoc;
                if(this._tweenProgress >= this._tweenDuration) {
                    this._tweenProgress = this._tweenDuration;
                    this._isStarted = false;
                }
            }
            else {
                this.movingState = BGTrainState.STOPPED;
                this._curVelocity = 0;
            }
            if(this._forceStop) {
                this._forceStop = false;
                this._isStarted = false;
                this._curVelocity = 0;
                this.movingState = BGTrainState.STOPPED;
            }
        }
        
        static protected var PUSH_FORWARD_ERROR : Number = .75;
        static public function main() : void {
        }
        
        static protected var unitTimeLength : Number = 60;
    }


class CSMath {
        static public function lerp(n0 : Number,n1 : Number,p : Number) : Number {
            return n0 * (1 - p) + n1 * p;
        }
        
        static public function rnd(min : Number,max : Number) : Number {
            return min + Math.random() * (max - min);
        }
        
    }



class EaseFunctions {
       public function EaseFunctions() : void {
        }
        
        public var distCovered : Function;
        public var distCovered_Out : Function;
        public var distCoveredGetX : Function;
        public var deriative : Function;
        public var deriative_Out : Function;
        public var deriativeGetX : Function;
        static public function linearDistCovered(t : Number) : Number {
            return t;
        }
        
        static public function linearDistCoveredGetX(offset : Number) : Number {
            return offset;
        }
        
        static public function linearDeriative(x : Number) : Number {
            return 1;
        }
        
        static public function linearDeriativeGetX(v : Number) : Number {
            return 0;
        }
        
        static public function quadraticDistCovered(t : Number) : Number {
            return t * t;
        }
        
        static public function quadraticDistCovered_Out(t : Number) : Number {
            return t * (2 - t);
        }
        
        static public function quadraticDistCoveredGetX(offset : Number) : Number {
            return Math.sqrt(offset);
        }
        
        static public function quadraticDeriative(x : Number) : Number {
            return 2 * x;
        }
        
        static public function quadraticDeriative_Out(x : Number) : Number {
            return 2 - 2 * x;
        }
        
        static public function quadraticDeriativeGetX(v : Number) : Number {
            return v / 2;
        }
        
        static public function cubicDistCovered(t : Number) : Number {
            return t * t * t;
        }
        
        static public function cubicDistCovered_Out(t : Number) : Number {
            return --t * t * t + 1;
        }
        
        static public function cubicDistCoveredGetX(offset : Number) : Number {
            return Math.pow(offset,0.33333333333333331);
        }
        
        static public function cubicDeriative(x : Number) : Number {
            return 3 * x * x;
        }
        
        static public function cubicDeriative_Out(x : Number) : Number {
            return 3 * x * x - 6 * x + 3;
        }
        
        static public function cubicDeriativeGetX(v : Number) : Number {
            return Math.sqrt(v / 3);
        }
        
        static public function quarticDistCovered(t : Number) : Number {
            return t * t * t * t;
        }
        
        static public function quarticDistCovered_Out(t : Number) : Number {
            return 1 - --t * t * t * t;
        }
        
        static public function quarticDistCoveredGetX(offset : Number) : Number {
            return Math.pow(offset,0.25);
        }
        
        static public function quarticDeriative(x : Number) : Number {
            return 4 * x * x * x;
        }
        
        static public function quarticDeriative_Out(x : Number) : Number {
            return -4 * x * x * x + 12 * x * x - 12 * x + 4 * x;
        }
        
        static public function quarticDeriativeGetX(v : Number) : Number {
            return Math.pow(v / 4,0.33333333333333331);
        }
        
        static public function quinticDistCovered(t : Number) : Number {
            return t * t * t * t * t;
        }
        
        static public function quinticDistCovered_Out(t : Number) : Number {
            return 1 + --t * t * t * t * t;
        }
        
        static public function quinticDistCoveredGetX(offset : Number) : Number {
            return Math.pow(offset,0.2);
        }
        
        static public function quinticDeriative(x : Number) : Number {
            return 5 * x * x * x * x;
        }
        
        static public function quinticDeriative_Out(x : Number) : Number {
            return 5 * x * x * x * x - 20 * x * x * x + 30 * x * x - 20 * x + 5;
        }
        
        static public function quinticDeriativeGetX(v : Number) : Number {
            return Math.pow(v / 5,0.25);
        }
        
        static public var LINEAR : int = 0;
        static public var QUADRATIC : int = 1;
        static public var CUBIC : int = 2;
        static public var QUARTIC : int = 3;
        static public var QUINTIC : int = 4;
        static public function create(powerIndex : int) : EaseFunctions {
            var me : EaseFunctions = new EaseFunctions();
            switch(powerIndex) {
            case 0:
            {
                me.distCovered = EaseFunctions.linearDistCovered;
                me.distCovered_Out = EaseFunctions.linearDistCovered;
                me.distCoveredGetX = EaseFunctions.linearDistCoveredGetX;
                me.deriative = EaseFunctions.linearDeriative;
                me.deriative_Out = EaseFunctions.linearDeriative;
                me.deriativeGetX = EaseFunctions.linearDeriativeGetX;
            }
            break;
            case 1:
            {
                me.distCovered = EaseFunctions.quadraticDistCovered;
                me.distCovered_Out = EaseFunctions.quadraticDistCovered_Out;
                me.distCoveredGetX = EaseFunctions.quadraticDistCoveredGetX;
                me.deriative = EaseFunctions.quadraticDeriative;
                me.deriative_Out = EaseFunctions.quadraticDeriative_Out;
                me.deriativeGetX = EaseFunctions.quadraticDeriativeGetX;
            }
            break;
            case 2:
            {
                me.distCovered = EaseFunctions.cubicDistCovered;
                me.distCovered_Out = EaseFunctions.cubicDistCovered_Out;
                me.distCoveredGetX = EaseFunctions.cubicDistCoveredGetX;
                me.deriative = EaseFunctions.cubicDeriative;
                me.deriative_Out = EaseFunctions.cubicDeriative_Out;
                me.deriativeGetX = EaseFunctions.cubicDeriativeGetX;
            }
            break;
            case 3:
            {
                me.distCovered = EaseFunctions.quarticDistCovered;
                me.distCovered_Out = EaseFunctions.quarticDistCovered_Out;
                me.distCoveredGetX = EaseFunctions.quarticDistCoveredGetX;
                me.deriative = EaseFunctions.quarticDeriative;
                me.deriative_Out = EaseFunctions.quarticDeriative_Out;
                me.deriativeGetX = EaseFunctions.quarticDeriativeGetX;
            }
            break;
            case 4:
            {
                me.distCovered = EaseFunctions.quinticDistCovered;
                me.distCovered_Out = EaseFunctions.quinticDistCovered_Out;
                me.distCoveredGetX = EaseFunctions.quinticDistCoveredGetX;
                me.deriative = EaseFunctions.quinticDeriative;
                me.deriative_Out = EaseFunctions.quinticDistCovered_Out;
                me.deriativeGetX = EaseFunctions.quinticDeriativeGetX;
            }
            break;
            default:
           // if(powerIndex > 0) (haxe.Log._trace)("Warning:: no easing functions case found",{ fileName : "EaseFunctions.hx", lineNumber : 193, className : "EaseFunctions", methodName : "create"});
            break;
            };
            return me;
        }
        
    }


    
         class GameSettings {
        public function GameSettings() : void {
        }
        
        public var minTurnTime : Number = 1;
        public var penaltyDelayMs : Number = 0;
        static public var SHARED_FPS : int = 60;
        static protected function delayInSeconds(ms : Number) : Number {
            return ms / 1000;
        }
        
    }