flash on 2012-3-2
/**
* Copyright MMMMMonchi ( http://wonderfl.net/user/MMMMMonchi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wI1O
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.utils.ByteArray;
public class Main extends Sprite
{
private var keys:Array = [];
private var status:Status = new Status();
private var blocks:Array = [];
private var next/*Array*/:Array = [];
private var nextLength:int = 3;
private var map/*Array*/:Array; // テトリス盤面
private var landingCount:int = 10; // 地面(ブロック)に付いてから固定されるまでのフレーム
private var leftKeyPressCount:int = 0;
private var rightKeyPressCount:int = 0;
private var rotateKeyPressFlag:Boolean; // 回転キーを押している状態か
private const WIDTH:int = 12; // 横幅
private const HEIGHT:int = 21; // 縦幅
private const FALL_SPEED:Number = 0.05; // 落ちるスピード
public function Main()
{
map = [];
for (var y:int = 0; y < HEIGHT; y++)
{
map[y] = new Array();
for (var x:int = 0; x < WIDTH; x++)
{
// 左端/右端/下端は壁なので1を入れ、それ以外のところは0を入れる
if (x == 0 || x == WIDTH - 1 || y == HEIGHT - 1) map[y][x] = 1;
else map[y][x] = 0;
}
}
for (var i:int = 0; i < nextLength; i++) next.push(getBlock());
initalize();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
}
// 初期化処理
private function initalize():void
{
rotateKeyPressFlag = false;
status.x = 4;
status.y = 0;
status.block = next.shift();
next.push(getBlock());
}
private function getBlock():Array
{
if (blocks.length == 0)
{
for (var i:int = 0; i < Block.SHAPE.length; i++)
{
blocks.push(Block.SHAPE[i]);
}
blocks = shuffle(blocks);
}
return blocks.pop();
}
// 配列をシャッフルする
private function shuffle(src:Array):Array
{
var temp:Array = src.slice();
var dest:Array = new Array();
while (temp.length > 0)
{
var index:int = Math.random() * temp.length;
dest.push(temp[index]);
temp.splice(index, 1);
}
return dest;
}
// 毎フレーム行う処理
private function onEnterFrame(event:Event):void
{
status.y += FALL_SPEED;
// 一つ下に移動して衝突する場合は、今のマスから動かさないようにする
if (check(status.x, status.y + 1)) status.y = int(status.y);
if (keys[Keyboard.LEFT] && !check(status.x - 1, Math.ceil(status.y)) && !check(status.x - 1, Math.floor(status.y)))
{
if (leftKeyPressCount == 0 || leftKeyPressCount >= 3)
{
status.x--;
}
leftKeyPressCount++;
}
else leftKeyPressCount = 0; // キーが離されたら、値を0に戻す
if (keys[Keyboard.RIGHT] && !check(status.x + 1, Math.ceil(status.y)) && !check(status.x + 1, Math.floor(status.y)))
{
if (rightKeyPressCount == 0 || rightKeyPressCount >= 3)
{
status.x++;
}
rightKeyPressCount++;
}
else rightKeyPressCount = 0;
if (keys[Keyboard.DOWN])
{
status.y += FALL_SPEED * 10; // 普通に落ちる速度の10倍
if (check(status.x, status.y + 1)) status.y = int(status.y);
}
if (keys[Keyboard.UP])
{
drop();
}
if (!rotateKeyPressFlag && keys[90])
{
status.block = rotate(status.block);
if (check(status.x, status.y)) status.block = rotate(status.block, false);
rotateKeyPressFlag = true;
}
if (!rotateKeyPressFlag && keys[88])
{
status.block = rotate(status.block, false);
if (check(status.x, status.y)) status.block = rotate(status.block);
rotateKeyPressFlag = true;
}
if (!keys[90] && !keys[88]) rotateKeyPressFlag = false;
if (check(status.x, status.y + 1))
{
if (--landingCount <= 0) endProcess();
}
else landingCount = 10;
draw();
}
// 仮に引数の(x, y)に今落ちているブロックを置いた場合、
// 他のブロックや壁と衝突してしまう場合はtrue, しない場合はfalseが返却される
private function check(tx:int, ty:int):Boolean
{
var block:Array = status.block;
for (var y:int = 0; y < Block.SIZE; y++)
{
for (var x:int = 0; x < Block.SIZE; x++)
{
if (block[y][x] && map[ty + y][tx + x]) return true;
}
}
return false;
}
// ブロックが地面に落ちて、位置が確定した後の処理
private function endProcess():void
{
// ENTER_FRAMEを一度止める
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
lock(); // ブロックを固定
deleteLine(); // 削除
draw(); // 描画
initalize(); // 初期化
landingCount = 10; // 初期化
// 最初の位置にブロックが置けなかったらゲームオーバー。
if (check(status.x, status.y)) gameOver();
else addEventListener(Event.ENTER_FRAME, onEnterFrame); // 再開
}
// 着地したブロックを固定させる
private function lock():void
{
var block:Array = status.block;
for (var y:int = 0; y < Block.SIZE; y++)
{
for (var x:int = 0; x < Block.SIZE; x++)
{
if (block[y][x]) map[status.y + y][status.x + x] = block[y][x];
}
}
}
private function deleteLine():void
{
for (var y:int = HEIGHT - 2; y >= 0; y--)
{
var flag:Boolean = true; // trueなら横一列が揃っている
for (var x:int = 1; x <= WIDTH - 2; x++)
{
// ある行に隙間を見つけたら横一列揃っていないということなので、
// flagをfalseにしてループを抜ける
if (!map[y][x])
{
flag = false;
break;
}
}
// 横一列揃っていたら
if (flag)
{
// 揃っている行から上にある全ての行を一段下にずらす
for (var yy:int = y - 1; yy >= 0; yy--)
{
for (x = 1; x <= WIDTH - 2; x++)
{
map[yy + 1][x] = map[yy][x];
}
}
// 一段ずれるので、yの値を戻す
y++;
}
}
}
private function getDropPosition():int
{
for (var y:int = status.y; ; y++)
{
if (check(status.x, y))
{
return y - 1;
}
}
return -999; // ここまで来ないが、何か書いておかないと警告が出る
}
private function drop():void
{
status.y = getDropPosition();
}
// block = 回転させるブロック(配列) leftRotateがtrueなら左に回転、falseなら右に回転
private function rotate(block:Array, leftRotate:Boolean = true):Array
{
var cloneBlock:Array = clone(block);
for (var y:int = 0; y < Block.SIZE; y++)
{
for (var x:int = 0; x < Block.SIZE; x++)
{
if (leftRotate) cloneBlock[Block.SIZE - x - 1][y] = block[y][x];
else cloneBlock[x][Block.SIZE - y - 1] = block[y][x];
}
}
return cloneBlock;
}
private function clone(array:Array):Array
{
var b:ByteArray = new ByteArray();
b.writeObject(array);
b.position = 0;
return b.readObject();
}
private function gameOver():void
{
trace("GAME OVER");
}
// ブロックの描画
private function draw():void
{
graphics.clear(); // 初期化
graphics.beginFill(0x0);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
graphics.endFill();
for (var y:int = 0; y < HEIGHT; y++)
{
for (var x:int = 0; x < WIDTH; x++)
{
// 注目しているマスに0が入っていない、つまり壁かブロックが入っている場合
if (map[y][x])
{
// 壁だったら
if (x == 0 || x == WIDTH - 1 || y == HEIGHT - 1)
{
graphics.lineStyle(1.0);
graphics.beginFill(0x555555);
}
// ブロックだったら
else
{
graphics.lineStyle(2.0);
graphics.beginFill(Block.COLOR[map[y][x]]);
}
graphics.drawRect(x * Block.WIDTH, y * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
graphics.endFill();
}
}
}
var block:Array = status.block;
var dropY:int = getDropPosition(); // 落下地点の位置yを取得
for (y = 0; y < Block.SIZE; y++)
{
for (x = 0; x < Block.SIZE; x++)
{
// 4*4配列の中でブロックの描画があるところだけを表示する
if (block[y][x])
{
// (status.x, drop.y)のところにブロックを薄く表示させる
graphics.lineStyle(1.5, 0x777777);
graphics.beginFill(Block.COLOR[block[y][x]], 0.1);
graphics.drawRect((status.x + x) * Block.WIDTH, (dropY + y) * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
graphics.endFill();
graphics.lineStyle(1.5);
graphics.beginFill(Block.COLOR[block[y][x]]);
graphics.drawRect((status.x + x) * Block.WIDTH, (status.y + y) * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
graphics.endFill();
}
}
}
for (var i:int = 0; i < next.length; i++)
{
block = next[i];
for (y = 0; y < Block.SIZE; y++)
{
for (x = 0; x < Block.SIZE; x++)
{
if (block[y][x])
{
graphics.lineStyle(1.5);
graphics.beginFill(Block.COLOR[block[y][x]]);
graphics.drawRect(300 + x * Block.WIDTH, i * 100 + y * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
graphics.endFill();
}
}
}
}
}
// キーが押されたとき
private function onKeyDown(event:KeyboardEvent):void
{
keys[event.keyCode] = true;
}
// キーが離されたとき
private function onKeyUp(event:KeyboardEvent):void
{
keys[event.keyCode] = false;
}
}
}
class Status
{
public var x:Number; // このx, yの位置からブロックを表示する
public var y:Number;
public var block/*Array*/:Array; // 今持っているブロック
}
class Block
{
public static const SIZE:int = 4; // ブロックの形状を4*4の配列で保持しているので、その4を定数にしている
public static const WIDTH:int = 20; // ブロックの横サイズ
public static const HEIGHT:int = 20; // ブロックの縦サイズ
// 色
public static const COLOR/*int*/:Array = [0x0, 0xFEFBB3, 0x69DEEE, 0x3DC642, 0xF33433, 0x797CFB, 0xF88C2D, 0xFFAAFF];
// 形状
public static const SHAPE/*Array*/:Array =
[
[
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 1, 1, 0],
[0, 0, 0, 0]
],
[
[0, 2, 0, 0],
[0, 2, 0, 0],
[0, 2, 0, 0],
[0, 2, 0, 0]
],
[
[0, 0, 0, 0],
[0, 3, 3, 0],
[3, 3, 0, 0],
[0, 0, 0, 0]
],
[
[0, 0, 0, 0],
[4, 4, 0, 0],
[0, 4, 4, 0],
[0, 0, 0, 0]
],
[
[0, 0, 0, 0],
[5, 0, 0, 0],
[5, 5, 5, 0],
[0, 0, 0, 0]
],
[
[0, 0, 0, 0],
[0, 0, 6, 0],
[6, 6, 6, 0],
[0, 0, 0, 0]
],
[
[0, 0, 0, 0],
[0, 7, 0, 0],
[7, 7, 7, 0],
[0, 0, 0, 0]
]
];
}