Tetris(テトリス)
操作方法
Enter:スタート
z,x,c:回転
→, ←:移動
↓:高速落下
↑:ハードドロップ
/**
* Copyright zukky162 ( http://wonderfl.net/user/zukky162 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rGAc
*/
package {
import flash.display.GradientType;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.utils.setInterval;
import flash.text.TextField;
//[SWF(width="320", height="240", backgroundColor="#000000")]
public class Tetris extends Sprite {
private var bg:Shape;
private var intervalId:Number;
private const BG_WIDTH:int = 300;
private const BG_HEIGHT:int = 360;
public function Tetris() {
bg = new Shape();
_global.matrix = new Matrix();
_global.matrix.createGradientBox(BG_WIDTH, BG_HEIGHT, Math.PI/4.0, 0, 0);
bg.graphics.beginGradientFill(
GradientType.LINEAR,
[0x444444, 0x000000],
[1, 1],
[0x00, 0xFF],
_global.matrix
);
bg.graphics.drawRect(0,0,BG_WIDTH,BG_HEIGHT);
bg.graphics.endFill();
addChild(bg);
_global.stage = stage;
_global.input = new Input();
_global.scene = new GameMain();
intervalId = flash.utils.setInterval(main, 17);
}
private function main() :void {
_global.scene.update();
_global.input.update();
}
}
}
const _global:Object = {};
_global.scene;
_global.input;
_global.stage;
_global.matrix;
class Input {
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
private var cnt:Array;
public function Input() {
cnt = new Array(256);
for(var i:int = 0; i < 256; ++i) cnt[i] = 0;
_global.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
_global.stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
}
public function update() :void{
for(var i:int = 0; i < 256; ++i) {
if(cnt[i] != 0) ++cnt[i];
}
}
public function getState(target:uint) :uint {
return cnt[target];
}
private function keyDown(e:KeyboardEvent) :void {
if(cnt[e.keyCode] == 0) cnt[e.keyCode] = 1;
}
private function keyUp(e:KeyboardEvent) :void {
cnt[e.keyCode] = 0;
}
}
class Scene {
public function Scene() :void {}
public function update() :int {
return 0;
}
}
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
class GameMain extends Scene {
private const WIDTH:int = 10;
private const HEIGHT:int = 20;
private var game:Game;
public function GameMain() :void {
game = new Game(20, 20);
}
override public function update() :int {
return game.update();
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.GradientType;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
class Game {
private const MODE_MAIN:int = 2;
private const MODE_GAMEOVER:int = 3;
private const WIDTH:int = 10;
private const HEIGHT:int = 20;
private const SIZE:int = 16;
private const GAME_NEXT_NUM:int = 3;
private var x:int, y:int;
private const BLOCK_COLOR:Array =
[0x000000, 0x00FFFF, 0x0000FF, 0xFF8800, 0x00FF00, 0xFF00FF, 0xFF0000, 0xFFFF00, 0x888888];
private const ERASE_POINT:Array = [0, 100, 300, 500, 800];
private var gra_bg:Shape;
private var gra_blo:Array;
private var gra_next:Array;
private var gra_score_tx:TextField;
private var game_mode:int;
private var game_wait:uint;
private var game_field:Array;
private var game_block:Block;
private var game_next:Next;
private var game_rcount:int;
private var game_gsp:Number;
private var game_gF:Number;
private var game_gf:Number;
private var game_aF:Number;
private var game_af:Number;
private var game_score:int;
public function Game(x:int, y:int) :void {
this.x = x;
this.y = y;
gra_init();
game_wait = 0;
game_field = new Array(HEIGHT);
for(var i:int = 0; i < HEIGHT; ++i) {
game_field[i] = new Array(WIDTH);
}
game_block = new Block();
game_next = new Next(GAME_NEXT_NUM);
init();
game_mode = MODE_GAMEOVER;
}
private function init() :void {
for(var i:int = 0; i < HEIGHT; ++i) {
for(var j:int = 0; j < WIDTH; ++j) {
game_field[i][j] = 0;
}
}
game_block.create(0);
game_rcount = 0;
game_gsp = 1;
game_gf = 0;
game_gF = 50;
game_af = -1;
game_aF = 40;
game_score = 0;
game_next.init();
game_mode = MODE_MAIN;
}
public function update() :int {
switch(game_mode) {
case MODE_MAIN: mode_main(); break;
case MODE_GAMEOVER: mode_gameover(); break;
}
draw();
return 0;
}
private function mode_main() :void{
if(game_wait > 0) {
--game_wait;
draw();
return;
}
if(game_block.getType() == 0) {
if(!apper()) {
game_mode = MODE_GAMEOVER;
allGray();
}
return;
}
if(_global.input.getState(90) == 1 || _global.input.getState(67) == 1) {
if(try_rotate(1)) ++game_rcount;
}
if(_global.input.getState(88) == 1) {
if(try_rotate(-1)) ++game_rcount;
}
if(_global.input.getState(37) == 1 || _global.input.getState(37) >= 8) { //left
try_move(-1);
}
if(_global.input.getState(38)) { //top
exdown();
}
if(_global.input.getState(39) == 1 || _global.input.getState(39) >= 8) { //right
try_move(1);
}
if(_global.input.getState(40)) { //down
if(game_af != -1) {
if(_global.input.getState(40) == 1) game_af = game_aF;
else ++game_af;
} else {
game_gf = game_gF;
}
}
down();
}
private function mode_gameover() :void{
if(_global.input.getState(13) == 1) {
init();
}
}
private function apper() : Boolean {
game_rcount = 0;
game_block.create(game_next.popNext());
if(_global.input.getState(90) || _global.input.getState(67)) game_block.rotate(1);
if(_global.input.getState(88)) game_block.rotate(-1);
if(canFix(game_block)) return true;
if(game_block.getDir() != 0) {
if(game_block.getDir() == 1) game_block.rotate(-1);
else game_block.rotate(1);
if(canFix(game_block)) return true;
}
return false;
}
private function allGray() : void {
var i:int, j:int;
for(i = 0; i < HEIGHT; ++i) {
for(j = 0; j < WIDTH; ++j) {
if(game_field[i][j] != 0) game_field[i][j] = 8;
}
}
}
private function try_rotate(d:int) :Boolean {
if(game_rcount >= 40) return false;
game_block.rotate(d);
if(!canFix(game_block)) {
if(try_move(1)) return true;
if(try_move(-1)) return true;
if(try_move2(1)) return true;
if(try_move2(-1)) return true;
game_block.rotate(-d);
return false;
} else {
return true;
}
}
private function try_move(d:int) :Boolean {
game_block.move(d);
if(!canFix(game_block)) {
game_block.move(-d);
return false;
} else {
return true;
}
}
private function try_move2(d:int) :Boolean {
game_block.down(d);
if(!canFix(game_block)) {
game_block.down(-d);
return false;
} else {
return true;
}
}
private function canDown() :Boolean {
game_block.down(1);
var flag:Boolean = canFix(game_block);
game_block.down(-1);
return flag;
}
private function down() :void{
if(!canDown()) {
if(game_af == -1) {
game_gf = 0;
game_af = 0;
}
} else {
game_af = -1;
}
if(game_af == -1) {
++game_gf;
if(game_gf >= game_gF) {
for(var i:int = 0; i < game_gsp; ++i) {
game_block.down(1);
if(!canFix(game_block)) {
game_block.down(-1);
break;
}
}
game_gf = 0;
}
} else {
++game_af;
if(game_af >= game_aF) {
fix();
eraseLine();
game_block.create(0);
game_af = -1;
game_gf = 0;
game_wait = 15;
}
}
}
private function exdown() :void{
do {
game_block.down(1)
} while(canFix(game_block));
game_block.down(-1);
}
private function canFix(b:Block) :Boolean {
for(var i:int = 0; i < 4; ++i) {
for(var j:int = 0; j < 4; ++j) {
var nx:int = b.getX() + j;
var ny:int = b.getY() + i;
if(game_block.isExist(nx, ny)) {
if(nx < 0 || nx >= WIDTH) return false;
if(ny >= HEIGHT) return false;
if(ny >= 0 && game_field[ny][nx] != 0) return false;
}
}
}
return true;
}
private function fix() :void{
for(var i:int = 0; i < 4; ++i) {
for(var j:int = 0; j < 4; ++j) {
var nx:int = game_block.getX() + j;
var ny:int = game_block.getY() + i;
if(game_block.isExist(nx, ny)) {
if(nx < 0 || nx >= WIDTH) continue;
if(ny < 0 || ny >= HEIGHT) continue;
if(game_field[ny][nx] != 0) continue;
game_field[ny][nx] = game_block.getType();
}
}
}
}
private function eraseOneLine(y:int) :void{
for(var i:int = y; i >= 0; --i) {
for(var j:int = 0; j < WIDTH; ++j) {
if(i-1 >= 0)
game_field[i][j] = game_field[i-1][j];
else
game_field[i][j] = 0;
}
}
}
private function eraseLine() :void{
var cnt:int = 0;
for(var i:int = HEIGHT-1; i >= 0; --i) {
for(var j:int = 0; j < WIDTH; ++j) {
if(game_field[i][j] == 0) break;
if(j+1 == WIDTH) {
eraseOneLine(i);
++cnt;
++i;
}
}
}
game_score += ERASE_POINT[cnt];
if(cnt >= 1) {
if(game_gF <= 1.0) {
game_gF = 1.0;
game_gsp += 0.2;
} else {
game_gF /= 1.2;
}
}
}
private function gra_init() :void {
var i:int;
gra_bg = new Shape();
_global.matrix.createGradientBox(WIDTH*SIZE, HEIGHT*SIZE, Math.PI/2.0, x, y);
gra_bg.graphics.beginGradientFill(
GradientType.LINEAR,
[0x333333, 0x888888],
[1, 1],
[0x00, 0xFF],
_global.matrix
);
gra_bg.graphics.drawRect(x, y, WIDTH*SIZE, HEIGHT*SIZE);
gra_bg.graphics.endFill();
_global.stage.addChild(gra_bg);
gra_blo = new Array(HEIGHT);
for(i = 0; i < HEIGHT; ++i) {
gra_blo[i] = new Array(WIDTH);
for(var j:int = 0; j < WIDTH; ++j) {
gra_blo[i][j] = new Shape();
gra_blo[i][j].x = x + SIZE*j;
gra_blo[i][j].y = y + SIZE*i;
_global.stage.addChild(gra_blo[i][j]);
}
}
gra_next = new Array(4*3);
for(i = 0; i < gra_next.length; ++i) {
gra_next[i] = new Array(4);
for(j = 0; j < gra_next[i].length; ++j) {
gra_next[i][j] = new Shape();
gra_next[i][j].x = x + SIZE*(WIDTH+1+j);
gra_next[i][j].y = y + SIZE*i;
_global.stage.addChild(gra_next[i][j]);
}
}
gra_score_tx = new TextField();
gra_score_tx.defaultTextFormat = new TextFormat("MS ゴシック", 16, 0xFFFFFF);
gra_score_tx.autoSize = TextFieldAutoSize.LEFT;
gra_score_tx.text = "SCORE\n1234567890";
gra_score_tx.x = 190;
gra_score_tx.y = 220;
_global.stage.addChild(gra_score_tx);
}
private function draw() :void {
var i:int, j:int, k:int;
for(i = 0; i < HEIGHT; ++i) {
for(j = 0; j < WIDTH; ++j) {
gra_blo[i][j].graphics.clear();
var blockColor:uint;
var flag:Boolean = true;
if(game_block.isExist(j, i)) {
blockColor = BLOCK_COLOR[game_block.getType()];
gra_blo[i][j].graphics.lineStyle(1, 0xFFFFFF, 1.0);
//gra_blo[i][j].graphics.beginFill(BLOCK_COLOR[game_block.getType()], 1.0);
} else {
if(game_field[i][j] == 0) {
flag = false;
} else {
blockColor = BLOCK_COLOR[game_field[i][j]];
gra_blo[i][j].graphics.lineStyle(1, 0x000000, 1.0);
}
}
if(flag) {
_global.matrix.createGradientBox(SIZE, SIZE, Math.PI/4.0, 0, 0);
gra_blo[i][j].graphics.beginGradientFill(
GradientType.LINEAR,
[0xFFFFFF, blockColor],
[1, 1],
[0x00, 0xFF],
_global.matrix
);
gra_blo[i][j].graphics.drawRect(0, 0, SIZE, SIZE);
gra_blo[i][j].graphics.endFill();
}
}
}
for(k = 0; k < GAME_NEXT_NUM; ++k) {
var type:int = game_next.getNext(k);
var b:Block = new Block();
b.create(type);
for(i = 0; i < 4; ++i) {
for(j = 0; j < 4; ++j) {
gra_next[i+k*4][j].graphics.clear();
if(b.isExist(b.getX()+j, b.getY()+i)) {
gra_next[i+k*4][j].graphics.lineStyle(1, 0x000000, 1.0);
_global.matrix.createGradientBox(SIZE, SIZE, Math.PI/4.0, 0, 0);
gra_next[i+k*4][j].graphics.beginGradientFill(
GradientType.LINEAR,
[0xFFFFFF, BLOCK_COLOR[type]],
[1, 1],
[0x00, 0xFF],
_global.matrix
);
gra_next[i+k*4][j].graphics.drawRect(0, 0, SIZE, SIZE);
gra_next[i+k*4][j].graphics.endFill();
}
}
}
}
gra_score_tx.text = "SCORE\n" + game_score;
}
}
class Block {
private var x:int, y:int, type:int, dir:int;
private const BLOCK:Array =
[
[
[
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
]
],
[
[
[0,0,0,0],
[1,1,1,0],
[0,1,0,0],
[0,0,0,0]
],
[
[0,1,0,0],
[0,1,1,0],
[0,1,0,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,1,0,0],
[1,1,1,0],
[0,0,0,0]
],
[
[0,1,0,0],
[1,1,0,0],
[0,1,0,0],
[0,0,0,0]
]
],
[
[
[0,0,0,0],
[1,1,1,0],
[0,0,1,0],
[0,0,0,0]
],
[
[0,1,1,0],
[0,1,0,0],
[0,1,0,0],
[0,0,0,0]
],
[
[0,0,0,0],
[1,0,0,0],
[1,1,1,0],
[0,0,0,0]
],
[
[0,1,0,0],
[0,1,0,0],
[1,1,0,0],
[0,0,0,0]
]
],
[
[
[0,0,0,0],
[1,1,1,0],
[1,0,0,0],
[0,0,0,0]
],
[
[0,1,0,0],
[0,1,0,0],
[0,1,1,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,0,1,0],
[1,1,1,0],
[0,0,0,0]
],
[
[0,0,0,0],
[1,1,0,0],
[0,1,0,0],
[0,1,0,0]
]
],
[
[
[0,0,0,0],
[1,1,0,0],
[0,1,1,0],
[0,0,0,0]
],
[
[0,0,1,0],
[0,1,1,0],
[0,1,0,0],
[0,0,0,0]
],
[
[0,0,0,0],
[1,1,0,0],
[0,1,1,0],
[0,0,0,0]
],
[
[0,0,1,0],
[0,1,1,0],
[0,1,0,0],
[0,0,0,0]
]
],
[
[
[0,0,0,0],
[0,1,1,0],
[1,1,0,0],
[0,0,0,0]
],
[
[1,0,0,0],
[1,1,0,0],
[0,1,0,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,1,1,0],
[1,1,0,0],
[0,0,0,0]
],
[
[1,0,0,0],
[1,1,0,0],
[0,1,0,0],
[0,0,0,0]
]
],
[
[
[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]
],
[
[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]
]
],
[
[
[0,0,0,0],
[0,1,1,0],
[0,1,1,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,1,1,0],
[0,1,1,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,1,1,0],
[0,1,1,0],
[0,0,0,0]
],
[
[0,0,0,0],
[0,1,1,0],
[0,1,1,0],
[0,0,0,0]
]
]
];
public function Block() :void {}
public function create(type:int) :void {
x = 3, y = -1, this.type = type, dir = 0;
}
public function isExist(tx:int, ty:int) :Boolean {
var nx:int = tx - x;
var ny:int = ty - y;
if(nx < 0 || nx >= 4) return false;
if(ny < 0 || ny >= 4) return false;
return BLOCK[type][dir][ny][nx] != 0;
}
public function rotate(d:int) :void { dir = (dir+4+d)%4; }
public function down(d:int) :void { y += d; }
public function move(d:int) :void { x += d; }
public function getX() :int { return x; }
public function getY() :int { return y; }
public function getType() :int { return type; }
public function getDir() :int { return dir; }
}
class Next {
private const NUM_TYPE:int = 7;
private var v:Array, npos:int;
private var count:Array;
public function Next(size:int) :void {
v = new Array(size);
count = new Array(NUM_TYPE);
init();
}
public function init() :void {
for(var i:int = 0; i < count.length; ++i) count[i] = 0;
npos = 0;
for(i = 0; i < v.length; ++i) {
pushNext();
}
}
private function make() : int {
return Math.floor(Math.random()*NUM_TYPE)+1;
}
private function pushNext() : void {
var buf:Array = new Array(count.length);
var size:int = 0;
for(var i:int = 0; i < count.length; ++i) {
if(count[i] >= NUM_TYPE) {
buf[size++] = i;
}
}
var nt:int;
if(size == 0) {
nt = make();
} else {
nt = buf[Math.floor(Math.random()*size)] + 1;
}
for(i = 0; i < count.length; ++i) {
if(i+1 == nt) count[i] = 0;
else ++count[i];
}
v[npos] = nt;
npos = (npos+1)%v.length;
}
public function popNext() : int {
var res:int = v[npos];
pushNext();
return res;
}
public function getNext(d:int) :int {
return v[(npos+d)%v.length];
}
}