forked from: シューティングっぽい動きで避ける
マウスカーソルでuwiさんのプログラムと勝負!
マウスカーソルは赤円で表示されます
勝敗判定とかはないので各自心の中で行ってください
/**
* Copyright Nicolas ( http://wonderfl.net/user/Nicolas )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/25aZ
*/
// forked from uwi's シューティングっぽい動きで避ける
// forked from uwi's forked from: avoidance function
// forked from uwi's avoidance function
//マウスカーソルでuwiさんのプログラムと勝負!
//マウスカーソルは赤円で表示されます
//勝敗判定とかはないので各自心の中で行ってください
package {
import com.flashdynamix.utils.SWFProfiler;
import flash.display.*;
import flash.geom.*;
import flash.events.*;
import flash.filters.*;
import flash.text.TextField;
import flash.ui.Mouse;
// frameRate="60"は本気モード
// TODO アルゴリズムの抜けを修正
[SWF(frameRate="30", backgroundColor="#660000")]
public class FlashTest extends Sprite {
private var _bullets : Array;
private var _ct : int;
private var _myx : Point;
private var _nhit : int;
private var _myx2 : Point;
private var _nhit2 : int;
private const R_BULLET : Number = 30.0;
private const R_SELF : Number = 5.0;
private const INFD : Number = Math.pow((R_BULLET + R_SELF), 2);
private var _space : BitmapData;
private var _bmdbullet : BitmapData;
private var _bmdself : BitmapData;
private var _bmdself2 : BitmapData;
private var _tf : TextField;
private var _tf2 : TextField;
private const P0 : Point = new Point(0, 0);
private const WEAKBLUR : BitmapFilter = new BlurFilter(3.0, 3.0);
public function FlashTest() {
Wonderfl.capture_delay(5);
SWFProfiler.init(this);
// 宇宙
_space = new BitmapData(400, 465, false, 0x000000);
var bmpspace : Bitmap = new Bitmap(_space);
addChild(bmpspace);
// 弾描画
var shBullet : Shape = new Shape();
var gb : Graphics = shBullet.graphics;
gb.lineStyle(0.0, 0x999999);
var mat : Matrix = new Matrix();
mat.createGradientBox(R_BULLET * 2, R_BULLET * 2, 0, 0, 0);
gb.beginGradientFill("radial", [0xffffff, 0xaaaaaa], [1, 1], [0x00, 0xff], mat);
gb.drawCircle(R_BULLET, R_BULLET, R_BULLET);
gb.endFill();
_bmdbullet = new BitmapData(R_BULLET * 2, R_BULLET * 2, true, 0x00000000);
_bmdbullet.draw(shBullet);
_bmdbullet.applyFilter(_bmdbullet, _bmdbullet.rect, P0, WEAKBLUR);
// 自機描画(COM)
var shSelf : Shape = new Shape();
var gs : Graphics = shSelf.graphics;
gs.lineStyle(1.0, 0x0000ff);
gs.beginFill(0x3333ff);
gs.drawCircle(R_SELF, R_SELF, R_SELF);
gs.endFill();
_bmdself = new BitmapData(R_SELF * 2, R_SELF * 2, true, 0x00000000);
_bmdself.draw(shSelf);
//自機描画(マウスカーソル)
var shSelf2 : Shape = new Shape();
var gs2 : Graphics = shSelf2.graphics;
gs2.lineStyle(1.0, 0xff0000);
gs2.beginFill(0xff3333);
gs2.drawCircle(R_SELF, R_SELF, R_SELF);
gs2.endFill();
_bmdself2 = new BitmapData(R_SELF * 2, R_SELF * 2, true, 0x00000000);
_bmdself2.draw(shSelf2);
_myx = new Point(200, 400);
_myx2 = new Point(200, 400);
_bullets = [];
_ct = 0;
_nhit = 0;
//addEventListener(Event.ENTER_FRAME, onEnterFrame);
_tf = new TextField();
_tf.autoSize = "left";
_tf.textColor = 0xffffff;
_tf.borderColor = 0xffffff;
_tf.border = true;
_tf.x = 400;
addChild(_tf);
_tf2 = new TextField();
_tf2.text = "Click to start"
_tf2.textColor = 0xffffff;
_tf2.x = 200;
_tf2.y = 200;
addChild(_tf2);
stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
_tf2.visible = false;
Mouse.hide();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
});
}
private var _gct : int = 0; // デバッグ用
private var _ans : int = 0;
private function onEnterFrame(e : Event) : void
{
//画面内にマウスカーソルがあるときのみ位置を更新
if (mouseX >= 0 && mouseX < 400 && mouseY >= 0 && mouseY < 465) {
_myx2.x = mouseX;
_myx2.y = mouseY;
}
draw();
judge();
_ct++;
if(_ct % 3 == 0){
addBullet();
// addBullet();
// addBullet();
}
if(_ct % 3 == 0){
_ans = calcAvoidanceAtRoot(_myx, 1);
}
// step
_myx.x += PTN_MOVE[_ans][0];
_myx.y += PTN_MOVE[_ans][1];
if(_myx.x < 0 || _myx.x >= 400 || _myx.y < 0 || _myx.y >= 465){
_myx.x -= PTN_MOVE[_ans][0];
_myx.y -= PTN_MOVE[_ans][1];
}
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 - _myx2.x) * (b.x.x - _myx2.x) +
(b.x.y - _myx2.y) * (b.x.y - _myx2.y)
< INFD) {
_nhit2++;
removeBullet(i);
continue;
}
if(b.x.x < 0 - R_BULLET || b.x.x > 400 + R_BULLET || b.x.y < 0 - R_BULLET || b.x.y > 465 + R_BULLET){
removeBullet(i);
}
}
}
private function draw() : void
{
_space.lock();
_space.fillRect(_space.rect, 0x000000);
// self
_space.copyPixels(_bmdself, _bmdself.rect,
new Point(_myx.x - R_SELF, _myx.y - R_SELF));
_space.copyPixels(_bmdself2, _bmdself2.rect,
new Point(_myx2.x - R_SELF, _myx2.y - R_SELF));
// bullets
for each(var b : Bullet in _bullets){
_space.copyPixels(_bmdbullet, _bmdbullet.rect,
new Point(b.x.x - R_BULLET, b.x.y - R_BULLET));
}
_space.unlock();
_tf.text = "time : \n" + _ct + "\n\nhit(Red) : \n" + _nhit2 + "\n\nhit(blue) : \n" + _nhit;
}
private function addBullet() : void
{
var x : Point = new Point(Math.random() * 400, 0);
var v : Point = new Point(Math.random() * 8 - 4, Math.random() * 5 + 5);
var b : Bullet = new Bullet();
b.x = x;
b.v = v;
_bullets.push(b);
}
/*
// 低速移動・高速移動
public static const PTN_MOVE : Array = [
[0, 0],
[3, 0], [6, 0],
[0, 3], [0, 6],
[-3, 0], [-6, 0],
[0, -3], [0, -6],
[2, 2], [4, 4],
[-2, 2], [-4, 4],
[-2, -2], [-4, -4],
[2, -2], [4, -4]
];
*/
// 高速移動オンリー
public static const PTN_MOVE : Array = [
[0, 0],
[6, 0],
[0, 6],
[-6, 0],
[0, -6],
[4, 4],
[-4, 4],
[-4, -4],
[4, -4]
];
// 回避アルゴリズム
// @param x 回避者位置
// @param depth 読むパスの深さ
public function calcAvoidanceAtRoot(x : Point, depth : int) : int
{
var i : int;
var t : Number;
var mincs : Array = new Array(PTN_MOVE.length);
// 壁への衝突
for(i = 0;i < PTN_MOVE.length;i++){
var minc : Number = Number.MAX_VALUE;
if(PTN_MOVE[i][0] > 0){
t = (400 - x.x) / PTN_MOVE[i][0];
if(t < minc)minc = t;
}else if(PTN_MOVE[i][0] < 0){
t = (x.x) / -PTN_MOVE[i][0];
if(t < minc)minc = t;
}
if(PTN_MOVE[i][1] > 0){
t = (465 - x.y) / PTN_MOVE[i][1];
if(t < minc)minc = t;
}else if(PTN_MOVE[i][1] < 0){
t = (x.y) / -PTN_MOVE[i][1];
if(t < minc)minc = t;
}
mincs[i] = minc;
}
// 弾への衝突
for each(var b : Bullet in _bullets){
var rx : Point = b.x.subtract(x);
for(i = 0;i < PTN_MOVE.length;i++){
var rv : Point = new Point(
b.v.x - PTN_MOVE[i][0],
b.v.y - PTN_MOVE[i][1]
); // rvはメモ化できそう
t = mint(rx, rv);
if(t > 0){
var d2 : Number = mind2(rx, rv, t);
if(d2 < INFD){
t -= Math.sqrt((INFD - d2) / rv.length);
_gct++;
if(t < mincs[i])mincs[i] = t;
}
}
}
}
var mc : Number;
var maxminc : Number = 0.0;
var maxmini : int = 0; // 詰みの防止
// var maxmini : int = Math.random() * PTN_MOVE.length; // 詰みの防止
for(i = 0;i < PTN_MOVE.length;i++){
var maxt : int = i == 0 ? 0 : int(mincs[i]) - 1;
if(maxt <= 0)continue;
if(depth == 0){
mc = mincs[i] + calcAvoidanceAtLeaf(
new Point(x.x + PTN_MOVE[i][0] * maxt, x.y + PTN_MOVE[i][1] * maxt),
maxt
);
}else{
mc = mincs[i] + calcAvoidanceAtNode(
new Point(x.x + PTN_MOVE[i][0] * maxt, x.y + PTN_MOVE[i][1] * maxt),
maxt,
depth - 1
);
}
if(mc > maxminc){
maxminc = mc;
maxmini = i;
}
}
return maxmini;
}
private function calcAvoidanceAtNode(x : Point, delay : int, depth : int) : Number
{
var i : int;
var t : Number;
var mincs : Array = new Array(PTN_MOVE.length);
// 壁への衝突
for(i = 0;i < PTN_MOVE.length;i++){
var minc : Number = Number.MAX_VALUE;
if(PTN_MOVE[i][0] > 0){
t = (400 - x.x) / PTN_MOVE[i][0];
if(t < minc)minc = t;
}else if(PTN_MOVE[i][0] < 0){
t = (x.x) / -PTN_MOVE[i][0];
if(t < minc)minc = t;
}
if(PTN_MOVE[i][1] > 0){
t = (465 - x.y) / PTN_MOVE[i][1];
if(t < minc)minc = t;
}else if(PTN_MOVE[i][1] < 0){
t = (x.y) / -PTN_MOVE[i][1];
if(t < minc)minc = t;
}
mincs[i] = minc;
}
// 弾への衝突
for each(var b : Bullet in _bullets){
var rx : Point = b.x.subtract(x);
rx.x += b.v.x * delay;
rx.y += b.v.y * delay;
for(i = 0;i < PTN_MOVE.length;i++){
var rv : Point = new Point(
b.v.x - PTN_MOVE[i][0],
b.v.y - PTN_MOVE[i][1]
);
t = mint(rx, rv);
if(t > 0){
var d2 : Number = mind2(rx, rv, t);
if(d2 < INFD){
t -= Math.sqrt((INFD - d2) / rv.length);
_gct++;
if(t < mincs[i])mincs[i] = t;
}
}
}
}
var mc : Number;
var maxminc : Number = 0.0;
for(i = 0;i < PTN_MOVE.length;i++){
var maxt : int = i == 0 ? 0 : int(mincs[i]) - 1;
if(maxt <= 0)continue;
if(depth == 0){
mc = mincs[i] + calcAvoidanceAtLeaf(
new Point(x.x + PTN_MOVE[i][0] * maxt, x.y + PTN_MOVE[i][1] * maxt),
delay + maxt
);
}else{
mc = mincs[i] + calcAvoidanceAtNode(
new Point(x.x + PTN_MOVE[i][0] * maxt, x.y + PTN_MOVE[i][1] * maxt),
delay + maxt,
depth - 1
);
}
if(mc > maxminc)maxminc = mc;
}
return maxminc;
}
private function calcAvoidanceAtLeaf(x : Point, delay : int) : Number
{
var i : int;
var t : Number;
var minc : Number = Number.MAX_VALUE;
// 壁への衝突
for(i = 0;i < PTN_MOVE.length;i++){
if(PTN_MOVE[i][0] > 0){
t = (400 - x.x) / PTN_MOVE[i][0];
if(t < minc)minc = t;
}else if(PTN_MOVE[i][0] < 0){
t = (x.x) / -PTN_MOVE[i][0];
if(t < minc)minc = t;
}
if(PTN_MOVE[i][1] > 0){
t = (465 - x.y) / PTN_MOVE[i][1];
if(t < minc)minc = t;
}else if(PTN_MOVE[i][1] < 0){
t = (x.y) / -PTN_MOVE[i][1];
if(t < minc)minc = t;
}
}
// 弾への衝突
for each(var b : Bullet in _bullets){
var rx : Point = b.x.subtract(x);
rx.x += b.v.x * delay;
rx.y += b.v.y * delay;
for(i = 0;i < PTN_MOVE.length;i++){
var rv : Point = new Point(
b.v.x - PTN_MOVE[i][0],
b.v.y - PTN_MOVE[i][1]
);
t = mint(rx, rv);
if(t > 0){
var d2 : Number = mind2(rx, rv, t);
if(d2 < INFD){
t -= Math.sqrt((INFD - d2) / rv.length);
_gct++;
if(t < minc)minc = t;
}
}
}
}
return minc;
}
private function mint(x : Point, v : Point) : Number
{
if(v.x * v.x + v.y * v.y < 0.01){
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;
}
}
}
import flash.geom.Point;
class Bullet
{
public var x : Point;
public var v : Point;
}