// forked from okoi's forked from: forked from: 某スペルカードの一部風 目コピ処理 - より本物らしく // forked from okoi's forked from: 某スペルカードの一部風 目コピ処理 - より本物らしく // forked from okoi's 某スペルカードの一部風 目コピ処理 // // 緑色の弾しか見ないようにして、通常より1段深く探索しています。 // // uwiさんが改良してくれたのを更に改良しました。 // http://wonderfl.net/code/f3e75f89a0423a830d4f1a7e85f4fd0af4a8fbb3 // // 東風谷早苗スペルカード「グレイソーマタージ」風処理 // 前回とは違い☆のスライド処理も入れ、より本物らしくしました。 // かなり目コピなんで計算方法はムリがあるかも // // 表示レイヤーは考慮していないです。余計なパラメータもあるかと思いますw // クリックすると新たに作成します package { import flash.display.Sprite; import flash.display.Shape; import flash.display.BitmapData; import flash.display.Bitmap; import flash.display.Graphics; import flash.events.Event; import flash.events.MouseEvent; import net.hires.debug.*; import flash.text.TextField; [SWF(backgroundColor = "0x000000", frameRate = "60")] /** * * @author okoi */ public class Main extends Sprite { private var patternList:Array = new Array(); private var _bmdBulletRed : BitmapData; private var _bmdBulletBlue : BitmapData; private var _canvas : BitmapData; private var _d : Dodger2D; private var _bullets : Array = []; 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); // entry point // MouseDown(null); var s : Shape = new Shape(); var g : Graphics = s.graphics; g.beginFill(0xff5555); g.drawCircle(5, 5, 5); g.endFill(); g.beginFill(0xffffff, 0.5); g.drawCircle(5, 5, 3); g.endFill(); _bmdBulletRed = new BitmapData(10, 10, true, 0x00000000); _bmdBulletRed.draw(s); g.clear(); g.beginFill(0x5555ff); g.drawCircle(5, 5, 5); g.endFill(); g.beginFill(0xffffff, 0.5); g.drawCircle(5, 5, 3); g.endFill(); _bmdBulletBlue = new BitmapData(10, 10, true, 0x00000000); _bmdBulletBlue.draw(s); _canvas = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000); addChild(new Bitmap(_canvas)); addEventListener(Event.ENTER_FRAME, EnterFrame ); stage.addEventListener(MouseEvent.MOUSE_DOWN, MouseDown); g.clear(); g.beginFill(0xffffff); g.drawCircle(4, 4, 4); g.endFill(); var self : BitmapData = new BitmapData(8, 8, true, 0x00000000); self.draw(s); _d = new Dodger2D(self, _canvas, VelocityStrokeDodgeAlgorithm2D.run); _d.xx = 465 / 2; _d.xy = 300; // addChild(_tf); // _tf.textColor = 0xffffff; // addChild(new Stats()); } private var _tf : TextField = new TextField(); private function EnterFrame(event:Event):void { var i:int = 0; var b : Bullet; for ( i = 0; i < patternList.length; i++ ) { b = patternList[i].Run(); if ( b != null ) { _bullets.push(b); } } for ( i = patternList.length - 1; i >= 0; i-- ) { if ( patternList[i].isEnd() ) { // 待機リストから移動リストへ // moveBullet = moveBullet.concat(patternList[i].waitBullet); for each(b in patternList[i].waitBullet){ b.t = 0; } patternList.splice( i, 1 ); } } // 弾移動 // やっぱり無理があるなぁ・・Bulletにkind属性とかつければすんなりいけそうな for ( i = 0; i < _bullets.length; i++ ) { b = _bullets[i]; if(b.next != null){ if(b.t < 50){ b.step(1 - b.t/50); if(b.t >= 50){ _bullets[i] = b.next; _bullets[i].xx = b.xx; _bullets[i].xy = b.xy; } } }else{ b.step(Math.min(b.t*0.02, 1)); if ( b.xx < -50 || b.xx > stage.stageWidth + 50 || b.xy < -50 || b.xy > stage.stageHeight + 50 ) { if(i == _bullets.length - 1){ _bullets.pop(); }else{ _bullets[i] = _bullets.pop(); i--; } } } } // 描画 _canvas.lock(); _canvas.fillRect(_canvas.rect, 0x000000); for each(b in _bullets){ b.draw(_canvas); } var val : int = _d.run(2, {maxxx : 460, maxxy : 460, minxx : 5, minxy : 5, bullets : _bullets, selfr : 3, basex : 465 / 2, basey : 465 / 2}, [[0, 0], [-3, 0], [3, 0], [0, -3], [0, 3], [2, 2], [-2, 2], [-2, -2], [2, -2]], 50); _d.step(); _d.paint(); _canvas.unlock(); } private function MouseDown(event:MouseEvent):void { // 小さい☆ patternList.push( new Pattern(stage.mouseX, stage.mouseY, false, 50, _bmdBulletRed, (270 + 72 * 0), 3 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, false, 50, _bmdBulletRed, (270 + 72 * 1), 3 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, false, 50, _bmdBulletRed, (270 + 72 * 2), 3 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, false, 50, _bmdBulletRed, (270 + 72 * 3), 3 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, false, 50, _bmdBulletRed, (270 + 72 * 4), 3 ) ); // 大きい☆ patternList.push( new Pattern(stage.mouseX, stage.mouseY, true, 100, _bmdBulletBlue, (270 + 72 * 0) + 180, 5 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, true, 100, _bmdBulletBlue, (270 + 72 * 1) + 180, 5 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, true, 100, _bmdBulletBlue, (270 + 72 * 2) + 180, 5 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, true, 100, _bmdBulletBlue, (270 + 72 * 3) + 180, 5 ) ); patternList.push( new Pattern(stage.mouseX, stage.mouseY, true, 100, _bmdBulletBlue, (270 + 72 * 4) + 180, 5 ) ); } } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// import flash.display.Sprite; import flash.geom.Point; //----------------------------- // 弾幕パターンクラス class Pattern { private var reverse:Boolean = false; // 反転フラグ private var starSize:Number = 150; // ☆サイズ private var bmd:BitmapData; private var slideAngle:Number = 0; // 弾スライド時に使用 private var slideSpeed:Number = 0; // 弾スライド時に使用 private var end:Boolean = false; private var count:int = 0; private var defX:int = 0; private var defY:int = 0; private var target:Array = new Array(); private static const PATH_OBJ_NUM:int = 20; // 1辺に出す弾の数 private static const TARGET_NUM:int = 5; private static const TARGET_ANGLE:Array = [ 270 + 72 * 3, 270 + 72 * 1, 270 + 72 * 4, 270 + 72 * 2, 270 ]; // パスの目標地点の角度 private static const TARGET_ANGLE2:Array = [ 270 + 72 * 2, 270 + 72 * 4, 270 + 72 * 1, 270 + 72 * 3, 270 ]; // パスの目標地点の角度 public var waitBullet:Array = new Array(); // 保持用バッファ public function Pattern( _gx:int = 0, _gy:int = 0, _rev:Boolean = false, _starSize:Number = 80, _bmd:BitmapData = null, _slideAngle:Number = 0, _slideSpeed:Number = 0 ) { count = 0; defX = _gx; defY = _gy; reverse = _rev; starSize = _starSize; bmd = _bmd; slideAngle = _slideAngle; slideSpeed = _slideSpeed; for ( var i:int = 0; i < 5; i++ ) { var angle:Number = TARGET_ANGLE[i]; if ( reverse ) angle = TARGET_ANGLE2[i] + 180; // 反転 else angle = TARGET_ANGLE[i]; target[i] = new Point( Math.cos( angle * Math.PI / 180 ) * starSize, Math.sin( angle * Math.PI / 180 ) * starSize ); } } /** * 弾発生処理 * @return */ public function Run() : Bullet { var targetNo:int = int(count / PATH_OBJ_NUM); var targetRate:int = int(count % PATH_OBJ_NUM); var p:Point; // 弾の座標を出す p = Point.interpolate( target[targetNo], target[(targetNo+(TARGET_NUM-1))%TARGET_NUM], targetRate / PATH_OBJ_NUM ); // 弾の移動角度を出す var moveAngle : Number = (-count / PATH_OBJ_NUM / TARGET_NUM * 720 + 135) * (reverse ? -1 : 1) * Math.PI / 180; var bullet : Bullet = new Bullet( bmd, p.x + defX, p.y + defY, Math.cos(slideAngle*Math.PI/180)*slideSpeed, Math.sin(slideAngle*Math.PI/180)*slideSpeed ); bullet.next = new Bullet( bmd, p.x + defX, p.y + defY, Math.cos(moveAngle) * 0.8, Math.sin(moveAngle) * 0.8 ); bullet.t = 999; waitBullet.push( bullet ); count++; if ( count == TARGET_NUM * PATH_OBJ_NUM ) end = true; return bullet; } public function isEnd() : Boolean { return end; } } import flash.display.BitmapData; class Bullet2D { public var xx : Number; public var xy : Number; public var vx : Number; public var vy : Number; public var r : Number; } //----------------------------- // 弾クラス class Bullet extends Bullet2D { private var bmd:BitmapData; private var _t:uint = 0; public var next:Bullet = null; public function Bullet(bmd:BitmapData, xx:Number, xy:Number,vx:Number,vy:Number) { this.bmd = bmd; this.xx = xx; this.xy = xy; this.vx = vx; this.vy = vy; this.r = 5; } public function step(c : Number = 1.0):void { xx += vx * c; xy += vy * c; _t++; } public function get t() : uint { return _t;} public function set t(val:uint) : void { _t = val;} public function draw(canvas : BitmapData) : void { canvas.copyPixels(bmd, bmd.rect, new Point(xx - bmd.width / 2, xy - bmd.height / 2)); } } class RangeUtils { public static function intersection(a : Array, b : Array) : Array { if (a == null || b == null) return null; if (a[1] < b[0] || b[1] < a[0]) return null; return [Math.max(a[0], b[0]), Math.min(a[1], b[1])]; } } import flash.geom.Point; import flash.geom.Rectangle; class Dodger2D extends Bullet2D { private var _bmd : BitmapData; private var _parent : BitmapData; private var _algorithm : Function; public function Dodger2D(bmd : BitmapData, parent : BitmapData, algorithm : Function) { _bmd = bmd; _parent = parent; _algorithm = algorithm; } /** * devlop tunnel vision * @param w * @param env * @return */ private function filter(w : Number, env : Object) : Object { var d : Number; var seen : Array = []; for each(var b : Bullet2D in env.bullets) { var ww : Number = w/2 + b.r; var dx0 : Number = b.xx - xx; var dy0 : Number = b.xy - xy; var tr : Array = [0, 100]; if (b.vx != 0) { var tx0 : Number = (ww - dx0) / b.vx; var tx1 : Number = (-ww - dx0) / b.vx; if (tx0 > tx1) { d = tx0; tx0 = tx1; tx1 = d; } tr = RangeUtils.intersection(tr, [tx0, tx1]); } if (b.vy != 0) { var ty0 : Number = (ww - dy0) / b.vy; var ty1 : Number = (-ww - dy0) / b.vy; if (ty0 > ty1) { d = ty0; ty0 = ty1; ty1 = d; } tr = RangeUtils.intersection(tr, [ty0, ty1]); } if (tr != null) { seen.push(b); // coloring for debugging _parent.fillRect(new Rectangle(b.xx - b.r, b.xy - b.r, 2*b.r, 2*b.r), 0x00ff00); } } var ret : * = { }; for (var key : String in env) ret[key] = env[key]; ret.bullets = seen; return ret; } /** * * @param depth * @param env * @param motions {minxx, minxy, maxxx, maxxy, selfr, [bullets], [basex, basey]} * @param width tunnel vision width * @return */ public function run(depth : uint, env : Object, motions : Array, width : uint = 0) : Number { var filtered : Object = width > 0 ? filter(width, env) : env; var ret : Object = _algorithm.apply(null, [xx, xy, depth, filtered, motions]); vx = ret.motion[0]; vy = ret.motion[1]; return ret.time; } public function step() : void { xx += vx; xy += vy; } public function paint() : void { _parent.copyPixels(_bmd, _bmd.rect, new Point(xx - _bmd.width / 2, xy - _bmd.height / 2)); } } class VelocityStrokeDodgeAlgorithm2D { /** * the root of calcSurvivalTime * @param xx * @param xy * @param depth * @param env {minxx, minxy, maxxx, maxxy, selfr, [bullets], [basex, basey]} * @param motions * @param limt * @return */ public static function run(xx : Number, xy : Number, depth : uint, env : *, motions : Array, limt : uint = 100) : Object { var ret : Array = [0.0, 0.0]; var maxval : Number = 0; for each(var m : Array in motions) { var val : Number = calcSurvivalTime(xx, xy, m, 0, depth, env, motions, limt); if (val > maxval) { maxval = val; ret = m; } } if (env.basex && env.basey && env.bullets.length == 0) { var mind2 : Number = Number.MAX_VALUE; for each(m in motions) { var d2 : Number = (xx + m[0] - env.basex) * (xx + m[0] - env.basex) + (xy + m[1] - env.basey) * (xy + m[1] - env.basey); if (d2 < mind2) { mind2 = d2; ret = m; } } } return { motion : ret, time : maxval }; } /** * calculate survival time. * This function is recursive. * @param xx current state of self. (at the time of t) * @param xy * @param motion * @param et elapsed time * @param depth depth remaining * @param env enemies' information etc. * @param motions movable motions * @param limt upper limit of time * @return survival time */ private static function calcSurvivalTime(xx : Number, xy : Number, motion : Array, et : Number, depth : uint, env : * , motions : Array, limt : Number) : Number { var mint : Number = limt - et; var t : Number; var vx : Number = motion[0]; var vy : Number = motion[1]; var r : Number = env.selfr; // collision with wall if (vx > 0) { t = ((env.maxxx - r) - xx) / vx; if (t < mint) mint = t; } if (vx < 0) { t = ((env.minxx + r) - xx) / vx; if (t < mint) mint = t; } if (vy > 0) { t = ((env.maxxy - r) - xy) / vy; if (t < mint) mint = t; } if (vy < 0) { t = ((env.minxy + r) - xy) / vy; if (t < mint) mint = t; } // collision with bullets if(env.bullets){ for each(var b : Bullet2D in env.bullets) { var colr : Number = (r + b.r) * (r + b.r); // collision radius // relative parameter var rxx : Number = xx - (b.xx + b.vx * et); var rxy : Number = xy - (b.xy + b.vy * et); var rvx : Number = vx - b.vx; var rvy : Number = vy - b.vy; if (rxx * rxx + rxy * rxy < colr) { mint = 0; break; } if (rvx * rvx + rvy * rvy > 0.1) { var ct : Number = -(rxx * rvx + rxy * rvy) / (rvx * rvx + rvy * rvy); if (ct <= 0) continue; var rxxt : Number = rxx + ct * rvx; var rxyt : Number = rxy + ct * rvy; var d2 : Number = rxxt * rxxt + rxyt * rxyt; if (d2 < colr) { ct -= Math.sqrt((colr - d2) / (rvx * rvx + rvy * rvy)); if(ct < mint)mint = ct; } } } } mint = Math.floor(mint); if (mint + et == limt) return mint + depth; if(mint >= 2 && depth >= 1){ // recursion var maxval : Number = 0; var tt : int = mint - 1; // move to the edge of collision var newxx : Number = vx * tt + xx; var newxy : Number = vy * tt + xy; for each(var m : Array in motions) { if (m == motion) continue; var val : Number = calcSurvivalTime(newxx, newxy, m, et + tt, depth - 1, env, motions, limt); if (val > maxval) { maxval = val; } } mint += maxval; } return mint; } } 某スペルカードをズルしてみた