ひらりとかわす程度の能力
/**
* 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;
}