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); } } } } } Dotris