In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

ひらりとかわす程度の能力

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

// forked from checkmate's Saqoosha challenge for professionals
package {
    import com.flashdynamix.utils.SWFProfiler;
    
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.Graphics;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.filters.BitmapFilter;
    import flash.filters.GradientBevelFilter;
    import flash.filters.BlurFilter;
    import flash.utils.Timer;
    import flash.utils.getTimer;
    import flash.geom.Point;
    import flash.geom.Matrix;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.display.BlendMode;

    [SWF(width=465, height=465, backgroundColor=0x000000, frameRate=60)]
    public class Hirari extends Sprite {
        private const TEXT : String = "ひらり";
        
        private var _bullets : Array;
        private var _ct : int;
        private var _myx : Point;
        private var _myxs : Array;
        private var _myv : Point;
        private var _nhit : int;
        private const LIMXY : Number = 4.0;
        private const LIMVY : Number = 0.1;
        private const LIMT : Number = 30.0;
        private const NSAMPLE : int = 100;
        private const SCALEX : Number = 50;
        private const OFFSETX : Number = 465 / 2;
        private const SCALEY : Number = 50;
        private const OFFSETY : Number = 465 / 2;
        private const R_BULLET : Number = 20.0;
        private const R_ME : Number = 16.0;
        private const INFD : Number = Math.pow((R_BULLET + R_ME) / SCALEX, 2);
        
        private const SPLITX : int = 10;
        private const SPLITY : int = 2;
        
        private var _tf : TextField;
        private var _space : BitmapData;
        private var _bgspace : BitmapData;
        private var _shapeself : Shape;
        
        private var _bmdbullet : BitmapData;
        
        private var _indices : Vector.<int>;
        private var _uvtData : Vector.<Number>;
        private var _bmd : BitmapData;
        
        private const P0 : Point = new Point(0, 0);
        private const WEAKBLUR : BitmapFilter = new BlurFilter(2.0, 2.0);
        
        public function Hirari() {
            Wonderfl.capture_delay(5);
            SWFProfiler.init(this);
            
            // 宇宙
            _space = new BitmapData(465, 465, false, 0x000000);
            var bmpspace : Bitmap = new Bitmap(_space);
            addChild(bmpspace);
            
            var shs : Shape = new Shape();
            var mat : Matrix = new Matrix();
            mat.createGradientBox(465, 465, 0, 0, 0);
            shs.graphics.beginGradientFill(
                "linear",
                [0x333377, 0x000000],
                [1, 1],
                [0, 255],
                mat
                );
            shs.graphics.drawRect(0, 0, 465, 465);
            shs.graphics.endFill();
            _bgspace = new BitmapData(465, 465, false, 0x000000);
            _bgspace.draw(shs);
                            
            _shapeself = new Shape();
            
            // 弾描画
            var bevel : BitmapFilter = new GradientBevelFilter(4.0, 45, [0xffffff, 0x0000ff], [1.0, 1.0], [70, 255], 4.0, 4.0, 1, 2, "inner");
            var sh : Shape = new Shape();
            var g : Graphics = sh.graphics;
            g.lineStyle(1.0, 0x999999);
            g.beginFill(0xeeeeee);
            g.drawCircle(R_BULLET, R_BULLET, R_BULLET);
            g.endFill();
            _bmdbullet = new BitmapData(R_BULLET * 2, R_BULLET * 2, true, 0x00000000);
            _bmdbullet.draw(sh);
            _bmdbullet.applyFilter(_bmdbullet, _bmdbullet.rect, P0, bevel);
            _bmdbullet.applyFilter(_bmdbullet, _bmdbullet.rect, P0, WEAKBLUR);

            // ひらり描画用データ
            var tfmt : TextFormat = new TextFormat("Arial, Helvetica, _sans", 50);
            _bmd = textToBitmapData(TEXT, tfmt);
            
            _indices = new Vector.<int>();
            _uvtData = new Vector.<Number>();
            
            var i : int, j : int;
            _myxs = [];
            for(i = 0;i < SPLITX;i++)_myxs.push(0);
            
            for(j = 0;j < SPLITY;j++){
                for(i = 0;i < SPLITX;i++){
                    _uvtData.push(i / (SPLITX - 1));
                    _uvtData.push(j / (SPLITY - 1));
                }
            }
            for(j = 0;j < SPLITY - 1;j++){
                for(i = 0;i < SPLITX - 1;i++){
                    _indices.push(j * SPLITX + i);
                    _indices.push(j * SPLITX + i + 1);
                    _indices.push((j + 1) * SPLITX + i);
                    
                    _indices.push(j * SPLITX + i + 1);
                    _indices.push((j + 1) * SPLITX + i);
                    _indices.push((j + 1) * SPLITX + i + 1);
                }
            }
            
            _myx = new Point(0, 0);
            _myv = new Point(0, 0);
            _bullets = [];
            _ct = 0;
            _nhit = 0;
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            
            // デバッグ用
            _tf = new TextField();
            _tf.autoSize = "left";
            _tf.text = "" + _bmd.width + "\t" + _bmd.height;
            _tf.textColor = 0xffffff;
            _tf.borderColor = 0xffffff;
            _tf.border = true;
 //           addChild(_tf);
        }
        
        private function textToBitmapData(text : String, tfmt : TextFormat) : BitmapData
        {
            var tf : TextField = new TextField();
            tf.defaultTextFormat = tfmt;
            tf.textColor = 0xeeeeee;
            tf.autoSize = "left";
            tf.text = text;
            var bmd : BitmapData = new BitmapData(tf.width, tf.height, false, 0x000000);
            bmd.draw(tf);
            return bmd;
        }
        
        private function onEnterFrame(e : Event) : void
        {
            draw();
            judge();
            
            _ct++;
            if(_ct % 10 == 0){
                addBullet();
            }
            
            if(_ct % 1 == 0){
            // TODO verbose
            var maxdv : Number = LIMVY;
            var mindv : Number = -LIMVY;
            // 上下に行きすぎないよう定義域を制限
            if(_myv.y > 0){
                maxdv = Math.min((LIMXY - _myx.y) / LIMT, LIMVY);
            }else{
                mindv = Math.max((-LIMXY - _myx.y) / LIMT, -LIMVY);
            }
            
            // quasi-MC
            var minav : Number = Number.MAX_VALUE;
            var mina : Number = 0;
            var tail : Point = new Point(SPLITX * 8 / SCALEX, _myxs[_myxs.length - 1]);
            for(var j : int = 0;j < NSAMPLE;j++){
                var a : Number = mindv + j * (maxdv - mindv) / NSAMPLE;
                var av : Number = calcAvoidance(a, _myx) + calcAvoidance(a, tail);
                if(av < minav){
                    minav = av;
                    mina = a;
                }
            }
            _myv.y += mina;
            }
            
            // step
            _myxs.unshift(_myx.y);
            _myxs.pop();
            _myx.x += _myv.x;
            _myx.y += _myv.y;
            
            for each(var b : Bullet in _bullets){
                b.x.x += b.v.x;
                b.x.y += b.v.y;
            }
        }
        
        // 弾削除
        private function removeBullet(i : int) : void
        {
            if(i < _bullets.length - 1){
                _bullets[i] = _bullets.pop();
                i--;
            }else{
                _bullets.pop();
            }
        }
        
        // 当たり判定。ひらりの先端部分だけ
        private function judge() : void
        {
            for(var i : int = 0;i < _bullets.length;i++){
                var b : Bullet = _bullets[i];
                if(
                    (b.x.x - _myx.x) * (b.x.x - _myx.x) + 
                    (b.x.y - _myx.y) * (b.x.y - _myx.y)
                    < INFD){
                        _nhit++;
                        removeBullet(i);
                        continue;
                }
                if(b.x.x < -5.0 || b.x.x > 5.0 || b.x.y < -5.0 || b.x.y > 5.0){
                    removeBullet(i);
                }
            }
        }
        
        // 描画
        private function draw() : void
        {
            _space.lock();
//            _space.fillRect(_space.rect, 0x000000);
            _space.copyPixels(_bgspace, _bgspace.rect, P0);
            
            var g : Graphics = _shapeself.graphics;
            g.clear();
            
            // self
            /*
            g.lineStyle(1.0, 0x333399);
            g.beginFill(0x3333ff);
            g.drawCircle(_myx.x * SCALEX + OFFSETX, _myx.y * SCALEY + OFFSETY, 5);
            g.endFill();
            */
            
            var i : int, j : int;
            var vertices : Vector.<Number> = new Vector.<Number>();
            for(j = 0;j < SPLITY;j++){
                for(i = 0;i < SPLITX;i++){
                    vertices.push(OFFSETX + i * 8);
                    vertices.push(OFFSETY + (j - SPLITY / 4) * 32 + _myxs[i] * SCALEY); // XXX
                }
            }
            
            g.beginBitmapFill(_bmd);
            g.drawTriangles(vertices, _indices, _uvtData);
            g.endFill();
            _space.draw(_shapeself, null, null, BlendMode.ADD);
            
            
            // bullets
            for each(var b : Bullet in _bullets){
                _space.copyPixels(_bmdbullet, _bmdbullet.rect,
                    new Point(b.x.x * SCALEX + OFFSETX - R_BULLET, b.x.y * SCALEY + OFFSETY - R_BULLET));
            }
            
            _space.unlock();
            _tf.text = "time : " + _ct + "\nhit : " + _nhit;
        }
        
        // 弾追加
        private function addBullet() : void
        {
            var x : Point = new Point(Math.random() * 1 - 5, Math.random() * 10 - 5);
            var v : Point = new Point(Math.random() * 0.05 + 0.05, Math.random() * 0.2 - 0.1);
            var b : Bullet = new Bullet();
            b.x = x;
            b.v = v;
            _bullets.push(b);
        }
        
        // 回避関数を計算。以下関連関数
        private function calcAvoidance(dvy : Number, cent : Point) : Number
        {
            var vy : Point = new Point(0, _myv.y + dvy);
            
            var ft : Number = Math.max((LIMXY - cent.y) / vy.y, (-LIMXY - cent.y) / vy.y);
            if(ft <= 20){
                ret += 100 / ft; // 向こう見ずな急移動防止
            }
            
            var ret : Number = 0.0;
            for each(var b : Bullet in _bullets){
                var vv : Point = b.v.subtract(vy);
                var xx : Point = b.x.subtract(cent);
                var t : Number = mint(xx, vv);
                if(t >= 0){
                    ret += f(mind2(xx, vv, t)) * 100 / (t + 10.0);
                }
            }
            
            // 中央に誘導するヒューリスティクス
            var iv : Number = -cent.y * 0.03;
            ret += (iv - vy.y) * (iv - vy.y) * 0.1;
//            ret += dvy * dvy * 0.1;
            return ret;
        }
        
        private function mint(x : Point, v : Point) : Number
        {
            if(v.x * v.x + v.y * v.y < 0.0001){
                return 0.0;
            }
            return -(x.x * v.x + x.y * v.y) / (v.x * v.x + v.y * v.y);
        }
        
        private function mind2(x : Point, v : Point, t : Number) : Number
        {
            var xx : Number = x.x + v.x * t;
            var yy : Number = x.y + v.y * t;
            return xx * xx + yy * yy;
        }
        
        private function f(d2 : Number) : Number
        {
            return d2 < INFD ? 1 : 0;
        }
    }
}

import flash.geom.Point;

class Bullet
{
    public var x : Point;
    public var v : Point;
}