In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Tetris

Get Adobe Flash player
by fokhei 31 Aug 2009
/**
 * Copyright fokhei ( http://wonderfl.net/user/fokhei )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xjsH
 */

package {
	import flash.display.Sprite;

	public class FlashTest extends Sprite {
		private var config:Config;
		private var game:Game;
		private var renderer:Renderer;

		public function FlashTest(){
	            config = new Config();
		    game = new Game();
		    game.init(config);
                       
			renderer = new Renderer();
			renderer.init(config, game);
			renderer.build();
			addChild(renderer);
                       game.start();                                                
			
		}
	}
}
/********************************************/
class Config {
	public var spaceColumn:uint = 23;
	public var spaceRow:uint = 23;
	public var blockSize:uint = 20;
}
/********************************************/
import flash.events.Event;

class GameEvent extends Event {
	static public const GAME_START:String = "GAME_START";
	static public const GAME_OVER:String = "GAME_OVER";
	static public const GAME_RESET:String = "GAME_RESET";
	static public const MAP_UPDATE:String = "MAP_UPDATE";

	public function GameEvent(type:String){
		super(type);
	}
}
/********************************************/
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.display.Sprite;

class Block {
	static public var TYPE_NONE:String = "0";
	static public var TYPE_I:String = "I";
	static public var TYPE_J:String = "J";
	static public var TYPE_L:String = "L";
	static public var TYPE_Q:String = "Q";
	static public var TYPE_S:String = "S";
	static public var TYPE_T:String = "T";
	static public var TYPE_Z:String = "Z";


	static public var TYPES:Array = [Block.TYPE_I, Block.TYPE_J, Block.TYPE_L, Block.TYPE_Q, Block.TYPE_S, Block.TYPE_T, Block.TYPE_Z];

	public var type:String = Block.TYPE_NONE;




	public function Block(type:String = "0"){
		this.type = type;
	}


	static public function getRandomType():String {
		var len:uint = Block.TYPES.length - 1;
		var r:Number = Math.round(Math.random() * len);
		return Block.TYPES[r];
	}



	public function getView(cfg:Config):DisplayObject {

		var size:uint = cfg.blockSize;
		var fillColor:uint;
		var fillAlpha:Number = 1;
		switch (type){
			case Block.TYPE_I:
				fillColor = 0x00F0F0;
				break;
			case Block.TYPE_J:
				fillColor = 0x0000F0;
				break;
			case Block.TYPE_L:
				fillColor = 0xF0A000;
				break;
			case Block.TYPE_Q:
				fillColor = 0xF0F000;
				break;
			case Block.TYPE_S:
				fillColor = 0x00F000;
				break;
			case Block.TYPE_T:
				fillColor = 0xA000F0;
				break;
			case Block.TYPE_Z:
				fillColor = 0xD80000;
				break;
			default:
			case Block.TYPE_NONE:
				return null;
				break;
		}
		var s:Sprite = new Sprite;
		var g:Graphics = s.graphics;
		g.beginFill(fillColor, fillAlpha);
		g.lineStyle(1, 0x666666, fillAlpha);
		g.drawRect(0, 0, size, size);
		g.endFill();
		return s;
	}



	public function toString():String {
		return this.type;
	}


}
/********************************************/
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Point;

class Puzzle {

	public var type:String;
	public var blocks:Array;
	public var position:Point;
	
	public function Puzzle(blockType:String = null){

		position = new Point(0, 0);
		if (blockType == null){
			blockType = Block.getRandomType();
		}
		changeType(blockType);

	}


	public function rotateArray2D(arr:Array):Array {

		var d1:Number = arr.length;
		var d2:Number = arr[0].length;
		var r:Array = new Array(d2);
		for (var i:Number = 0; i < d2; i++){
			var t:Array = new Array(d1);
			for (var j:Number = 0; j < d1; j++){
				t[j] = arr[d1 - 1 - j][i];
			}
			r[i] = t;
		}
		return r;
	}



	private function changeType(blockType:String):void {
		this.type = blockType;
		switch (type){

			case Block.TYPE_I:
				blocks = [[new Block(Block.TYPE_I), new Block(Block.TYPE_I), new Block(Block.TYPE_I), new Block(Block.TYPE_I)]]
				break;



			case Block.TYPE_J:
				blocks = [[new Block(Block.TYPE_J), new Block(Block.TYPE_NONE), new Block(Block.TYPE_NONE)], [new Block(Block.TYPE_J), new Block(Block.TYPE_J), new Block(Block.TYPE_J)]]
				break;


			case Block.TYPE_L:
				blocks = [[new Block(Block.TYPE_L), new Block(Block.TYPE_L), new Block(Block.TYPE_L)], [new Block(Block.TYPE_L), new Block(Block.TYPE_NONE), new Block(Block.TYPE_NONE)]

					]
				break;


			case Block.TYPE_Q:
				blocks = [[new Block(Block.TYPE_Q), new Block(Block.TYPE_Q)], [new Block(Block.TYPE_Q), new Block(Block.TYPE_Q)]

					]
				break;


			case Block.TYPE_S:
				blocks = [[new Block(Block.TYPE_NONE), new Block(Block.TYPE_S), new Block(Block.TYPE_S)], [new Block(Block.TYPE_S), new Block(Block.TYPE_S), new Block(Block.TYPE_NONE)]

					]
				break;

			case Block.TYPE_T:
				blocks = [[new Block(Block.TYPE_NONE), new Block(Block.TYPE_T), new Block(Block.TYPE_NONE)], [new Block(Block.TYPE_T), new Block(Block.TYPE_T), new Block(Block.TYPE_T)]

					]
				break;


			case Block.TYPE_Z:
				blocks = [[new Block(Block.TYPE_Z), new Block(Block.TYPE_Z), new Block(Block.TYPE_NONE)], [new Block(Block.TYPE_NONE), new Block(Block.TYPE_Z), new Block(Block.TYPE_Z)]

					]
				break;

			default:
			case Block.TYPE_NONE:
				blocks = []
				break;


		}


	}




	public function getView(cfg:Config):DisplayObject {
		var s:Sprite = new Sprite();
		var block:Block;
		var blockClip:DisplayObject;
		var h:uint = blocks.length;
		var w:uint = blocks[0].length;
		var ty:uint, tx:uint;
		for (ty = 0; ty < h; ty++){
			for (tx = 0; tx < w; tx++){
				block = blocks[ty][tx] as Block;
				if (block != null){
					blockClip = block.getView(cfg);
					if (blockClip != null){
						blockClip.x = tx * cfg.blockSize;
						blockClip.y = ty * cfg.blockSize;

						s.addChild(blockClip);
					}
				}
			}
		}
		return s;
	}

	public function rotateRight():void {
		blocks = rotateArray2D(blocks);
	}

	public function moveDown():void {
		position.y++;
	}

	public function moveRight():void {
		position.x++;
	}

	public function moveLeft():void {
		position.x--;
	}





	public function allowRotateRight(game:Game):Boolean {
		var clone:Array = rotateArray2D(blocks);
		var h:uint = clone.length;
		var w:uint = clone[0].length;
		var chkBlock:Block;
		var ty:int, tx:int;
		var cx:int, cy:int;
		for (ty = 0; ty < h; ty++){
			for (tx = 0; tx < w; tx++){

				if (clone[ty][tx].type == Block.TYPE_NONE){
					continue;
				} else {
					cx = this.position.x + tx;
					cy = this.position.y + ty;
					if (cx < 0 || cx >= game.cfg.spaceColumn || cy < 0 || cy >= game.cfg.spaceRow - 1){
						return false;
					}
					chkBlock = game.getBlock(cx, cy);
					if (chkBlock.type != Block.TYPE_NONE){
						return false;
					}

				}
			}
		}
		return true;
	}



	public function allowMoveDown(game:Game):Boolean {
		if ((position.y + blocks.length) >= game.cfg.spaceRow){
			return false;
		}
		var h:uint = blocks.length - 1;
		var w:uint = blocks[0].length;
		var ty:int, tx:int;
		var chkBlock:Block;
		var cx:int, cy:int;
		for (ty = h; ty > -1; ty--){
			for (tx = 0; tx < w; tx++){
				if (blocks[ty][tx].type == Block.TYPE_NONE){
					continue;
				} else {
					cx = this.position.x + tx;
					cy = this.position.y + ty + 1;
					chkBlock = game.getBlock(cx, cy);
					if (chkBlock.type != Block.TYPE_NONE){
						return false;
					}

				}

			}
		}
		return true;
	}





	public function allowMoveRight(game:Game):Boolean {
		if ((position.x + blocks[0].length) >= game.cfg.spaceColumn){
			return false;
		}
		var h:uint = blocks.length - 1;
		var w:uint = blocks[0].length - 1;
		var ty:int, tx:int;
		var chkBlock:Block;
		var cx:int, cy:int;
		for (ty = h; ty > -1; ty--){
			for (tx = w; tx > -1; tx--){


				if (blocks[ty][tx].type == Block.TYPE_NONE){
					continue;
				} else {
					cx = this.position.x + tx + 1;
					cy = this.position.y + ty;
					chkBlock = game.getBlock(cx, cy);
					if (chkBlock.type != Block.TYPE_NONE){
						return false;
					}

				}

			}
		}
		return true;

	}





	public function allowMoveLeft(game:Game):Boolean {
		if (position.x <= 0){
			return false;
		}
		var h:uint = blocks.length - 1;
		var w:uint = blocks[0].length;
		var ty:int, tx:int;
		var chkBlock:Block;
		var cx:int, cy:int;
		for (ty = h; ty > -1; ty--){
			for (tx = 0; tx < w; tx++){
				if (blocks[ty][tx].type == Block.TYPE_NONE){
					continue;
				} else {
					cx = this.position.x + tx - 1;
					cy = this.position.y + ty;
					chkBlock = game.getBlock(cx, cy);
					if (chkBlock.type != Block.TYPE_NONE){
						return false;
					}

				}
			}
		}
		return true;

	}



	public function appendToMap(game:Game):void {
		var h:uint = blocks.length;
		var w:uint = blocks[0].length;
		var ty:int, tx:int;
		var cx:int, cy:int;
		var block:Block;
		for (ty = 0; ty < h; ty++){
			for (tx = 0; tx < w; tx++){
				if (blocks[ty][tx].type == Block.TYPE_NONE){
					continue;
				} else {
					cx = this.position.x + tx;
					cy = this.position.y + ty;
					if (cy >= 0){
						block = game.getBlock(cx, cy) as Block;
						if (block != null){
							block.type = blocks[ty][tx].type;
						}
					}
				}
			}
		}
	}


	public function allowDropDown(game:Game):Boolean {
		var h:uint = blocks.length - 1;
		var w:uint = blocks[0].length;
		var ty:int, tx:int;
		var chkBlock:Block;
		var cx:int, cy:int;
		for (ty = h; ty > 0; ty--){
			for (tx = 0; tx < w; tx++){
				if (blocks[ty][tx].type == Block.TYPE_NONE){
					continue;
				} else {
					cx = this.position.x + tx;
					cy = this.position.y + ty;
					chkBlock = game.getBlock(cx, cy);
					if (chkBlock.type != Block.TYPE_NONE){
						return false;
					}

				}

			}
		}
		return true;
	}



}

/**********************************************************/
import flash.events.EventDispatcher;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Timer;

class Game extends EventDispatcher {
	public var cfg:Config;
	private var map:Array;
	public var activePuzzle:Puzzle;
	public var nextPuzzle:Puzzle;
	private var updateTimer:Timer;

	public function init(config:Config):void {
		cfg = config;
	}

	public function reset():void {
		updateTimer.stop();
		resetMap();
		activePuzzle = null;
		dispatchEvent(new GameEvent(GameEvent.GAME_RESET));
		start();
	}

	private function resetMap():void {
		map = new Array();
		var h:uint = cfg.spaceRow;
		var w:uint = cfg.spaceColumn;
		var ty:int, tx:int;
		for (ty = 0; ty < h; ty++){
			map[ty] = [];
			for (tx = 0; tx < w; tx++){
				map[ty][tx] = new Block(Block.TYPE_NONE);
			}
		}
		for (ty = 0; ty <= -1; ty--){
			for (tx = 0; tx < w; tx++){
				map[ty][tx] = new Block(Block.TYPE_NONE);
			}
		}
	}

	private function newRow():Array {
		var row:Array = new Array();
		var w:uint = cfg.spaceColumn;
		var tx:int;
		for (tx = 0; tx < w; tx++){
			row[tx] = new Block(Block.TYPE_NONE);
		}
		return row;
	}

	public function start():void {
		resetMap();
		if (hasEventListener(GameEvent.GAME_START)){
			dispatchEvent(new GameEvent(GameEvent.GAME_START));
		}
		nextPuzzle = new Puzzle(Block.getRandomType());
		updateTimer = new Timer(500);
		updateTimer.addEventListener(TimerEvent.TIMER, onUpdate);
		updateTimer.start()
	}

	public function getBlock(tx:int, ty:int):Block {
		return map[ty][tx] as Block;
	}

	private function allowDropPuzzle():Boolean {
		var testPuzzle:Puzzle = new Puzzle(nextPuzzle.type);
		testPuzzle.position = new Point(Math.floor((cfg.spaceColumn - testPuzzle.blocks[0].length) * 0.5), -1);
		return testPuzzle.allowDropDown(this);
	}

	private function dropPuzzle():void {
		activePuzzle = new Puzzle(nextPuzzle.type);
		activePuzzle.position = new Point(Math.floor((cfg.spaceColumn - activePuzzle.blocks[0].length) * 0.5), -1);
		nextPuzzle = new Puzzle(Block.getRandomType());
	}

	private function onUpdate(e:TimerEvent):void {
		update();
	}

	private function update():void {
		if (activePuzzle == null){
			if (allowDropPuzzle()){
				dropPuzzle();
			} else {
				updateTimer.stop();
				dispatchEvent(new GameEvent(GameEvent.GAME_OVER));
				reset();
			}
		} else {
			if (activePuzzle.allowMoveDown(this)){
				activePuzzle.moveDown();
			} else {
				activePuzzle.appendToMap(this);
				activePuzzle = null;
				var h:int = map.length;
				var w:int = map[0].length;
				var ty:int, tx:int;
				var cellCount:int;
				var removeIdx:Array = new Array();
				for (ty = 0; ty < h; ty++){
					cellCount = 0;
					for (tx = 0; tx < w; tx++){
						if (getBlock(tx, ty).type != Block.TYPE_NONE){
							cellCount++;
						}
					}
					if (cellCount == w){
						removeIdx.push(ty)
					}
				}
				var len:int = removeIdx.length;
				var removedRow:Array
				if (len > 0){
					var i:int = len - 1;
					for (i; i > -1; i--){
						removedRow = map.splice(removeIdx[i], 1);
					}
				}

				for (i = 0; i < len; i++){
					map.unshift(newRow());
				}



				if (hasEventListener(GameEvent.MAP_UPDATE)){
					dispatchEvent(new GameEvent(GameEvent.MAP_UPDATE));
				}

			}
		}
	}
}


/*******************************************************/
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.geom.Rectangle;

class Renderer extends Sprite {
	private var cfg:Config;
	private var game:Game;
	private var bg:Sprite;
	private var grid:Sprite;
	private var layerBlocks:Sprite;
	private var layerPuzzle:Sprite;
	private var layerMask:Rectangle;	
	public function init(config:Config, game:Game):void {
		this.game = game;
		this.cfg = config;		
		game.addEventListener(GameEvent.GAME_START, onGameStart);
		game.addEventListener(GameEvent.GAME_OVER, onGameOver);
		game.addEventListener(GameEvent.GAME_RESET, onGameReset);
		game.addEventListener(GameEvent.MAP_UPDATE, onMapUpdate);
		addEventListener(Event.ENTER_FRAME, onEnterFrame);
	}
	public function build():void {
		initBG();
		initGrid();
		initLayerBlocks();
		initLayerPuzzle();
		initMask();
	}
	private function initBG():void {
		bg = new Sprite();
		var g:Graphics = bg.graphics;
		g.beginFill(0xFFFFFF);
		g.drawRect(0, 0, cfg.spaceColumn * cfg.blockSize, cfg.spaceRow * cfg.blockSize);
		g.endFill();
		bg.mouseEnabled = false;
		addChild(bg);
	}
	private function initGrid():void {
		grid = new Sprite();
		var g:Graphics = grid.graphics;
		g.lineStyle(1, 0xCCCCCC, 0.5);
		var ty:int, tx:int;
		var w:int = cfg.spaceColumn * cfg.blockSize;
		var h:int = cfg.spaceRow * cfg.blockSize
		for (ty = 1; ty < cfg.spaceRow; ty++){
			g.moveTo(0, ty * cfg.blockSize);
			g.lineTo(w, ty * cfg.blockSize)
		}
		for (tx = 1; tx < cfg.spaceColumn; tx++){
			g.moveTo(tx * cfg.blockSize, 0);
			g.lineTo(tx * cfg.blockSize, h);
		}
		g.drawRect(0, 0, cfg.spaceColumn * cfg.blockSize, cfg.spaceRow * cfg.blockSize);
		grid.mouseEnabled = false;
		addChild(grid);
	}
	private function initMask():void {

		layerMask = new Rectangle(0, 0, cfg.spaceColumn * cfg.blockSize + 1, cfg.spaceRow * cfg.blockSize + 1);
		this.scrollRect = layerMask;
	}
	private function initLayerBlocks():void {
		layerBlocks = new Sprite();
		addChild(layerBlocks);
	}
	private function drawBlocks():void {
		var block:Block;
		var clip:DisplayObject;
		var ty:uint, tx:uint;
		while (layerBlocks.numChildren){
			layerBlocks.removeChildAt(0);
		}
		for (ty = 0; ty < cfg.spaceRow; ty++){
			for (tx = 0; tx < cfg.spaceColumn; tx++){
				block = game.getBlock(tx, ty) as Block;
				if (block != null && block.type != Block.TYPE_NONE){
					clip = block.getView(cfg) as DisplayObject;
					if (clip != null){
						clip.x = tx * cfg.blockSize;
						clip.y = ty * cfg.blockSize;
						layerBlocks.addChild(clip);
					}
				}
			}
		}
	}
	private function initLayerPuzzle():void {
		layerPuzzle = new Sprite();
		addChild(layerPuzzle);
	}
	private function updateLayerPuzzle():void {
		drawPuzzle(game.activePuzzle);
	}
	private function drawPuzzle(puzzle:Puzzle = null):void {		
		while (layerPuzzle.numChildren){
			layerPuzzle.removeChildAt(0);
		}
		if (puzzle != null){
			var puzzleClip:DisplayObject = puzzle.getView(cfg) as DisplayObject;
			if (puzzleClip != null){
				puzzleClip.x = puzzle.position.x * cfg.blockSize;
				puzzleClip.y = puzzle.position.y * cfg.blockSize;
				layerPuzzle.addChild(puzzleClip);
			}
		}
	}
	private function onEnterFrame(e:Event):void {
		update();
	}

	private function update():void {
		updateLayerPuzzle();
	}
	private function onGameStart(e:Event):void {
		//trace("onGameStart");
		drawBlocks();
		stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
	}
	private function onKeyDown(e:KeyboardEvent):void {
		//trace("onKeyDown:", e.keyCode);
		var p:Puzzle = game.activePuzzle;
		if (p != null){
			//Arrow Key or A,S,D,W
			if (e.keyCode == 37 || e.keyCode == 65){
				if (p.allowMoveLeft(game)){
					p.moveLeft();
				}
			}
			if (e.keyCode == 38 || e.keyCode == 87){
				if (p.allowRotateRight(game)){
					p.rotateRight();
				}
			}
			if (e.keyCode == 39 || e.keyCode == 68){
				if (p.allowMoveRight(game)){
					p.moveRight();
				}
			}
			if (e.keyCode == 40 || e.keyCode == 83){
				if (p.allowMoveDown(game)){
					p.moveDown();
				}
			}
		}
	}
	private function onMapUpdate(e:Event = null):void {		
		updateLayerPuzzle();
		drawBlocks();
	}
	private function onGameOver(e:Event = null):void {
		trace("onGameOver");
	}
	private function onGameReset(e:Event = null):void {
		trace("onGameReset");
		build();
	}

}