Ponytail (何も考えずBraidをSTGにしてみた)
Braid (http://www.xbox.com/ja-JP/games/b/braidxboxlivearcade/)
が面白かったので何も考えずSTGにしてみた。
緑弾の扱いとか大失敗した感があるが後悔していない。
// Braid (http://www.xbox.com/ja-JP/games/b/braidxboxlivearcade/)
// が面白かったので何も考えずSTGにしてみた。
// 緑弾の扱いとか大失敗した感があるが後悔していない。
package {
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import net.hires.debug.Stats;
[SWF(width=465,height=465,frameRate=60,backgroundColor=0x111111)]
public class Ponytail extends Sprite {
private var step:uint = 0;
private var step2:uint = 0;
private var deadStep:uint = 0xFFFFFFFF;
private var canvas:Canvas = new Canvas(400, 465);
private var rewindHint:RewindHint = new RewindHint();
private var fighter:Fighter = new Fighter(200, 420);
private var waves:Array = [new Wave1(), new Wave2(), new Wave3()];
private var waveIndex:uint = 0;
private var bulletList:BulletList;
/**
* おコンストラクタ
*/
public function Ponytail() {
var bounds:Rectangle = canvas.bitmapData.rect.clone();
bounds.inflate(4, 4);
bulletList = new BulletList(bounds);
addChild(canvas);
var stats:Stats = new Stats();
stats.x = canvas.width;
addChild(stats);
rewindHint.x = canvas.width - rewindHint.width >> 1;
rewindHint.y = canvas.height - rewindHint.height >> 1;
rewindHint.visible = false;
addChild(rewindHint);
addEventListener(Event.ENTER_FRAME, enterFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyboardManager.keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, KeyboardManager.keyUp);
}
/**
* フレームごとの処理
*/
private function enterFrame(event:Event):void {
var i:uint;
var forward:Boolean = false;
if (KeyboardManager.keyStates[88]) {
if (step > 0) {
step--;
canvas.rollback();
} else {
canvas.clear();
}
} else if (step - deadStep > 30) {
rewindHint.visible = true;
return;
} else {
step++;
canvas.clear();
forward = true;
}
rewindHint.visible = false;
step2++;
if (forward) {
canvas.sepia = Math.max(0, canvas.sepia - 0.02);
} else {
canvas.sepia = Math.min(1, canvas.sepia + 0.002);
}
var currentWave:IWave = waves[waveIndex % waves.length];
currentWave.getBullets(step, step2, bulletList);
if (deadStep > step) {
if (forward) {
fighter.update(canvas.bitmapData.rect, step);
deadStep = 0xFFFFFFFF;
var hitRect:Rectangle = new Rectangle(fighter.getX(step) - 4, fighter.getY(step) - 4, 8, 8);
for (i=0; i<bulletList.count; i++) {
if (hitRect.contains(bulletList.listX[i], bulletList.listY[i])) {
deadStep = step;
break;
}
}
}
canvas.blit(fighter.bitmap, fighter.getX(step), fighter.getY(step));
}
for (i=0; i<bulletList.count; i++) {
canvas.blit(
bulletList.listLocked[i] ? BulletVisual.locked : BulletVisual.normal,
bulletList.listX[i], bulletList.listY[i]
);
}
if (step > 100 && deadStep > step && bulletList.count == 0) {
fighter.reset(step);
step = 0;
step2 = 0;
waveIndex++;
}
}
}
}
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.display.Bitmap;
import flash.filters.ColorMatrixFilter;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
class BulletList {
private var bounds:Rectangle;
public var listX:Vector.<Number> = new Vector.<Number>(0, false);
public var listY:Vector.<Number> = new Vector.<Number>(0, false);
public var listLocked:Vector.<Boolean> = new Vector.<Boolean>(0, false);
public var count:uint = 0;
public function BulletList(bounds:Rectangle) {
this.bounds = bounds;
}
public function reset():void {
count = 0;
}
public function addBullet(x:Number, y:Number, locked:Boolean=false):void {
if (bounds.contains(x, y)) {
listX[count] = x;
listY[count] = y;
listLocked[count] = locked;
count++;
}
}
}
interface IWave {
function getBullets(step1:uint, step2:uint, list:BulletList):void;
}
class Wave1 implements IWave {
public function getBullets(step:uint, step2:uint, list:BulletList):void {
list.reset();
for (var i:uint=0; i<12; i++) {
var elapsed:int = step - i * 12;
if (elapsed > 0) {
for (var j:uint=0; j<30; j++) {
var angle:Number = j / 30 * Math.PI * 2 - i * 0.021;
list.addBullet(Math.cos(angle) * elapsed + 200, Math.sin(angle) * elapsed + 100);
}
}
}
}
}
class Wave2 implements IWave {
public function getBullets(step:uint, step2:uint, list:BulletList):void {
list.reset();
var elapsed:int;
for (var i:uint=0; i<60; i++) {
elapsed = step - i * 6;
if (elapsed > 0) {
for (var j:uint=0; j<10; j++) {
var angle:Number = j / 18 * Math.PI * 2;
list.addBullet(Math.cos(angle) * elapsed + 200, Math.sin(angle) * elapsed + 100);
}
}
}
elapsed = step - 59 * 6;
if (elapsed > 0) {
for (j=0; j<400 * 17 / 18; j++) {
angle = (j / 400 + 8 / 18) * Math.PI * 2;
list.addBullet(Math.cos(angle) * elapsed + 200, Math.sin(angle) * elapsed + 100);
}
}
}
}
class Wave3 implements IWave {
public function getBullets(step:uint, step2:uint, list:BulletList):void {
list.reset();
var elapsed:int;
var i:uint, j:uint, angle:Number;
for (i=0; i<60; i++) {
elapsed = step - i * 8;
if (elapsed > 0) {
for (j=0; j<20; j++) {
angle = j / 20 * Math.PI * 2 + i * 0.02;
list.addBullet(Math.cos(angle) * elapsed + 180, Math.sin(angle) * elapsed + 100);
}
}
}
for (i=0; i<60; i++) {
elapsed = step2 - i * 8;
if (elapsed > 0) {
for (j=0; j<20; j++) {
angle = j / 20 * Math.PI * 2 + i * -0.02;
list.addBullet(Math.cos(angle) * elapsed + 180, Math.sin(angle) * elapsed + 100, true);
}
}
}
}
}
class Fighter {
private var historyX:Array;
private var historyY:Array;
public const bitmap:BitmapData = new BitmapData(16, 16, false, 0xFF0000);
public function Fighter(x:Number, y:Number):void {
historyX = [x];
historyY = [y];
}
public function update(bounds:Rectangle, step:uint):void {
var newX:Number = historyX[step - 1];
var newY:Number = historyY[step - 1];
if (KeyboardManager.keyStates[Keyboard.RIGHT]) {
newX += 2;
}
if (KeyboardManager.keyStates[Keyboard.LEFT]) {
newX -= 2;
}
if (KeyboardManager.keyStates[Keyboard.DOWN]) {
newY += 2;
}
if (KeyboardManager.keyStates[Keyboard.UP]) {
newY -= 2;
}
newX = Math.max(bounds.left, Math.min(bounds.right, newX));
newY = Math.max(bounds.top, Math.min(bounds.bottom, newY));
historyX[step] = newX;
historyY[step] = newY;
}
public function getX(step:uint):Number {
return historyX[step];
}
public function getY(step:uint):Number {
return historyY[step];
}
public function reset(step:uint):void {
historyX[0] = historyX[step];
historyY[0] = historyY[step];
}
}
class BulletVisual extends BitmapData {
public static const normal:BulletVisual = new BulletVisual(0x0000FF, 0x00FFFF);
public static const locked:BulletVisual = new BulletVisual(0x008000, 0x00FF00);
public function BulletVisual(edgeColor:uint, frameColor:uint) {
super(8, 8, false, edgeColor);
fillRect(new Rectangle(1, 1, 6, 6), frameColor);
fillRect(new Rectangle(2, 2, 4, 4), 0xFFFFFF);
}
}
class Canvas extends Bitmap {
private var bmp:BitmapData;
private var tmp:BitmapData;
private var darken:ColorTransform;
private var shrink:Matrix;
private var dest:Point = new Point();
private var _sepia:Number = 0;
private var rgb2yuv:ColorMatrixFilter = new ColorMatrixFilter([
+0.299, +0.587, +0.114, 0, 0,
-0.169, -0.331, +0.500, 0, 128,
+0.500, -0.419, -0.081, 0, 128,
0, 0, 0, 1, 0
]);
private var yuv2rgb:ColorMatrixFilter = new ColorMatrixFilter([
1, +0.000, +1.402, 0, 128 * -1.402,
1, -0.344, -0.714, 0, 128 * (0.344 + 0.714),
1, +1.772, +0.000, 0, 128 * -1.772,
0, 0, 0, 1, 0
]);
public function get sepia():Number {
return _sepia;
}
public function set sepia(value:Number):void {
if (_sepia != value) {
_sepia = value;
if (value) {
var r:Number = 1 - value;
var matrix:Array = rgb2yuv.matrix.slice();
matrix[5] *= r; matrix[6] *= r; matrix[7] *= r;
matrix[10] *= r; matrix[11] *= r; matrix[12] *= r;
matrix[9] += value * -0.091 * 128;
matrix[14] += value * +0.056 * 128;
filters = [new ColorMatrixFilter(matrix), yuv2rgb];
} else {
filters = null;
}
}
}
public function Canvas(width:int, height:int):void {
super(bmp = new BitmapData(width, height, false, 0));
tmp = bmp.clone();
darken = new ColorTransform(0.85, 0.85, 0.85);
shrink = new Matrix();
shrink.translate(width * -0.5, height * -0.5);
shrink.scale(1.05, 1.05);
shrink.translate(width * 0.5, height * 0.5);
}
public function clear():void {
bmp.fillRect(bmp.rect, 0x000000);
}
public function rollback():void {
tmp.copyPixels(bmp, bmp.rect, bmp.rect.topLeft);
bmp.draw(tmp, shrink, darken);
}
public function blit(bitmap:BitmapData, x:Number, y:Number):void {
dest.x = x - (bitmap.width >> 1);
dest.y = y - (bitmap.height >> 1);
bmp.copyPixels(bitmap, bitmap.rect, dest);
}
}
class RewindHint extends TextField {
public function RewindHint() {
defaultTextFormat = new TextFormat("_typewriter", 30, 0xFFFFFF, true);
text = "PRESS [X]";
autoSize = TextFieldAutoSize.LEFT;
selectable = false;
}
}
class KeyboardManager {
public static const keyStates:Object = {};
public static function keyDown(event:KeyboardEvent):void {
keyStates[event.keyCode] = true;
}
public static function keyUp(event:KeyboardEvent):void {
keyStates[event.keyCode] = false;
}
}