flash on 2009-2-11
テ○リス風落ち物ゲームです.
操作方法
← → : ブロック移動
↓ : 高速落下
↑ : 超高速落下
SPACE : 右回転
ENTER : 左回転
// テ○リス風落ち物ゲームです.
// 操作方法
// ← → : ブロック移動
// ↓ : 高速落下
// ↑ : 超高速落下
// SPACE : 右回転
// ENTER : 左回転
package
{
//凹型のブロックには未対応
import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.ui.*;
public class Tetris extends Sprite
{
//map1(color):0(nothing),1(red),2(blue),3(yellow)
//map2(type):0(nothing),1(left),2(right),3(up),4(down),5(center),6(stop);
private var map1:Array;
private var map2:Array;
private var blocks1:Array;
private var blocks2:Array;
private var block1:Array;
private var block2:Array;
private var xx:int;
private var yy:int;
private var lastScene:int = SCENE_PLAY;
private var message:TextField = new TextField();
public function Tetris()
{
addEventListener(KeyboardEvent.KEY_DOWN, keyDownEvent);
addEventListener(KeyboardEvent.KEY_UP, keyUpEvent);
addEventListener(Event.ENTER_FRAME, loop_Proc);
message.text = "pause";
message.x = (100 - message.textWidth) / 2;
message.y = (200 - message.textHeight) / 2;
message.textColor = 0xFF0000;
scene = SCENE_PAUSE;
addEventListener(FocusEvent.FOCUS_IN, function(event:FocusEvent):void {
scene = lastScene;
message.text = "";
message.x = (100 - message.textWidth) / 2;
});
addEventListener(FocusEvent.FOCUS_OUT, function(event:FocusEvent):void {
lastScene = scene;
scene = SCENE_PAUSE;
message.text = "pause";
message.x = (100 - message.textWidth) / 2;
});
addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void {
if (scene == SCENE_OVER) {
scene = SCENE_PLAY;
message.text = "";
init();
initMap();
}
});
addChild(message);
init();
initMap();
}
public function newArray(ii:int, jj:int):Array
{
var t:Array = new Array(ii);
for (var i:int = 0; i < ii; i++)
{
t[i] = new Array(jj);
}
for (i = 0; i < t.length; i++) {
for (var j:int = 0; j < t[0].length; j++) {
t[i][j] = 0;
}
}
return t;
}
public function initMap():void {
map1 = newArray(20, 10);
map2 = newArray(20, 10);
}
public function init():void {
map1 = newArray(20, 10);
map2 = newArray(20, 10);
blocks1 =
[
[
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
],
[
[0, 1, 0],
[1, 1, 1],
[0, 0, 0],
],
[
[1, 1, 0],
[0, 1, 1],
],
[
[0, 1, 1],
[1, 1, 0],
],
[
[1, 1],
[1, 1],
],
[
[0, 0, 1],
[1, 1, 1],
[0, 0, 0],
],
[
[1, 0, 0],
[1, 1, 1],
[0, 0, 0],
],
];
blocks2 = new Array(blocks1.length);
for (var k:int = 0; k < blocks1.length; k++) {
var b1:Array = blocks1[k];
var b2:Array = newArray(blocks1[k].length, blocks1[k][0].length);
for (var i:int = 0; i < b2.length; i++) {
for (var j:int = 0; j < b2[0].length; j++) {
if (b1[i][j] != 0) {
if (i + 1 < b1.length && b1[i + 1][j] != 0) {
b2[i][j] |= 1 << MAP_DOWN;
}
if (j + 1 < b1[0].length && b1[i][j + 1] != 0) {
b2[i][j] |= 1 << MAP_RIGHT;
}
if (i - 1 >= 0 && b1[i -1][j] != 0) {
b2[i][j] |= 1 << MAP_UP;
}
if (j - 1 >=0 && b1[i][j-1] != 0) {
b2[i][j] |= 1 << MAP_LEFT;
}
}
}
}
blocks2[k] = b2;
}
newBlock();
}
public function genRand(st:int, end:int):int {
return (Math.random() * 9999) % (end - st + 1) + st;
}
public function newBlock():void {
var t:int = genRand(0, blocks1.length-1);
block1 = blocks1[t];
block2 = blocks2[t];
for (var i:int = 0; i < block1.length; i++) {
for (var j:int = 0; j < block1[0].length; j++) {
if (block1[i][j] != 0) {
block1[i][j] = t + 1;
}
}
}
xx = 3;
yy = 0;
}
public function getRotateBlock1(b:Array):Array
{
var t:Array = newArray(b[0].length,b.length);
for (var i:int = 0; i < b[0].length; i++) {
for (var j:int = 0; j < b.length; j++) {
t[i][j] = b[b.length - j - 1][i];
}
}
return t;
}
public function getRotateBlockR1(b:Array):Array
{
var t:Array = newArray(b[0].length,b.length);
for (var i:int = 0; i < b.length; i++){
for (var j:int = 0; j < b[0].length; j++) {
t[b[0].length - j - 1][i] = b[i][j];
}
}
return t;
}
public function getRotateBlock2(b:Array):Array
{
var t:Array = newArray(b[0].length,b.length);
for (var i:int = 0; i < b[0].length; i++) {
for (var j:int = 0; j < b.length; j++) {
t[i][j] = b[b.length - j - 1][i];
}
}
for (i = 0; i < t.length; i++) {
for (j = 0; j < t[0].length; j++) {
var temp:int = t[i][j];
t[i][j] = ((temp >>> 1) | (temp << 3)) & 0x0F;
}
}
return t;
}
public function getRotateBlockR2(b:Array):Array
{
var t:Array = newArray(b[0].length,b.length);
for (var i:int = 0; i < b.length; i++){
for (var j:int = 0; j < b[0].length; j++) {
t[b[0].length - j - 1][i] = b[i][j];
}
}
for (i = 0; i < t.length; i++) {
for (j = 0; j < t[0].length; j++) {
var temp:int = t[i][j];
t[i][j] = ((temp << 1) | (temp >>> 3)) & 0x0F;
}
}
return t;
}
public function isCollision(m:Array, b:Array, x:int, y:int):Boolean
{
for (var i:int = 0; i < b.length; i++) {
var yy:int = y + i;
for (var j:int = 0; j < b[0].length; j++) {
var xx:int = x + j;
if (b[i][j] != 0 && (yy<0 || yy>=m.length ||
xx<0 || xx>=m[0].length ||
m[yy][xx] != 0)) {
return true;
}
}
}
return false;
}
public function setMap():void
{
for (var i:int = 0; i < block1.length; i++) {
for (var j:int = 0; j < block1[0].length; j++) {
var t:int = block1[i][j];
if (t != 0) {
map1[yy + i][xx + j] = t;
map2[yy + i][xx + j] = block2[i][j];
}
}
}
}
private var sc:int = 0;
private const STOP_COUNT:int = 3;
private var dc:int = 0;
private const DOWN_COUNT:int = 5;
private const KEY_RIGHT:int = 0;
private const KEY_LEFT:int = 1;
private const KEY_UP:int = 2;
private const KEY_DOWN:int = 3;
private const KEY_A:int = 4;
private const KEY_B:int = 5;
private var keypad:int = 0;
public function keyDownEvent(event:KeyboardEvent):void
{
var code:uint = event.keyCode;
switch(code) {
case Keyboard.RIGHT:
keypad |= (1 << KEY_RIGHT);
break;
case Keyboard.LEFT:
keypad |= (1 << KEY_LEFT);
break;
case Keyboard.UP:
keypad |= (1 << KEY_UP);
break;
case Keyboard.DOWN:
keypad |= (1 << KEY_DOWN);
break;
case Keyboard.ENTER:
keypad |= (1 << KEY_B);
break;
case Keyboard.SPACE:
keypad |= (1 << KEY_A);
break;
}
}
public function keyUpEvent(event:KeyboardEvent):void
{
var code:uint = event.keyCode;
switch(code) {
case Keyboard.RIGHT:
keypad &= ~(1 << KEY_RIGHT);
break;
case Keyboard.LEFT:
keypad &= ~(1 << KEY_LEFT);
break;
case Keyboard.UP:
keypad &= ~(1 << KEY_UP);
break;
case Keyboard.DOWN:
keypad &= ~(1 << KEY_DOWN);
break;
case Keyboard.ENTER:
keypad &= ~(1 << KEY_B);
break;
case Keyboard.SPACE:
keypad &= ~(1 << KEY_A);
break;
}
}
private const SCENE_PLAY:int = 0;
private const SCENE_UPDATE:int = 1;
private const SCENE_DELETE:int = 2;
private const SCENE_OVER:int = 3;
private const SCENE_PAUSE:int = 4;
private const SCENE_DELETEVIEW:int = 5;
private var scene:int = SCENE_PLAY;
public function loop_Proc(event:Event):void {
if(scene==SCENE_PLAY){
if ((keypad & (1 << KEY_RIGHT)) != 0) {
keypad &= ~(1 << KEY_RIGHT);
if (!isCollision(map1, block1, xx + 1, yy)) {
xx++;
sc = 0;
}
}
if ((keypad & (1 << KEY_LEFT)) != 0) {
keypad &= ~(1 << KEY_LEFT);
if (!isCollision(map1, block1, xx - 1, yy)) {
xx--;
sc = 0;
}
}
if ((keypad & (1 << KEY_DOWN)) != 0) {
//keypad &= ~(1 << KEY_DOWN);
dc = DOWN_COUNT;
}
if ((keypad & (1 << KEY_A)) != 0) {
keypad &= ~(1 << KEY_A);
var rblock1:Array = getRotateBlock1(block1);
var rblock2:Array = getRotateBlock2(block2);
if (!isCollision(map1, rblock1, xx, yy)) {
block1 = rblock1;
block2 = rblock2;
sc = 0;
}else if (!isCollision(map1, rblock1, xx, yy-1)) {
block1 = rblock1;
block2 = rblock2;
yy--;
sc = 0;
}else if (!isCollision(map1, rblock1, xx+1, yy)) {
block1 = rblock1;
block2 = rblock2;
xx++;
sc = 0;
}else if (!isCollision(map1, rblock1, xx-1, yy)) {
block1 = rblock1;
block2 = rblock2;
xx--;
sc = 0;
}
}
if ((keypad & (1 << KEY_B)) != 0) {
keypad &= ~(1 << KEY_B);
rblock1 = getRotateBlockR1(block1);
rblock2 = getRotateBlockR2(block2);
if (!isCollision(map1, rblock1, xx, yy)) {
block1 = rblock1;
block2 = rblock2;
sc = 0;
}else if (!isCollision(map1, rblock1, xx, yy-1)) {
block1 = rblock1;
block2 = rblock2;
yy--;
sc = 0;
}else if (!isCollision(map1, rblock1, xx+1, yy)) {
block1 = rblock1;
block2 = rblock2;
xx++;
sc = 0;
}else if (!isCollision(map1, rblock1, xx-1, yy)) {
block1 = rblock1;
block2 = rblock2;
xx--;
sc = 0;
}
}
if ((keypad & (1 << KEY_UP)) != 0) {
keypad &= ~(1 << KEY_UP);
var cy:int = yy;
while (!isCollision(map1, block1, xx, cy + 1)) {
cy++;
}
yy=cy;
dc = DOWN_COUNT;
sc = STOP_COUNT;
}
if (++dc >= DOWN_COUNT) {
dc = 0;
if (!isCollision(map1, block1, xx, yy + 1)) {
yy++;
sc = 0;
}else {
if (++sc >= STOP_COUNT) {
sc = 0;
setMap();
//clearMap(map1, map2);
scene = SCENE_UPDATE;
}
}
}
}else if (scene == SCENE_UPDATE) {
if (++uc >= UPDATE_COUNT) {
uc = 0;
if (!updateMap(map1, map2)) {
scene = SCENE_DELETE;
}
}
}else if (scene == SCENE_DELETE) {
if (clearMap(map1, map2)) {
scene = SCENE_UPDATE;
}else {
scene = SCENE_PLAY;
newBlock();
if (isCollision(map1, block1, xx, yy)) {
scene = SCENE_OVER;
message.text = "game over";
message.x = (100 - message.textWidth) / 2;
}
}
}
draw();
}
private var uc:int = 0;
private const UPDATE_COUNT:int = 3;
private var colorTable:Array = [0x344454, 0x68C8E0, 0xB07CBC, 0xBC4C4C, 0x60A460, 0xE0B874, 0xD08860, 0x6C90D0];
public function draw():void {
graphics.clear();
graphics.beginFill(0x344454);
graphics.drawRect(0, 0, 100, 200);
graphics.endFill();
for (var i:int = 0; i < map1.length; i++) {
for (var j:int = 0; j < map1[0].length; j++) {
var t:int = map1[i][j];
if (t != 0) {
var tt:int = map2[i][j];
if(tt!=16){
graphics.beginFill(colorTable[t]);
var ia:Array = [i * 10, i * 10 + 5, (i + 1) * 10];
var ja:Array = [j * 10, j * 10 + 5, (j + 1) * 10];
graphics.moveTo(ja[0], ia[1]);
if ((tt & (1 << MAP_LEFT)) == 0 && (tt & (1 << MAP_UP)) == 0) {
graphics.curveTo(ja[0], ia[0], ja[1], ia[0]);
}else {
graphics.lineTo(ja[0], ia[0]);
graphics.lineTo(ja[1], ia[0]);
}
if ((tt & (1 << MAP_UP)) == 0 && (tt & (1 << MAP_RIGHT)) == 0) {
graphics.curveTo(ja[2], ia[0], ja[2], ia[1]);
}else {
graphics.lineTo(ja[2], ia[0]);
graphics.lineTo(ja[2], ia[1]);
}
if ((tt & (1 << MAP_DOWN)) == 0 && (tt & (1 << MAP_RIGHT)) == 0) {
graphics.curveTo(ja[2], ia[2], ja[1], ia[2]);
}else {
graphics.lineTo(ja[2], ia[2]);
graphics.lineTo(ja[1], ia[2]);
}
if ((tt & (1 << MAP_DOWN)) == 0 && (tt & (1 << MAP_LEFT)) == 0) {
graphics.curveTo(ja[0], ia[2], ja[0], ia[1]);
}else {
graphics.lineTo(ja[0], ia[2]);
graphics.lineTo(ja[0], ia[1]);
}
graphics.endFill();
}else {
graphics.beginFill(colorTable[t]);
graphics.moveTo(j * 10, i * 10);
graphics.curveTo(j * 10 + 5, i * 10 + 5, (j + 1) * 10, i * 10);
graphics.curveTo(j * 10 + 5, i * 10 + 5, (j + 1) * 10, (i + 1) * 10);
graphics.curveTo(j * 10 + 5, i * 10 + 5, j * 10, (i + 1) * 10);
graphics.curveTo(j * 10 + 5, i * 10 + 5, j * 10, i * 10);
graphics.endFill();
}
}
}
}
if(scene==SCENE_PLAY || scene==SCENE_PAUSE){
var cy:int = yy;
while (!isCollision(map1, block1, xx, cy + 1)) {
cy++;
}
for (var ii:int = 0; ii < block1.length; ii++) {
for (var jj:int = 0; jj < block1[0].length; jj++) {
t = block1[ii][jj];
if (t != 0) {
i = ii + cy;
j = jj + xx;
tt = block2[ii][jj];
graphics.beginFill(colorTable[t],0.5);
ia = [i * 10, i * 10 + 5, (i + 1) * 10];
ja = [j * 10, j * 10 + 5, (j + 1) * 10];
graphics.moveTo(ja[0], ia[1]);
if ((tt & (1 << MAP_LEFT)) == 0 && (tt & (1 << MAP_UP)) == 0) {
graphics.curveTo(ja[0], ia[0], ja[1], ia[0]);
}else {
graphics.lineTo(ja[0], ia[0]);
graphics.lineTo(ja[1], ia[0]);
}
if ((tt & (1 << MAP_UP)) == 0 && (tt & (1 << MAP_RIGHT)) == 0) {
graphics.curveTo(ja[2], ia[0], ja[2], ia[1]);
}else {
graphics.lineTo(ja[2], ia[0]);
graphics.lineTo(ja[2], ia[1]);
}
if ((tt & (1 << MAP_DOWN)) == 0 && (tt & (1 << MAP_RIGHT)) == 0) {
graphics.curveTo(ja[2], ia[2], ja[1], ia[2]);
}else {
graphics.lineTo(ja[2], ia[2]);
graphics.lineTo(ja[1], ia[2]);
}
if ((tt & (1 << MAP_DOWN)) == 0 && (tt & (1 << MAP_LEFT)) == 0) {
graphics.curveTo(ja[0], ia[2], ja[0], ia[1]);
}else {
graphics.lineTo(ja[0], ia[2]);
graphics.lineTo(ja[0], ia[1]);
}
graphics.endFill();
}
}
}
for (ii = 0; ii < block1.length; ii++) {
for (jj = 0; jj < block1[0].length; jj++) {
t = block1[ii][jj];
if (t != 0) {
i = ii + yy;
j = jj + xx;
tt = block2[ii][jj];
graphics.beginFill(colorTable[t]);
ia = [i * 10, i * 10 + 5, (i + 1) * 10];
ja = [j * 10, j * 10 + 5, (j + 1) * 10];
graphics.moveTo(ja[0], ia[1]);
if ((tt & (1 << MAP_LEFT)) == 0 && (tt & (1 << MAP_UP)) == 0) {
graphics.curveTo(ja[0], ia[0], ja[1], ia[0]);
}else {
graphics.lineTo(ja[0], ia[0]);
graphics.lineTo(ja[1], ia[0]);
}
if ((tt & (1 << MAP_UP)) == 0 && (tt & (1 << MAP_RIGHT)) == 0) {
graphics.curveTo(ja[2], ia[0], ja[2], ia[1]);
}else {
graphics.lineTo(ja[2], ia[0]);
graphics.lineTo(ja[2], ia[1]);
}
if ((tt & (1 << MAP_DOWN)) == 0 && (tt & (1 << MAP_RIGHT)) == 0) {
graphics.curveTo(ja[2], ia[2], ja[1], ia[2]);
}else {
graphics.lineTo(ja[2], ia[2]);
graphics.lineTo(ja[1], ia[2]);
}
if ((tt & (1 << MAP_DOWN)) == 0 && (tt & (1 << MAP_LEFT)) == 0) {
graphics.curveTo(ja[0], ia[2], ja[0], ia[1]);
}else {
graphics.lineTo(ja[0], ia[2]);
graphics.lineTo(ja[0], ia[1]);
}
graphics.endFill();
}
}
}
}
}
public function clearMap(map1:Array, map2:Array):Boolean {
var l:Array = new Array();
for (var i:int = 0; i < map1.length; i++) {
var flag:Boolean = true;
for (var j:int = 0; j < map1[0].length; j++) {
if (map1[i][j] == 0) {
flag = false;
break;
}
}
if (flag) {
l.push(i);
}
}
for (var ii:int = 0; ii < l.length; ii++) {
i = l[ii];
for (j = 0; j < map1[0].length; j++) {
if (j + 1 < map2[0].length) {
map2[i][j + 1] &= ~(1 << MAP_LEFT);
}
if (j - 1 >= 0) {
map2[i][j - 1] &= ~(1 << MAP_RIGHT);
}
if (i + 1 < map2.length) {
map2[i + 1][j] &= ~(1 << MAP_UP);
}
if (i - 1 >= 0) {
map2[i - 1][j] &= ~(1 << MAP_DOWN);
}
map1[i][j] = map2[i][j] = 0;
}
}
return l.length > 0;
}
public const MAP_LEFT:int = 0;
public const MAP_DOWN:int = 1;
public const MAP_RIGHT:int = 2;
public const MAP_UP:int = 3;
public const MAP_STOP:int = 4;
public function search(map2:Array, i:int, j:int, a:Array, b:Array):void {
a[i][j] = 1;
b.push({ i:i, j:j });
var t:int = map2[i][j];
if ((t & 1 << MAP_DOWN) != 0 && a[i + 1][j] == 0) {
search(map2, i + 1, j, a, b);
}
if ((t & 1 << MAP_UP) != 0 && a[i - 1][j] == 0) {
search(map2, i - 1, j, a, b);
}
if ((t & 1 << MAP_RIGHT) != 0 && a[i][j + 1] == 0) {
search(map2, i, j + 1, a, b);
}
if ((t & 1 << MAP_LEFT) != 0 && a[i][j - 1] == 0) {
search(map2, i, j - 1, a, b);
}
}
public function canDown(map1:Array, map2:Array, i:int, j:int, a:Array, b:Array):Boolean {
search(map2, i, j, newArray(map1.length, map1[0].length), b);
if (map2[i][j] == 1 << MAP_STOP) {
//a[i][j] = 1;
return false;
}
for (var i:int = 0; i < b.length; i++) {
var ii:int = b[i].i;
var jj:int = b[i].j;
//a[ii][jj] = 1;
if ((map2[ii][jj] & 1 << MAP_DOWN) == 0) {
if (ii + 1 >= map1.length || map1[ii + 1][jj] != 0) {
return false;
}
}
}
return true;
}
public function down(map1:Array, map2:Array, a:Array, b:Array):void {
while (true) {
var flag:Boolean = true;
for (var i:int = 0; i < b.length - 1; i++) {
if (b[i].i < b[i+1].i) {
var ti:int = b[i].i;
var tj:int = b[i].j;
b[i].i = b[i + 1].i;
b[i].j = b[i + 1].j;
b[i + 1].i = ti;
b[i + 1].j = tj;
flag = false;
}
}
if (flag) {
break;
}
}
for (i = 0; i < b.length; i++) {
var t:Object = b[i];
map1[t.i + 1][t.j] = map1[t.i][t.j];
map2[t.i + 1][t.j] = map2[t.i][t.j];
a[t.i + 1][t.j] = 1;
map1[t.i][t.j] = 0;
map2[t.i][t.j] = 0;
a[t.i][t.j] = 0;
}
}
public function updateMap(map1:Array, map2:Array):Boolean {
var a:Array = newArray(map1.length, map1[0].length);
var flag:Boolean = false;
for (var i:int = map1.length - 2; i >= 0; i--) {
for (var j:int = 0; j < map1[0].length; j++) {
var b:Array = new Array();
if (a[i][j] == 0 && map1[i][j] != 0 && canDown(map1, map2, i, j, a, b)) {
down(map1, map2, a, b);
flag = true;
}
}
}
return flag;
}
}
}