Dotris
マジキチテトリス、始まるよー!!
←, → : 左右移動
↓ : 高速落下
↑ : ハードドロップ
z : 時計回り
x : 反時計回り
package{
/*
Dotris
Copyright (C) 2011 Susisu, All rights reserved.
http://susisu.ktkr.net/
*/
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.text.TextFieldType;
import flash.utils.Timer;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
[SWF(width="465",height="465",frameRate="60",backgroundColor="0xffffff")]
public class Dotris extends Sprite{
private var _width:int;
private var _height:int;
private var textFormatCenter:TextFormat;
private var textFormatLeft:TextFormat;
private var textFormatRight:TextFormat;
//title
private var titleSprite:Sprite;
private var titleText:TextField;
private var widthText:TextField;
private var heightText:TextField;
private var widthBox:TextField;
private var heightBox:TextField;
private var startButton:Sprite;
private var startButtonText:TextField;
private var copyrightText:TextField;
//game
private var gameSprite:Sprite;
private var canvas:BitmapData;
private var canvasContainer:Bitmap;
private var block:Array;
private var blockColor:uint;
private var blockX:int;
private var blockY:int;
private var blockWidth:int;
private var blockHeight:int;
private var blockEdge:Array;
private var waitingCounter:int;
private var blockCounter:Array;
private var blockPatterns:Array;
private var blockColors:Array;
private var downKeyIsDown:Boolean;
private var lineRect:Rectangle;
private var dPoint:Point;
private var scoreSprite:Sprite;
private var score:int;
private var scoreText:TextField;
private var speed:int;
private var waitingTime:int;
private var frameCounter:int;
private var time:uint;
private var timer:Timer;
public function Dotris(){
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
_width=256;
_height=192;
textFormatCenter=new TextFormat("_sans",10,0x000000,false,false,false,null,null,TextFormatAlign.CENTER);
textFormatLeft=new TextFormat("_sans",10,0x000000,false,false,false,null,null,TextFormatAlign.LEFT);
textFormatRight=new TextFormat("_sans",10,0x000000,false,false,false,null,null,TextFormatAlign.RIGHT);
//title
titleSprite=new Sprite();
titleSprite.x=(stage.stageWidth-256)/2>>0;
titleSprite.y=(stage.stageHeight-192)/2>>0;
titleText=new TextField();
titleText.x=0;
titleText.y=40;
titleText.width=256;
titleText.height=16;
titleText.selectable=false;
titleText.defaultTextFormat=textFormatCenter;
titleText.text="Dotris";
widthText=new TextField();
widthText.x=78;
widthText.y=60;
widthText.width=40;
widthText.height=16;
widthText.selectable=false;
widthText.defaultTextFormat=textFormatLeft;
widthText.text="width";
heightText=new TextField();
heightText.x=138;
heightText.y=60;
heightText.width=40;
heightText.height=16;
heightText.selectable=false;
heightText.defaultTextFormat=textFormatLeft;
heightText.text="height";
widthBox=new TextField();
widthBox.x=78;
widthBox.y=80;
widthBox.width=40;
widthBox.height=16;
widthBox.border=true;
widthBox.borderColor=0xc0c0c0;
widthBox.type=TextFieldType.INPUT;
widthBox.restrict="0-9";
widthBox.maxChars=4;
widthBox.defaultTextFormat=textFormatRight;
widthBox.text=stage.stageWidth.toString();//_width.toString();
heightBox=new TextField();
heightBox.x=138;
heightBox.y=80;
heightBox.width=40;
heightBox.height=16;
heightBox.border=true;
heightBox.borderColor=0xc0c0c0;
heightBox.type=TextFieldType.INPUT;
heightBox.restrict="0-9";
heightBox.maxChars=4;
heightBox.defaultTextFormat=textFormatRight;
heightBox.text=stage.stageHeight.toString();//_height.toString();
startButton=new Sprite();
startButton.x=98;
startButton.y=120;
startButton.buttonMode=true;
startButtonText=new TextField();
startButtonText.width=60;
startButtonText.height=16;
startButtonText.border=true;
startButtonText.mouseEnabled=false;
startButtonText.selectable=false;
startButtonText.defaultTextFormat=textFormatCenter;
startButtonText.text="start";
startButton.addChild(startButtonText);
startButton.addEventListener(MouseEvent.CLICK,startClick);
copyrightText=new TextField();
copyrightText.x=0;
copyrightText.y=160;
copyrightText.width=256;
copyrightText.height=32;
//copyrightText.selectable=false;
copyrightText.defaultTextFormat=textFormatCenter;
copyrightText.text="Copyright (C) 2011 Susisu\nhttp://susisu.ktkr.net/";
titleSprite.addChild(titleText);
titleSprite.addChild(widthText);
titleSprite.addChild(heightText);
titleSprite.addChild(widthBox);
titleSprite.addChild(heightBox);
titleSprite.addChild(startButton);
titleSprite.addChild(copyrightText);
//game
gameSprite=new Sprite();
gameSprite.x=(stage.stageWidth-_width)/2>>0;
gameSprite.y=(stage.stageHeight-_height)/2>>0;
canvas=new BitmapData(_width+2,_height+2,true,0x00000000);
canvasContainer=new Bitmap(canvas);
canvasContainer.x=-1;
canvasContainer.y=-1;
block=[];
blockColor=0xffff0000;
blockX=0;
blockY=0;
blockWidth=0;
blockHeight=0;
blockEdge=null;
waitingCounter=0;
blockCounter=null;
blockPatterns=[
[
[1,1,1,1]
],
[
[0,1,0],
[1,1,1]
],
[
[1,1],
[1,1]
],
[
[1,1,0],
[0,1,1]
],
[
[0,1,1],
[1,1,0]
],
[
[0,0,1],
[1,1,1]
],
[
[1,0,0],
[1,1,1]
],
];
blockColors=[
0xffff0000,
0xff00c0ff,
0xffc0c000,
0xff00c000,
0xffc000c0,
0xff0000ff,
0xfff08000
];
downKeyIsDown=false;
lineRect=new Rectangle(1,0,_width,1);
dPoint=new Point(1,2);
scoreSprite=new Sprite();
scoreSprite.alpha=0.5;
score=0;
scoreText=new TextField();
scoreText.width=stage.stageWidth;
scoreText.height=64;
scoreText.selectable=false;
scoreText.background=false;
scoreText.backgroundColor=0xffffff;
scoreText.defaultTextFormat=textFormatLeft;
scoreText.text="score : "+score+"\ntime : 0:00:00";
scoreSprite.addChild(scoreText);
speed=20;
waitingTime=2;
frameCounter=0;
time=0;
timer=new Timer(1000);
gameSprite.addChild(canvasContainer);
addChild(titleSprite);
stage.addEventListener(Event.RESIZE,resize);
}
private function startClick(e:MouseEvent):void{
_width=parseInt(widthBox.text);
_height=parseInt(heightBox.text);
if(_width<8){
_width=8;
widthBox.text=_width.toString();
}
else if(_width>stage.stageWidth){
_width=stage.stageWidth;
widthBox.text=_width.toString();
}
if(_height<16){
_height=16;
heightBox.text=_height.toString();
}
else if(_height>stage.stageHeight){
_height=stage.stageHeight;
heightBox.text=_height.toString();
}
init();
}
private function resize(e:Event):void{
titleSprite.x=(stage.stageWidth-256)/2>>0;
titleSprite.y=(stage.stageHeight-192)/2>>0;
widthBox.text=stage.stageWidth.toString();
heightBox.text=stage.stageHeight.toString();
gameSprite.x=(stage.stageWidth-_width)/2>>0;
gameSprite.y=(stage.stageHeight-_height)/2>>0;
scoreText.width=stage.stageWidth;
}
private function init():void{
gameSprite.x=(stage.stageWidth-_width)/2>>0;
gameSprite.y=(stage.stageHeight-_height)/2>>0;
canvas.dispose();
canvas=new BitmapData(_width+2,_height+2,true,0x00000000);
//draw border
var t:Rectangle=new Rectangle(0,0,_width+2,1);
canvas.fillRect(t,0xff000000);
t.y=_height+1;
canvas.fillRect(t,0xff000000);
t.y=0;
t.width=1;
t.height=_height+2;
canvas.fillRect(t,0xff000000);
t.x=_width+1;
canvas.fillRect(t,0xff000000);
canvasContainer.bitmapData=canvas;
setNewBlock();
drawBlock()
blockCounter=new Array(_height);
for(var i:int=0;i<_height;i++){
blockCounter[i]=0;
}
downKeyIsDown=false;
lineRect.width=_width;
score=0;
scoreSprite.alpha=0.5;
scoreText.width=stage.stageWidth;
scoreText.background=false;
scoreText.text="score : "+score+"\ntime : 0:00:00";
speed=20;
waitingTime=2;
frameCounter=0;
time=0;
timer.reset();
timer.addEventListener(TimerEvent.TIMER,timeOut);
timer.start();
removeChild(titleSprite);
addChild(gameSprite);
addChild(scoreSprite);
addEventListener(Event.ENTER_FRAME,enterFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUp);
stage.focus=stage;
}
private function quit():void{
removeChild(gameSprite);
removeChild(scoreSprite);
addChild(titleSprite);
}
private function timeOut(e:TimerEvent):void{
time++;
scoreText.text="score : "+score+"\ntime : "+getTimeText();
}
private function getTimeText():String{
var str:String=(time/3600>>0).toString()+":";
var t:uint=(time%3600)/60>>0;
if(t<10){
str+="0";
}
str+=t.toString()+":";
t=time%60;
if(t<10){
str+="0";
}
str+=t.toString();
return str;
}
private function enterFrame(e:Event):void{
if(frameCounter==speed){
moveBlock(0,1);
frameCounter=0;
}
frameCounter++;
}
private function keyDown(e:KeyboardEvent):void{
var keyCode:int=e.keyCode;
switch(keyCode){
case 37: //left
moveBlock(-1,0);
break;
case 39: //right
moveBlock(1,0);
break;
case 40: //down
downKeyIsDown=true;
moveBlock(0,1);
break;
case 38: //up
downKeyIsDown=true;
while(moveBlock(0,1)){}
downKeyIsDown=false;
break;
case 90: //z
rotateBlock(1);
break;
case 88: //x
rotateBlock(-1);
break;
}
}
private function keyUp(e:KeyboardEvent):void{
var keyCode:int=e.keyCode;
switch(keyCode){
case 40: //down
downKeyIsDown=false;
break;
}
}
private function gameoverClick(e:MouseEvent):void{
quit();
stage.removeEventListener(MouseEvent.CLICK,gameoverClick);
}
private function setNewBlock():void{
var r:int=Math.random()*7>>0;
block=blockPatterns[r].slice();
blockColor=blockColors[r];
blockWidth=block[0].length;
blockHeight=block.length;
blockX=Math.random()*(_width-blockWidth)>>0;//(_width-blockWidth)/2>>0;
blockY=0;
getBlockEdge();
waitingCounter=0;
//game over
if(blockHitTest()){
scoreSprite.alpha=0.75;
scoreText.background=true;
scoreText.text="score : "+score+"\ntime : "+getTimeText()+"\ngame over\nclick anywhere to back to title";
timer.stop();
timer.removeEventListener(TimerEvent.TIMER,timeOut);
removeEventListener(Event.ENTER_FRAME,enterFrame);
stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDown);
stage.removeEventListener(KeyboardEvent.KEY_UP,keyUp);
stage.addEventListener(MouseEvent.CLICK,gameoverClick);
}
}
private function getBlockEdge():void{
blockEdge=new Array(4); //top right bottom left
//top
blockEdge[0]=new Array(blockWidth);
for(var i:int=0;i<blockWidth;i++){
for(var j:int=0;j<blockHeight;j++){
if(block[j][i]==1){
blockEdge[0][i]=j;
break;
}
}
}
//right
blockEdge[1]=new Array(blockHeight);
for(i=0;i<blockHeight;i++){
for(j=blockWidth-1;j>=0;j--){
if(block[i][j]==1){
blockEdge[1][i]=blockWidth-1-j;
break;
}
}
}
//bottom
blockEdge[2]=new Array(blockWidth);
for(i=0;i<blockWidth;i++){
for(j=blockHeight-1;j>=0;j--){
if(block[j][i]==1){
blockEdge[2][i]=blockHeight-1-j;
break;
}
}
}
//left
blockEdge[3]=new Array(blockHeight);
for(i=0;i<blockHeight;i++){
for(j=0;j<blockWidth;j++){
if(block[i][j]==1){
blockEdge[3][i]=j;
break;
}
}
}
}
private function blockHitTest():Boolean{
for(var i:int=0;i<blockHeight;i++){
for(var j:int=0;j<blockWidth;j++){
if(block[i][j]==1&&uint(canvas.getPixel32(1+blockX+j,1+blockY+i)&0xff000000)==0xff000000){
return true;
}
}
}
return false;
}
private function blockBottomHitTest():Boolean{
for(var i:int=0;i<blockWidth;i++){
if(uint(canvas.getPixel32(1+blockX+i,1+blockY+blockHeight-1-blockEdge[2][i])&0xff000000)==0xff000000){
return true;
}
}
return false;
}
private function blockSideHitTest():Boolean{
for(var i:int=0;i<blockHeight;i++){
if(uint(canvas.getPixel32(1+blockX+blockEdge[3][i],1+blockY+i)&0xff000000)==0xff000000
||uint(canvas.getPixel32(1+blockX+blockWidth-1-blockEdge[1][i],1+blockY+i)&0xff000000)==0xff000000){
return true;
}
}
return false;
}
private function moveBlock(dx:int,dy:int):Boolean{
eraseBlock();
blockX+=dx;
blockY+=dy;
//canceling
var r:Boolean=true;
if(blockSideHitTest()){
blockX-=dx;
r=false;
}
if(blockBottomHitTest()){
blockY-=dy;
if(waitingCounter==waitingTime||downKeyIsDown){
drawBlock();
for(var j:int=0;j<blockHeight;j++){
for(var k:int=0;k<blockWidth;k++){
blockCounter[blockY+j]+=block[j][k];
}
}
deleteBlock();
setNewBlock();
}
else{
waitingCounter++;
}
r=false;
}
else if(dy!=0){
waitingCounter=0;
}
drawBlock();
return r;
}
private function rotateBlock(d:int):void{
var t:Array=new Array(blockWidth);
for(var i:int=0;i<blockWidth;i++){
t[i]=new Array(blockHeight);
}
if(d==1){ //clockwise
for(i=0;i<blockWidth;i++){
for(var j:int=0;j<blockHeight;j++){
t[i][j]=block[blockHeight-1-j][i];
}
}
}
else if(d==-1){ //counterclockwise
for(i=0;i<blockWidth;i++){
for(j=0;j<blockHeight;j++){
t[i][j]=block[j][blockWidth-1-i];
}
}
}
eraseBlock();
var b:Array=block;
block=t;
blockWidth=block[0].length;
blockHeight=block.length;
blockX+=(b[0].length-blockWidth)/2>>0;
blockY+=(b.length-blockHeight)/2>>0;
//canceling
if(blockHitTest()){
blockX-=(b[0].length-blockWidth)/2>>0;
blockY-=(b.length-blockHeight)/2>>0;
block=b;
blockWidth=block[0].length;
blockHeight=block.length;
}
getBlockEdge();
drawBlock();
}
private function drawBlock():void{
for(var i:int=0;i<blockHeight;i++){
for(var j:int=0;j<blockWidth;j++){
if(block[i][j]==1){
canvas.setPixel32(1+blockX+j,1+blockY+i,blockColor);
}
}
}
}
private function eraseBlock():void{
for(var i:int=0;i<blockHeight;i++){
for(var j:int=0;j<blockWidth;j++){
if(block[i][j]==1){
canvas.setPixel32(1+blockX+j,1+blockY+i,0x00000000);
}
}
}
}
private function deleteBlock():void{
for(var i:int=0;i<_height;i++){
if(blockCounter[i]==_width){
lineRect.y=i+1;
canvas.fillRect(lineRect,0x00000000);
var t:Rectangle=new Rectangle(1,1,_width,i);
canvas.copyPixels(canvas,t,dPoint);
lineRect.y=1;
canvas.fillRect(lineRect,0x00000000);
score++;
scoreText.text="score : "+score+"\ntime : "+getTimeText();
blockCounter.splice(i,1);
blockCounter.unshift(0);
}
}
}
}
}