forked from: Garbage TETRIS
forked from Garbage TETRIS (diff: 1)
◆ ごみテトリス -ごみはゴミ箱へ- しばらくゲーム作りから離れていたので、練習がてら作るのが簡単そうなテトリスを。 慣れてる人なら一時間あればできるらしいけど、しばらくぶりだったので一週間以上かかってしまいました。 勘を取り戻すのには時間がかかりそうです。 ◆ 操作方法 ←・→ 移動 ↓ ソフトドロップ ↑ ハードドロップ Z・X 回転(クラシック準拠)
ActionScript3 source code
/**
* Copyright nan05aur ( http://wonderfl.net/user/nan05aur )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/brfv
*/
// forked from nemu90kWw's Garbage TETRIS
/*
◆ ごみテトリス -ごみはゴミ箱へ-
しばらくゲーム作りから離れていたので、練習がてら作るのが簡単そうなテトリスを。
慣れてる人なら一時間あればできるらしいけど、しばらくぶりだったので一週間以上かかってしまいました。
勘を取り戻すのには時間がかかりそうです。
◆ 操作方法
←・→ 移動 ↓ ソフトドロップ ↑ ハードドロップ Z・X 回転(クラシック準拠)
*/
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import com.bit101.components.*;
import net.wonderfl.score.basic.*;
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="60")]
public class Tetris extends Sprite
{
private var label:Label;
private var btn_start:PushButton;
private var btn_ranking:PushButton;
private var btn_clean:PushButton;
private var play:Boolean = false;
private var form_score:BasicScoreForm;
private var form_ranking:BasicScoreRecordViewer;
private var buffer:BitmapData = new BitmapData(465, 465, false, 0x000000);
private var screen:Bitmap = new Bitmap(buffer);
private var gamedata:GameData;
private var field:Field;
function Tetris()
{
Key.setListener(this);
KeyWatcher.watch("LEFT", 37, 100, 65);
KeyWatcher.watch("RIGHT", 39, 102, 68);
KeyWatcher.watch("UP", 38, 104, 87);
KeyWatcher.watch("DOWN", 40, 98, 83);
KeyWatcher.watch("ROT_L", 90, 75);
KeyWatcher.watch("ROT_R", 16, 88, 74);
func_key = new KeyWatcher();
addChild(screen);
Style.LABEL_TEXT = 0x000000;
label = new Label(this, 0, 0);
message("Garbage TETRIS");
btn_start = new PushButton(this, 182, 300, "START", startGame);
btn_ranking = new PushButton(this, 182, 330, "RANKING", showRanking);
btn_clean = new PushButton(this, 182, 380, "CLEAN UP!", clean);
btn_clean.visible = false;
gamedata = new GameData();
field = new Field(gamedata, this);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function message(text:String):void
{
if(label != null) {this.removeChild(label);}
label = new Label(this, 0, 0, text);
label.x = 465/2 - label.width*3;
label.y = 465/2 - label.height*3 - 50;
label.scaleX = label.scaleY = 6;
label.blendMode = BlendMode.INVERT;
}
public function startGame(e:Event):void
{
label.visible = false;
btn_start.visible = false;
btn_ranking.visible = false;
btn_clean.visible = false;
play = true;
field.init();
return;
}
public function entryRanking():void
{
label.visible = false;
form_score = new BasicScoreForm(this, (465-280)/2, (465-160)/2, gamedata.score, "ENTRY", onCloseScoreForm);
return;
}
private function onCloseScoreForm(succeeded:Boolean):void
{
if (form_score != null) {removeChild(form_score);}
form_ranking = new BasicScoreRecordViewer(this, (465-220)/2, (465-240)/2, "RANKING", 30, true, onCloseRankingForm);
return;
}
private function showRanking(e:Event):void
{
label.visible = false;
btn_start.visible = false;
btn_ranking.visible = false;
btn_clean.visible = false;
form_ranking = new BasicScoreRecordViewer(this, (465-220)/2, (465-240)/2, "RANKING", 30, true, onCloseRankingForm);
return;
}
private function onCloseRankingForm():void
{
if (form_ranking != null) {removeChild(form_ranking);}
btn_start.visible = true;
btn_ranking.visible = true;
if(play == true) {btn_clean.visible = true;}
message("Garbage TETRIS");
return;
}
private function clean(e:Event):void
{
field.garbage.fillRect(field.garbage.rect, 0x00000000);
return;
}
public function onEnterFrame(e:Event):void
{
func_key.update();
field.main();
draw();
return;
}
public function draw():void
{
field.draw(buffer);
return;
}
}
}
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import frocessing.color.FColor;
var func_key:KeyWatcher;
class GameData
{
public var score:int = 0;
}
class Field
{
public static const WIDTH:int = 10;
public static const INVISIBLE_HEIGHT:int = 1;
public static const HEIGHT:int = 20+INVISIBLE_HEIGHT;
public static const G:int = 0x10000;
private var gamedata:GameData;
private var root:Tetris;
public var map:Vector.<Vector.<int>>;
private var minopool:ActorPool = new ActorPool();
private var effectpool:ActorPool = new ActorPool();
private var particlepool:ActorPool = new ActorPool();
public var garbage:BitmapData = new BitmapData(465, 465, true, 0x00000000);
public var x:int = Math.floor((465/2) - (20*WIDTH)/2);
public var y:int = Math.floor((465/2) - (20*HEIGHT)/2) - (10*INVISIBLE_HEIGHT);
private var tetromino:Tetromino;
private var ghost:Tetromino;
private var next:Tetromino;
private var table:Array;
private var drop_speed:int;
private var lockdown_length:int;
private var lockdown_time:int;
private var halflock:Boolean;
private var action:Function;
private var count:int;
function Field(gamedata:GameData, root:Tetris)
{
this.gamedata = gamedata;
this.root = root;
changeAction("act_blank");
return;
}
private function changeAction(name:String):void
{
action = this[name];
count = -1;
return;
}
public function init():void
{
map = new Vector.<Vector.<int>>(HEIGHT);
for(var y:int = 0; y < HEIGHT; y++) {
map[y] = new Vector.<int>(WIDTH);
for(var x:int = 0; x < WIDTH; x++) {
map[y][x] = -1;
}
}
do {
table = MathEx.shuffle([0, 1, 2, 3, 4, 5, 6]);
}while(
table[0] == MinoPattern.S || table[0] == MinoPattern.Z
|| table[1] == MinoPattern.S || table[1] == MinoPattern.Z)
drop_speed = G / 30;
lockdown_length = 60;
gamedata.score = 0;
changeAction("act_ready");
return;
}
public function main():void
{
count++;
action();
minopool.main();
effectpool.main();
particlepool.main();
return;
}
// --------------------------------//
// 状態
// --------------------------------//
private function act_blank():void
{
return;
}
private function act_ready():void
{
if(count == 0) {
root.message("Ready");
}
if(count == 60)
{
root.message("");
changeAction("act_move");
}
return;
}
private function act_move():void
{
if(count == 0)
{
shiftMino();
// ゲームオーバー判定
if(tetromino.hitTest() == true)
{
tetromino.lock();
tetromino = null;
next = null;
changeAction("act_gameover");
return;
}
}
// 回転
if(func_key.isPress("ROT_L")) {tetromino.rotate(1);}
else if(func_key.isPress("ROT_R")) {tetromino.rotate(-1);}
// 横移動
if(func_key.isPress("LEFT", true)) {tetromino.slide(-1);}
else if(func_key.isPress("RIGHT", true)) {tetromino.slide(1);}
if(func_key.isPress("UP") == true)
{
// ハードドロップ
tetromino.drop(G*20);
lockdown_time = lockdown_length;
}
else if(tetromino.isLanding() == false)
{
// ソフトドロップ
if(func_key.isDown("DOWN") && drop_speed < G/2) {tetromino.drop(G/2);}
else {tetromino.drop(drop_speed);}
lockdown_time = 0;
halflock = false;
}
// 接地
if(tetromino.isLanding() == true)
{
lockdown_time++;
if(lockdown_time >= lockdown_length || func_key.isPress("DOWN"))
{
changeAction("act_lockdown");
}
else if(func_key.isDown("DOWN"))
{
if(halflock == false)
{
halflock = true;
lockdown_time = lockdown_length-7;
}
}
}
// ゴースト処理
ghost = tetromino.clone();
ghost.ghost = true;
ghost.drop(G*20);
return;
}
private function act_lockdown():void
{
if(count == 0)
{
tetromino.lock();
tetromino = null;
ghost = null;
// ライン判定
for(var i:int = 0; i < HEIGHT; i++)
{
if(checkLine(i) == true)
{
changeAction("act_erase");
return;
}
}
}
if(count == 15)
{
changeAction("act_move");
return;
}
}
private function act_erase():void
{
var i:int;
if(count == 0)
{
for(i = 0; i < HEIGHT; i++) {
if(checkLine(i) == true) {
for each(var mino:Mino in minopool.list) {
if (mino.py == i) {
mino.changeAction("act_break");
}
}
gamedata.score++;
}
}
}
if(count == 45)
{
for(i = 0; i < HEIGHT; i++) {
if(checkLine(i) == true) {
eraseLine(i);
}
}
}
if(count == 110)
{
changeAction("act_move");
if(gamedata.score >= 50) {
drop_speed += G/100;
}
}
}
private function act_gameover():void
{
if(count == 0)
{
root.message("GAME OVER");
for(var i:int = INVISIBLE_HEIGHT; i < HEIGHT; i++)
{
for(var j:int = 0; j < WIDTH; j++)
{
if(map[i][j] != -1) {
map[i][j] = 7;
}
}
for each(var mino:Mino in minopool.list) {
mino.changeAction("act_gameover");
}
}
}
if(count == 350) {
root.entryRanking();
}
}
// --------------------------------//
// フィールド操作
// --------------------------------//
public function shiftMino():void
{
if(next == null)
{
tetromino = new Tetromino(this);
tetromino.x = 3;
tetromino.y = 0;
tetromino.type = table.shift();
tetromino.rot = 0;
}
else {
tetromino = next;
tetromino.ghost = false;
}
next = new Tetromino(this);
next.x = 3;
next.y = 0;
next.type = table.shift();
next.ghost = true;
next.rot = 0;
if(func_key.isDown("ROT_L") && tetromino.hitTest(0, 0, 1) == false) {tetromino.rotate(1);}
else if(func_key.isDown("ROT_R") && tetromino.hitTest(0, 0, -1) == false) {tetromino.rotate(-1);}
if(table.length == 0) {
table = MathEx.shuffle([0, 1, 2, 3, 4, 5, 6]);
}
lockdown_time = 0;
halflock = false;
return;
}
public function writeMino(x:int, y:int, type:int):void
{
map[y][x] = type;
minopool.add(new Mino(this, x, y, type));
}
public function eraseLine(h:int):void
{
for(var y:int = h; y >= 1; y--) {
map[y] = map[y-1];
}
map[0] = new Vector.<int>(WIDTH);
for(var x:int = 0; x < WIDTH; x++) {
map[0][x] = -1;
}
for each(var mino:Mino in minopool.list) {
if(mino.py < h) {
mino.py++;
mino.y += 20;
}
}
return;
}
// --------------------------------//
// 生成
// --------------------------------//
public function addBreakingEffect(px:int, py:int, type:int):void
{
effectpool.add(new BreakingMino(this, x+px*20+10, y+py*20+10, type));
for(var i:int = 0; i < 5; i++) {
particlepool.add(new Particle(x+px*20+10, y+py*20+10));
}
}
public function addParticle(x:Number, y:Number):void
{
particlepool.add(new Particle(x, y));
}
// --------------------------------//
// 判定
// --------------------------------//
public function hitTest(x:int, y:int):Boolean
{
if(x < 0 || x >= WIDTH || y >= HEIGHT) {return true;}
if(y < 0) {return false;}
return (map[y][x] >= 0 && map[y][x] <= 6);
}
public function checkLine(h:int):Boolean
{
for(var i:int = 0; i < WIDTH; i++) {
if(hitTest(i, h) == false) {return false;}
}
return true;
}
// --------------------------------//
// 描画
// --------------------------------//
public function draw(buffer:BitmapData):void
{
buffer.colorTransform(buffer.rect, new ColorTransform(1, 1, 1, 1, 24, 32, 48, 0));
buffer.fillRect(new Rectangle(x, y+INVISIBLE_HEIGHT*20, WIDTH*20, (HEIGHT-INVISIBLE_HEIGHT)*20), 0x404040);
for(var i:int = INVISIBLE_HEIGHT; i < HEIGHT; i++) {
for(var j:int = 0; j < WIDTH; j++) {
buffer.fillRect(new Rectangle(x+j*20, y+i*20, 19, 19), 0x000000);
}
}
minopool.draw(buffer);
if(next != null) {next.draw(buffer)};
if(tetromino != null) {tetromino.draw(buffer);}
buffer.copyPixels(garbage, garbage.rect, new Point(0, 0));
particlepool.draw(buffer);
effectpool.draw(buffer);
if(ghost != null) {ghost.draw(buffer);}
return;
}
}
class Tetromino
{
private var field:Field;
public var x:int;
public var y:int;
public var type:int;
public var ghost:Boolean = false;
private var _rot:int;
public function get rot():int {return _rot;}
public function set rot(value:int):void
{
_rot = value;
if(_rot < 0) {_rot = MinoPattern.TABLE[type].length-1;}
if(_rot >= MinoPattern.TABLE[type].length) {_rot = 0;}
}
function Tetromino(field:Field)
{
this.field = field;
}
public function clone():Tetromino
{
var temp:Tetromino = new Tetromino(field);
temp.x = x;
temp.y = y;
temp.type = type;
temp.rot = rot;
return temp;
}
// --------------------------------//
// 移動・回転
// --------------------------------//
public function slide(vx:int):void
{
if(hitTest(vx) == true) {return;}
x += vx;
return;
}
public function drop(vy:int):void
{
if(isLanding() == true) {return;}
while(vy >= 0)
{
y += Math.min(vy, 0x10000);
vy -= 0x10000;
if(isLanding() == true) {
y = (y >> 16) << 16;
break;
}
}
}
public function rotate(r:int):void
{
if(hitTest(0, 0, r) == false)
{
rot += r;
return;
}
// Iは補正しない
if(type == MinoPattern.I) {return;}
// JLTは中央列以外にブロックが存在しない場合は補正しない
if(type == MinoPattern.J || type == MinoPattern.L || type == MinoPattern.T)
{
var side:Boolean = false;
loop : for(var i:int = 0; i < 3; i++) {
for(var j:int = 0; j < 3; j+=2) {
if(field.hitTest(x+j, ((y+0x8000)>>16)+i) == true) {side = true; break loop;}
if(field.hitTest(x+j, ((y+0xFFFF)>>16)+i) == true) {side = true; break loop;}
}
}
if(side == false) {
return;
}
}
// 回転補正
if(hitTest(1, 0, r) == false)
{
rot += r;
x++;
return;
}
if(hitTest(-1, 0, r) == false)
{
rot += r;
x--;
return;
}
return;
}
// --------------------------------//
// 当たり判定
// --------------------------------//
public function hitTest(offset_x:int = 0, offset_y:int = 0, offset_rot:int = 0):Boolean
{
var temp:Tetromino = this.clone();
temp.x += offset_x;
temp.y += offset_y;
temp.rot += offset_rot;
var pattern:Array = MinoPattern.TABLE[temp.type][temp.rot];
for(var i:int = 0; i < pattern.length; i++) {
for(var j:int = 0; j < pattern[i].length; j++) {
if(pattern[i][j] != 0) {
if(field.hitTest(temp.x+j, ((temp.y+0x8000)>>16)+i) == true) {return true;}
if(field.hitTest(temp.x+j, ((temp.y+0xFFFF)>>16)+i) == true) {return true;}
}
}
}
return false;
}
public function isLanding():Boolean
{
var temp:Tetromino = this.clone();
var pattern:Array = MinoPattern.TABLE[temp.type][temp.rot];
for(var i:int = 0; i < pattern.length; i++) {
for(var j:int = 0; j < pattern[i].length; j++) {
if(pattern[i][j] != 0) {
if(field.hitTest(temp.x+j, (temp.y>>16)+(i+1)) == true) {return true;}
}
}
}
return false;
}
public function lock():void
{
var pattern:Array = MinoPattern.TABLE[type][rot];
for(var i:int = 0; i < pattern.length; i++) {
for(var j:int = 0; j < pattern[i].length; j++) {
if(pattern[i][j] != 0) {
field.writeMino(x+j, (y>>16)+i, type);
}
}
}
return;
}
// --------------------------------//
// 描画
// --------------------------------//
public function draw(buffer:BitmapData):void
{
var i:int, j:int;
var pattern:Array = MinoPattern.TABLE[type][rot];
if(ghost == false)
{
for(i = 0; i < pattern.length; i++) {
for(j = 0; j < pattern[i].length; j++) {
if(pattern[i][j] != 0) {
buffer.fillRect(
new Rectangle(
field.x + (x+j)*20 - 1, field.y + (y/0x10000+i)*20 - 1,
21, 21
),
FColor.HSVtoValue(
FColor.hue(MinoPattern.COLOR[type]),
FColor.saturation(MinoPattern.COLOR[type]),
0.5
)
);
buffer.fillRect(
new Rectangle(
field.x + (x+j)*20, field.y + (y/0x10000+i)*20,
19, 19
),
MinoPattern.COLOR[type]
);
}
}
}
}
else {
i = -1;
do {
j = -1;
do {
var pc:Boolean, py:Boolean, px:Boolean;
pc = pattern[i] == undefined || pattern[i][j] == undefined || pattern[i][j] == 0;
py = pattern[i+1] == undefined || pattern[i+1][j] == undefined || pattern[i+1][j] == 0;
px = pattern[i] == undefined || pattern[i][j+1] == undefined || pattern[i][j+1] == 0;
if(pc != py)
{
buffer.fillRect(
new Rectangle(
field.x + (x+j)*20, field.y + (y/0x10000+i+1)*20-1,
20, 2
),
MinoPattern.COLOR[type]
);
}
if(pc != px)
{
buffer.fillRect(
new Rectangle(
field.x + (x+j+1)*20-1, field.y + (y/0x10000+i)*20,
2, 20
),
MinoPattern.COLOR[type]
);
}
j++;
} while(j < pattern[0].length)
i++;
} while(i < pattern.length)
}
return;
}
}
class Actor
{
protected var count:int = -1;
public var deleteflag:Boolean = false;
public var x:Number = 0;
public var y:Number = 0;
public var visible:Boolean = true;
public var action:String = "act_blank";
public function main():void
{
count++;
this[action]();
}
public function act_blank():void {}
public function draw(buffer:BitmapData):void {}
public function changeAction(name:String):void
{
action = name;
count = -1;
}
public function vanish():void
{
deleteflag = true;
}
}
class ActorPool
{
public var list:Array;
function ActorPool()
{
list = new Array();
}
public function get length():uint {return list.length;}
public function add(actor:Actor):Actor
{
list.push(actor);
return actor;
}
public function main():void
{
for(var i:int = 0; i < list.length; i++)
{
list[i].main();
if(list[i].deleteflag == true)
{
list.splice(i, 1);
i--;
}
}
}
public function draw(bmp:BitmapData):void
{
for(var i:int = 0; i < list.length; i++)
{
if(list[i].visible == false) {continue;}
list[i].draw(bmp);
}
}
}
class Mino extends Actor
{
private var field:Field;
public var px:int;
public var py:int;
public var type:int;
public var color:uint;
function Mino(field:Field, px:int, py:int, type:int):void
{
this.px = px;
this.py = py;
this.type = type;
this.field = field;
x = px*20;
y = py*20;
changeAction("act_flash");
}
public function act_flash():void
{
if(count < 2) {
color = 0xFFFFFF;
}
else if(count < 4) {
color = 0x000000;
}
else if(count < 150) {
color = FColor.RGBtoValue(
(0xFF + FColor.red(MinoPattern.COLOR[type]) * (count-4)) / (count-3),
(0xFF + FColor.green(MinoPattern.COLOR[type]) * (count-4)) / (count-3),
(0xFF + FColor.blue(MinoPattern.COLOR[type]) * (count-4)) / (count-3)
);
}
else {
color = MinoPattern.COLOR[type];
}
}
public function act_break():void
{
if(count % 6 < 3) {
color = 0xFFFFFF;
}
else {
color = MinoPattern.COLOR[type];
}
if(count == 12+Math.abs((px - Field.WIDTH/2) * 3)) {
field.addBreakingEffect(px, py, type);
vanish();
}
}
public function act_gameover():void
{
if(count == 0) {
color = MinoPattern.COLOR[type];
}
if(21 - Math.floor(count/3) == py) {
color = 0xA0A0A0;
}
if(count == 200) {
changeAction("act_break");
}
}
override public function draw(buffer:BitmapData):void
{
buffer.fillRect(new Rectangle(field.x + x, field.y + y, 19, 19), color+0xFF000000);
}
}
class BreakingMino extends Actor
{
private var field:Field;
private var shape:Shape;
private var matrix:Matrix = new Matrix();
private var vx:Number;
private var vy:Number;
private var bound:int;
private var angle:Number;
private var rot:Number;
private var h:Number;
function BreakingMino(field:Field, x:Number, y:Number, type:int)
{
this.field = field;
this.x = x;
this.y = y;
vx = Math.random() * 10 - 5;
vy = Math.random() * -6 - 6;
angle = 0;
rot = Math.random() * 20 - 10;
h = y - Math.random() * 20;
shape = new Shape();
shape.graphics.beginFill(MinoPattern.COLOR[type]);
shape.graphics.drawRect(-9, -9, 18, 18);
changeAction("act_main");
}
public function act_main():void
{
if(count <= 15 && count % 5 == 0) {
field.addParticle(x, y);
}
x += vx;
y += vy;
angle += rot;
if(x < 0) {
x = 0;
vx = -vx;
vx /= 1.5;
}
if(x > 465) {
x = 465
vx = -vx;
vx /= 1.5;
}
if(field.garbage.getPixel32(x, y+5) != 0 || y > 465)
{
if(bound > 10)
{
draw(field.garbage);
vanish();
return;
}
else if(vy > 0 && y > h)
{
vx /= 1.2;
vy /= -1.5;
rot = Math.random() * 20 - 10;
bound++;
}
}
vy += 0.5;
}
override public function draw(buffer:BitmapData):void
{
matrix.identity();
matrix.rotate(angle);
matrix.translate(x, y);
buffer.draw(shape, matrix);
}
}
class Particle extends Actor
{
public var vx:Number;
public var vy:Number;
public var size:Number;
function Particle(x:Number, y:Number)
{
this.x = x;
this.y = y;
vx = Math.random() * 10 - 5;
vy = Math.random() * 6 - 6;
size = 30;
changeAction("act_main");
}
public function act_main():void
{
x += vx;
y += vy;
vx /= 1.1;
vy += 0.3;
size /= 1.1;
if(size < 1) {
vanish();
}
}
override public function draw(buffer:BitmapData):void
{
buffer.fillRect(new Rectangle(x-size/2, y-size/2, size, size), 0xFFFFFFFF);
}
}
class MinoPattern
{
public static const I:int = 0, O:int = 1, S:int = 2, Z:int = 3, J:int = 4, L:int = 5, T:int = 6;
public static const COLOR:Array = [0xFF0040, 0xE8FF00, 0xFF40FF, 0x20F000, 0x8040FF, 0xFF8000, 0x00E0FF];
public static const TABLE:Array = new Array();
TABLE[I] = [[
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 0, 0, 0]
], [
[0, 0, 1, 0],
[0, 0, 1, 0],
[0, 0, 1, 0],
[0, 0, 1, 0]
]];
TABLE[O] = [[
[0, 0, 0],
[0, 1, 1],
[0, 1, 1]
]];
TABLE[S] = [[
[0, 0, 0],
[0, 1, 1],
[1, 1, 0]
],[
[1, 0, 0],
[1, 1, 0],
[0, 1, 0]
]];
TABLE[Z] = [[
[0, 0, 0],
[1, 1, 0],
[0, 1, 1]
],[
[0, 0, 1],
[0, 1, 1],
[0, 1, 0]
]];
TABLE[J] = [[
[0, 0, 0],
[1, 1, 1],
[0, 0, 1]
],[
[0, 1, 0],
[0, 1, 0],
[1, 1, 0]
],[
[0, 0, 0],
[1, 0, 0],
[1, 1, 1]
],[
[0, 1, 1],
[0, 1, 0],
[0, 1, 0]
]];
TABLE[L] = [[
[0, 0, 0],
[1, 1, 1],
[1, 0, 0]
],[
[1, 1, 0],
[0, 1, 0],
[0, 1, 0]
],[
[0, 0, 0],
[0, 0, 1],
[1, 1, 1]
],[
[0, 1, 0],
[0, 1, 0],
[0, 1, 1]
]];
TABLE[T] = [[
[0, 0, 0],
[1, 1, 1],
[0, 1, 0]
],[
[0, 1, 0],
[1, 1, 0],
[0, 1, 0]
],[
[0, 0, 0],
[0, 1, 0],
[1, 1, 1]
],[
[0, 1, 0],
[0, 1, 1],
[0, 1, 0]
]];
}
class Key
{
private static var down:Array = new Array(256);
public static function setListener(target:InteractiveObject):void
{
target.stage.focus = target;
target.addEventListener(KeyboardEvent.KEY_DOWN, function (event:KeyboardEvent):void {down[event.keyCode] = true;});
target.addEventListener(KeyboardEvent.KEY_UP, function (event:KeyboardEvent):void {down[event.keyCode] = false;});
target.addEventListener(FocusEvent.FOCUS_OUT, onFocusOut);
}
private static function onFocusOut(event:FocusEvent):void
{
event.currentTarget.stage.focus = event.currentTarget;
for(var i:String in down) {down[i] = false;}
}
public static function isDown(keycode:int):Boolean
{
return down[keycode];
}
}
class KeyWatcher
{
private static var watchlist:Object = new Object();
private static var repeat_wait:uint = 12;
private static var repeat_rate:uint = 2;
private var keylist:Object = new Object();
public var lock:Boolean = false;
public function KeyWatcher():void
{
for(var name:String in watchlist)
{
keylist[name] = new Object();
keylist[name].down = false;
keylist[name].press = false;
keylist[name].release = false;
keylist[name].repeat = false;
keylist[name].repeatcount = 0;
}
return;
}
public static function watch(name:String, ...keycodes):void {watchlist[name] = keycodes;}
public static function unwatch(name:String):void {delete watchlist[name];}
public static function unwatchAll():void {watchlist = new Object();}
public function isDown(name:String):Boolean
{
if(keylist[name] is Object == false) {return false;}
return keylist[name].down;
}
public function isPress(name:String, getrepeat:Boolean = false):Boolean
{
if(keylist[name] is Object == false) {return false;}
if(getrepeat == false) {return keylist[name].press;}
else {return keylist[name].press || keylist[name].repeat;}
}
public function isRelease(name:String):Boolean
{
if(keylist[name] is Object == false) {return false;}
return keylist[name].release;
}
public function update():void
{
var name:String, keycode:int;
var input:Object = new Object();
if(lock == false) {
for(name in watchlist) {
for each(keycode in watchlist[name]) {
if(Key.isDown(keycode) == true) {input[name] = true; break;}
}
}
}
else {
for each(keycode in watchlist[name]) {input[name] = false;}
}
for(name in keylist) {
var key:Object = keylist[name];
if(input[name] == true) {
if(key.down == false) {
key.press = true;
key.repeat = true;
}
else {
key.press = false;
key.repeat = false;
}
key.down = true;
key.release = false;
key.repeatcount++;
if(key.repeatcount == repeat_wait) {
key.repeatcount -= repeat_rate;
key.repeat = true;
}
}
else {
if(key.down == true) {
key.release = true;
}
else {
key.release = false;
}
key.down = false;
key.press = false;
key.repeatcount = 0;
key.repeat = false;
}
}
return;
}
}
class MathEx
{
public static function shuffle(array:Array):Array
{
for(var j:int, t:Number, i:int = array.length, a:Array = array.slice();i; j = Math.random() * i, t = a[--i], a[i] = a[j], a[j] = t);
return a;
}
}