某スペルカードをズルしてみた
緑色の弾しか見ないようにして、通常より1段深く探索しています。
uwiさんが改良してくれたのを更に改良しました。
http://wonderfl.net/code/f3e75f89a0423a830d4f1a7e85f4fd0af4a8fbb3
東風谷早苗スペルカード「グレイソーマタージ」風処理
前回とは違い☆のスライド処理も入れ、より本物らしくしました。
かなり目コピなんで計算方法はムリがあるかも
表示レイヤーは考慮していないです。余計なパラメータもあるかと思いますw
クリックすると新たに作成します
/**
* Copyright uwi ( http://wonderfl.net/user/uwi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/bbUO
*/
// 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;
}
}