if (!canDodge) { gameover(); }
GAME :: 避けゲーっぽいの
*
* 操作はマウスを動かすのみです。上方から降り注ぐ流星をひたすら避け続けます。
* Level 5 付近から結構きついです(主観)。
/**
* Copyright uwi ( http://wonderfl.net/user/uwi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/qsv0
*/
// forked from daniwell's if (isHit) { gameover(); }
/**
* GAME :: 避けゲーっぽいの
*
* 操作はマウスを動かすのみです。上方から降り注ぐ流星をひたすら避け続けます。
* Level 5 付近から結構きついです(主観)。
*/
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Mouse;
[SWF(backgroundColor = "0x333333", frameRate = "60", width = "465", height = "465")]
public class Evade extends Sprite
{
private const WIDTH :uint = 390 / 3;
private const HEIGHT:uint = 465 / 3;
private var bmd :BitmapData;
private var bmp :Bitmap;
private var particles :Vector.<Vector.<Particle>> = new Vector.<Vector.<Particle>>(WIDTH);
private var pos :int = 0;
private var numList :Vector.<uint> = new Vector.<uint>(WIDTH);
private var scoreText :TextField;
private var tx :TextField = new TextField();
private var lv :uint;
private var speed :Number;
private var particleNum :uint;
public function Evade()
{
bmd = new BitmapData(WIDTH, HEIGHT, false, 0);
bmp = new Bitmap(bmd);
bmp.scaleX = bmp.scaleY = 3;
addChild(bmp);
scoreText = new TextField();
tx = new TextField();
tx.autoSize = scoreText.autoSize = "left";
tx.defaultTextFormat = scoreText.defaultTextFormat = new TextFormat("_等幅", 10, 0xffffff);
scoreText.x = 395;
scoreText.y = 435;
addChild(scoreText);
tx.text = "CLICK TO RESTART";
tx.x = (465 - tx.width) / 2;
tx.y = (465 - tx.height) / 2;
addChild(tx);
initialize();
}
private function initialize():void
{
var i:uint, j:uint, len:uint = 0;
tx.visible = false;
lv = pos = 0;
for (i = 0; i < WIDTH; i++)
{
if (particles[i]) len = particles[i].length;
for (j = 0; j < len; j++) particles[i][j] = null;
numList[i] = i;
particles[i] = new Vector.<Particle>();
}
_particles = [];
for (i = 0; i < WIDTH; i++)
{
var tmp:uint = numList[i];
var r :uint = Math.random() * WIDTH;
numList[i] = numList[r];
numList[r] = tmp;
}
// Mouse.hide();
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.CLICK, onClick);
mX = 100; mY = 100;
}
private var _mode : uint = 0;
private function onClick(e : MouseEvent) : void
{
_mode = ++_mode % 2;
}
private function addParticle():void
{
if (particleNum < pos) return;
var n :uint = numList[pos % WIDTH];
var p:Particle = new Particle();
p.x = n;
p.y = 0;
p.vy = Math.random() * speed + 1;
particles[n].push(p);
_particles.push(p);
}
private var mX : int;
private var mY : int;
private var _particles : Array;
private function enterFrameHandler(e:Event):void
{
if (lv < Level.max && Level.counts[lv] <= pos)
{
speed = Level.speeds[lv];
particleNum = Level.nums[lv];
lv ++; // level up
}
addParticle();
pos ++;
scoreText.text = "level: " + lv + "\nscore: " + pos;
var i:uint, j:uint, len:uint = 0;
var p:Particle;
bmd.lock();
bmd.colorTransform(bmd.rect, new ColorTransform (0.4, 0.4, 0.4));
for (i = 0; i < WIDTH; i++)
{
len = particles[i].length;
for (j = 0; j < len; j++)
{
p = particles[i][j];
p.py = p.y;
p.y += p.vy;
if (HEIGHT <= p.y)
{
p.vy = Math.random() * speed + 1;
p.y = 0;
}
bmd.setPixel(p.x, p.y, 0xffffff);
p.reflect();
}
}
// var mX :int = mouseX / 3;
// var mY :int = mouseY / 3;
var ret : Object;
if(_mode == 0){
ret = VelocityStrokeDodgeAlgorithm2D.run(mX, mY, 3, {
maxxx : 133, maxxy : 145, minxx : 0, minxy : 0,
bullets : _particles, selfr : 1, basex : 133 / 2, basey : 100
}, [[0, 0], [1, 0], [-1, 0]], LInfinityNorm.calcLinearCollisionTime2D,
40, 40
);
}else if(_mode == 1){
ret = VelocityStrokeDodgeAlgorithm2D.run(mX, mY, 1, {
maxxx : 133, maxxy : 145, minxx : 0, minxy : 0,
bullets : _particles, selfr : 1, basex : 133 / 2, basey : 100
}, [[0, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]], LInfinityNorm.calcLinearCollisionTime2D,
40, 40
);
}
mX += ret.motion[0];
mY += ret.motion[1];
scoreText.appendText("\n" + ret.time);
if (mX < 0) mX = 0; else if (WIDTH <= mX) mX = WIDTH - 1;
// 衝突判定
len = particles[mX].length;
for (j = 0; j < len; j++)
{
p = particles[mX][j];
if ( p.py <= mY && mY <= p.y )
{
Mouse.show();
tx.visible = true;
stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.CLICK, clickHandler);
}
}
bmd.setPixel(mX, mY, 0xff6600); // mouse
bmd.unlock();
}
private function clickHandler(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.CLICK, clickHandler);
initialize();
}
}
}
/* Level 毎の 速さ調整 & 個数 管理 */
class Level
{
public static const max :uint = 10;
public static const counts :Array = [ 0, 400, 800, 1200, 1500, 2000, 2500, 3000, 5000, 10000]; // pos
public static const speeds :Array = [ 0, 0.5, 1, 1, 1.5, 1.8, 2, 2.5, 3, 3]; // Particle 速さ
public static const nums :Array = [130, 150, 150, 180, 180, 200, 200, 200, 220, 260]; // Particle 個数
}
interface IBullet
{
function step() : void;
function predict(t : Number) : Array;
}
class Bullet2D implements IBullet
{
public var xx : Number;
public var xy : Number;
public var r : Number;
public var t : Number;
public function Bullet2D(xx : Number, xy : Number, r : Number, t : Number = 0)
{
this.xx = xx; this.xy = xy;
this.r = r;
this.t = t;
}
public function step() : void
{
}
public function predict(t : Number) : Array
{
return null;
}
}
class LinearBullet2D extends Bullet2D implements IBullet
{
public var vx : Number;
public var vy : Number;
public function LinearBullet2D(xx : Number, xy : Number, vx : Number, vy : Number, r : Number, t : Number = 0)
{
super(xx, xy, r, t);
this.vx = vx; this.vy = vy;
}
public override function step() : void
{
xx += vx; xy += vy;
}
public override function predict(t : Number) : Array
{
return [xx + vx * t, xy + vy * t];
}
}
class Particle extends LinearBullet2D
{
public var x :Number = 0;
public var y :Number = 0;
// public var vy:Number = 0;
public var py:Number = 0; // previous y
public function Particle()
{
super(0, 0, 0, 0, 1);
}
public function reflect() : void
{
this.xx = x;
this.xy = y;
}
}
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])];
return [a[0] > b[0] ? a[0] : b[0], a[1] < b[1] ? a[1] : b[1]];
}
}
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, collisionTimeCalculator : Function, width : Number = 0, limt : uint = 100) : Object
{
if (width > 0) env = filter(xx, xy, width, env, limt);
var ret : Array = [0.0, 0.0];
var maxval : Number = 0;
var stability : Array = [];
for each(var m : Array in motions) {
var val : Number = calcSurvivalTime(xx, xy, m, 0, depth, env, motions, limt, collisionTimeCalculator);
if(val >= limt)stability.push(m);
if (val > maxval) {
maxval = val;
ret = m;
}
}
if (stability.length >= 2) {
var mind2 : Number = Number.MAX_VALUE;
for each(m in stability) {
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 };
}
private static var _t : uint = 0;
private static var _s : Number = 0;
/**
* 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, calcCollisionTime : Function) : Number
{
var mint : Number = limt - et;
var t : Number;
var rxx : Number, rxy : Number, rvx : Number, rvy : Number;
var colr2 : Number;
var colt : Number;
var rxxt : Number, rxyt : Number;
var d2 : 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; }
var self : LinearBullet2D = new LinearBullet2D(xx, xy, vx, vy, r);
// collision with bullets
if (env.bullets) {
for each(var b : LinearBullet2D in env.bullets) {
colt = calcCollisionTime(self, b, et);
if (colt < mint) {
mint = colt;
}
}
}
mint = Math.floor(mint);
if (mint + et == limt) return mint + depth;
if(mint >= 2 && depth >= 1){
// recursion
//var maxval : int = mint >= 10 ? mint / 10 - 1 : 0;
//var tt : int = mint - 1 - maxval; // move to the edge of collision
//mint -= maxval;
var maxval : int = 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, calcCollisionTime);
if (val > maxval) {
maxval = val;
}
}
mint += maxval;
}
return mint;
}
/**
* develop tunnel vision
* @param w
* @param env
* @return
*/
private static function filter(xx : Number, xy : Number, w : Number, env : Object, limt : Number) : Object
{
var d : Number;
var seen : Array = [];
for each(var b : LinearBullet2D 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, limt];
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);
}
}
var ret : Object = { };
for (var key : String in env) ret[key] = env[key];
ret.bullets = seen;
return ret;
}
}
class LInfinityNorm
{
public static function calcLinearCollisionTime2D(a : LinearBullet2D, b : LinearBullet2D, tb : Number = 0) : Number
{
var colr : Number = a.r + b.r; // collision radius
// relative parameter
var rxx : Number = a.xx - (b.xx + b.vx * tb);
var rxy : Number = a.xy - (b.xy + b.vy * tb);
var rvx : Number = a.vx - b.vx;
var rvy : Number = a.vy - b.vy;
var d : Number;
var range : Array = [0, Number.MAX_VALUE]; // collision time range
if(rvx != 0){
var txinf : Number = (rxx - colr) / -rvx;
var txsup : Number = (rxx + colr) / -rvx;
if (txsup < txinf) { d = txinf; txinf = txsup; txsup = d; }
range = RangeUtils.intersection(range, [txinf, txsup]);
}else {
if (rxx > colr || rxx < -colr) range = null;
}
if(rvy != 0){
var tyinf : Number = (rxy - colr) / -rvy;
var tysup : Number = (rxy + colr) / -rvy;
if (tysup < tyinf) { d = tyinf; tyinf = tysup; tysup = d; }
range = RangeUtils.intersection(range, [tyinf, tysup]);
}else {
if (rxy > colr || rxy < -colr) range = null;
}
return range != null ? range[0] : Number.MAX_VALUE;
}
}