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

ぷよぷよ

GAME :: ぷよぷよ

[←][↓][→]: 移動
[Z]: 左回転
[X]: 右回転
[C]: 下まで一気に落下

できたらいいな、300連鎖♪
Get Adobe Flash player
by daniwell 12 Feb 2012
/**
 * Copyright daniwell ( http://wonderfl.net/user/daniwell )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gDzo
 */

package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.ShaderParameter;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.ui.Keyboard;
	
	[SWF(backgroundColor = "0x555555", frameRate = "30", width = "465", height = "465")]
	public class Puyopuyo extends Sprite 
	{
		private const NUM_W:uint = 40;	// ヨコ 個数
		private const NUM_H:uint = 40;	// タテ 個数
		
		private const COLOR1:Vector.<uint> = Vector.<uint>([0xffffff, 0xff3300, 0x33ee00, 0x3366ff, 0xffcc00]);
		private const COLOR2:Vector.<uint> = Vector.<uint>([0xffffff, 0xff9966, 0x88ff55, 0x88aaff, 0xffee44]);
		
		private const BLOCK :Array = 
		[
			[[0, 2, 0],[0, 1, 0],[0, 0, 0]],
			[[0, 0, 0],[0, 1, 2],[0, 0, 0]],
			[[0, 0, 0],[0, 1, 0],[0, 2, 0]],
			[[0, 0, 0],[2, 1, 0],[0, 0, 0]]
		];
		
		private var phase:int;
		private var map  :Vector.<Vector.<Puyo>>;
		
		private var bmd:BitmapData;
		private var bmp:Bitmap;
		
		private var nowX:int = int((NUM_W - 3) / 2);
		private var nowY:int = 0;
		private var num :int = 0;	// BLOCK 番号
		
		private var maxH:Vector.<int> = new Vector.<int>(NUM_W);
		private var tmpH:Vector.<int> = new Vector.<int>(NUM_W);
		
		private var nowCols :Vector.<int> = Vector.<int>([rand(), rand()]);
		private var nextCols:Vector.<int> = Vector.<int>([rand(), rand()]);
		
		private var que :Vector.<Puyo> = new Vector.<Puyo>();
		private var isChain :Boolean = false;
		
		private var interval   :int = 30;
		private var intervalCt :int = 0;
		private var time :int = 0;
		
		private var chainCt :uint;
		private var status  :Status;
		private var mapRect :Rectangle = new Rectangle(0, 0, NUM_W, NUM_H);
		
		private var keyFlags  :Array = new Array();
		private var keyCounts :Array = new Array();
		
		private var tf :TextField = new TextField();
		
		public function Puyopuyo():void 
		{
			graphics.beginFill(0x555555); graphics.drawRect(0,0,465,465);
			
			bmd = new BitmapData(NUM_W + 5, NUM_H, false, 0x555555);
			bmp = new Bitmap(bmd);
			bmp.scaleX = bmp.scaleY = 10;
			addChild(bmp);
			
			// map 初期化
			map = new Vector.<Vector.<Puyo>>(NUM_H);
			for (var i :int = 0; i < NUM_H; i ++)
			{
				map[i] = new Vector.<Puyo>(NUM_W);
				for (var j :int = 0; j < NUM_W; j ++)
				{
					var puyo :Puyo = new Puyo();
					puyo.x = j;
					puyo.y = i;
					map[i][j] = puyo;
				}
			}
			
			status = new Status();
			status.addScore(0);
			status.setChain(0);
			addChild(status);
			
			status.x = status.y = bmp.x = 10;
			bmp.y = int(status.y + status.height + 5);
			
			tf.defaultTextFormat = new TextFormat("_sans", 10, 0xffffff); tf.autoSize = "left"; tf.selectable = false;
			tf.text = "CLICK TO START"; tf.x = (465 - tf.width) / 2; tf.y = (465 - tf.height) / 2;
			addChild(tf);
			
			stage.addEventListener(MouseEvent.CLICK, clickHandler);
		}
		private function clickHandler(e:MouseEvent = null):void
		{
			tf.visible = false;
			
			bmd.fillRect(new Rectangle(NUM_W + 1, 0, 3, 4), 0xffffff);
			bmd.setPixel(NUM_W + 2, 1, COLOR1[nextCols[1]]);
			bmd.setPixel(NUM_W + 2, 2, COLOR1[nextCols[0]]);
			
			// 配列初期化
			for (var i :int = 0; i < NUM_H; i ++)
				for (var j :int = 0; j < NUM_W; j ++)
					map[i][j].type = 0;
			
			for (i = 0; i < NUM_W; i ++) { maxH[i] = NUM_H - 1; tmpH[i] = -1; }
			
			status.reset();
			interval = 30;
			phase = 1;
			render();
			
			stage.removeEventListener(MouseEvent.CLICK, clickHandler);
			stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
		}
		/* ENTER FRAME */
		private function enterFrameHandler(e:Event):void
		{
			if (phase == 1)     loopPhase1(); /* phase1 (操作) */
			else if(phase == 2) loopPhase2(); /* phase2 (探索, 落下) */
		}
		private function loopPhase1():void
		{
			intervalCt ++;
			
			// 落下速度アップ(とりあえずなし)
			// time ++; if (time % 1800 == 0) interval = (2 <= interval)? interval - 1:1;
			
			var tmp:int = (nowY != 0)? interval:Math.max(NUM_W, interval);
			
			if (keyFlags[37]) if (keyCounts[37]++ == 0 || 4 < keyCounts[37]) move(-1);
			if (keyFlags[39]) if (keyCounts[39]++ == 0 || 4 < keyCounts[39]) move(1);
			if (keyFlags[90]) if (keyCounts[90]++ == 0 || 4 < keyCounts[90]) rotate();
			if (keyFlags[88]) if (keyCounts[88]++ == 0 || 4 < keyCounts[88]) rotate(true);
			if (keyFlags[40]) move(1, true, true);
			if (keyFlags[67]) while(phase==1) move(1, true, true);
			
			if (tmp <= intervalCt) { move(1, true); intervalCt = 0; }
		}
		private function loopPhase2():void
		{
			intervalCt ++;
			switch ( intervalCt )
			{
				case  3: fallPuyo();	break;
				case  9: searchStep();	break;
				case 18: fallStep();	break;
			}
		}
		/* 移動 */
		private function move ( n :int, isY :Boolean = false, isScore :Boolean = false ) :void
		{
			if ( ! isY ) /* x 方向 */
			{
				if ( ! check(BLOCK[num], nowX + n, nowY) ) nowX += n;
			}
			else /* y 方向 */
			{
				if (isScore) status.addScore(1);
				
				if ( ! check(BLOCK[num], nowX, nowY + n) ) nowY += n;
				else { intervalCt = 0; phase = 2; return; }
			}
			render();
		}
		/* 回転 */
		private function rotate ( isRight :Boolean = false ) :void
		{
			var nn :int;
			if (isRight)	nn = (num + 1 < 4)? num + 1:0;
			else			nn = (0 <= num - 1)? num - 1:3;
			
			var tmp :int = num; num = nn;
			if ( check(BLOCK[nn], nowX, nowY) )
			{
				if ( nn == 2 ) nowY --;
				else if ( nn == 1 || nn == 3 )
				{
					if ( ! check(BLOCK[nn], nowX + (nn - 2), nowY) ) nowX += (nn - 2);
					else
					{
						num = - (tmp - 2);
						if ( check(BLOCK[num], nowX, nowY) ) nowY --;
					}
				}
			}
			render();
		}
		/* ぷよ接地ステップ */
		private function fallPuyo () :void
		{
			var px :int, py :int;
			var ar :Array = BLOCK[num];
			
			chainCt = 0;
			
			for (var i :int = 2; 0 <= i; i --)
			{
				py = i + nowY;
				for (var j :int = 0; j < 3; j ++)
				{
					px = j + nowX;
					if ( 0 < ar[i][j] )
					{
						map[py][px].type = nowCols[ar[i][j] - 1];
						fall( px, py );
						
						if (tmpH[px] < maxH[px] + 1) tmpH[px] = maxH[px] + 1;
					}
				}
			}
			render();
		}
		/* 探索ステップ */
		private function searchStep ():void
		{
			var i :int, j :int;
			var tH :Vector.<int> = Vector.<int>(tmpH.concat()); // Vector コピー
			for (i = 0; i < NUM_W; i ++) tmpH[i] = -1;	// 初期化
			
			for (i = 0; i < NUM_W; i ++)
			{
				if (tH[i] == -1) continue;
				for (j = tH[i]; 0 <= j; j --) search(i, j);
			}
			render();
		}
		/* 落下ステップ */
		private function fallStep ():void
		{
			var i :int, j :int;
			
			if (isChain)	// 1 箇所でも消えた
			{
				chainCt ++;
				
				for (i = 0; i < NUM_W; i ++)
				{
					if (tmpH[i] == -1) continue;
					for (j = tmpH[i]; 0 <= j; j --) fall(i, j);
				}
				isChain = false;
				intervalCt = 4;
			}
			else
			{
				nowX = int((NUM_W - 3) / 2);
				nowY = 0;
				
				num = 0;
				intervalCt = 0;
				
				nowCols[0] = nextCols[0]; nextCols[0] = rand();
				nowCols[1] = nextCols[1]; nextCols[1] = rand();
				
				bmd.setPixel(NUM_W + 2, 1, COLOR1[nextCols[1]]);
				bmd.setPixel(NUM_W + 2, 2, COLOR1[nextCols[0]]);
				
				if (!check(BLOCK[num], nowX, nowY))	phase = 1;
				else								gameover();
			}
			render();
			status.setChain(chainCt);
		}
		private function gameover ():void
		{
			stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			stage.addEventListener(MouseEvent.CLICK, clickHandler);
		}
		/* 落下 */
		private function fall (nx:int, ny:int) :void
		{
			var nn :int = maxH[nx];
			
			if (0 <= nn && 0 < map[ny][nx].type)
			{
				if (nn != ny)
				{
					map[nn][nx].type = map[ny][nx].type;
					map[ny][nx].type = 0;
				}
				maxH[nx] = nn - 1;
			}
		}
		private function render ( ) :void
		{
			bmd.lock();
			bmd.fillRect(mapRect, COLOR1[0]);
			
			for (var i :int = 0; i < NUM_H; i ++)
				for (var j :int = 0; j < NUM_W; j ++)
					bmd.setPixel(j, i, COLOR1[map[i][j].type]);
			
			if (phase == 1)
			{
				var px:int, py:int;
				var ar :Array = BLOCK[num];
				
				for (i = 0; i < 3; i ++)
				{
					py = i + nowY;
					for (j = 0; j < 3; j ++)
					{
						px = j + nowX;
						if ( 0 < ar[i][j] )
						{
							var n:int = ((num == 0 && ar[i][j] == 2) || (num == 2 && ar[i][j] == 1))? 1:0;
							bmd.setPixel(px, maxH[px] - n, COLOR2[nowCols[ar[i][j] - 1]]);
							bmd.setPixel(px, py, COLOR1[nowCols[ar[i][j] - 1]]);
						}
					}
				}
			}
			bmd.unlock();
		}
		/* 衝突チェック */
		private function check(ar:Array, nx:int, ny:int):Boolean
		{
			var px :int, py :int;
			
			for (var i :int = 0; i < 3; i ++)
			{
				py = i + ny;
				for (var j :int = 0; j < 3; j ++)
				{
					px = j + nx;
					if ( 0 < ar[i][j] )
					{
						if ((px < 0 || NUM_W <= px) || (py < 0 || NUM_H <= py)) return true; // 壁
						if (0 < map[py][px].type) return true; // ぷよ
					}
				}
			}
			return false;
		}
		/* 探索開始 */
		private function search(nx:int, ny:int):void
		{
			if (map[ny][nx].type == 0) return;
			
			searchLoop(map[ny][nx].type, nx, ny); /* 再帰探索 */
			
			if (4 <= que.length) // 4 連結以上
			{
				// score 加算
				status.addScore( generateScore(que.length, chainCt) );
				
				while (que.length != 0)
				{
					var p:Puyo = que.pop();
					p.flag = false;
					p.type = 0;
					
					tmpH[p.x] = maxH[p.x] = Math.max(maxH[p.x], p.y);
				}
				isChain = true;
			}
			else while (que.length != 0) que.pop().flag = false;
		}
		/* 再起探索 */
		private function searchLoop(n:int, nx:int, ny:int):void
		{
			// 探索済み or 不一致の場合
			if (map[ny][nx].flag || n != map[ny][nx].type) return;
			
			map[ny][nx].flag = true;
			que.push(map[ny][nx]);
			
			if (0 <= nx - 1)	searchLoop(n, nx - 1, ny);
			if (nx + 1 < NUM_W)	searchLoop(n, nx + 1, ny);
			if (0 <= ny - 1)	searchLoop(n, nx, ny - 1);
			if (ny + 1 < NUM_H)	searchLoop(n, nx, ny + 1);
		}
		
		private function keyDownHandler(e:KeyboardEvent):void
		{
			if (phase != 1) return;
			keyCounts[e.keyCode] = 0;
			keyFlags[e.keyCode] = true;
		}
		private function keyUpHandler(e:KeyboardEvent):void
		{
			keyFlags[e.keyCode] = false;
		}
		
		private function generateScore(len:uint, chain:uint):uint
		{
			var k:uint;
			if (chain == 0)		k = 1;
			else if (chain < 3)	k = chain * 8;
			else 				k = (chain - 2) * 32;
			
			if (5 <= len) k += (len - 4) + 1;
			
			return k * (len * 10);
		}
		private function rand(max:int = 4, min:int = 1):int { return int(Math.random() * (max - min + 1)) + min; }
	}
}
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;

class Status extends Sprite
{
	private var _score      :uint = 0;
	private var _chain      :uint = 0;
	private var _tfMaxChain :TextField;
	private var _tfScore    :TextField;
	
	public function Status()
	{
		_tfMaxChain = createTextField(); _tfMaxChain.y = 13;
		_tfScore    = createTextField();
		
		addChild(_tfMaxChain);
		addChild(_tfScore);
	}
	public function addScore(n:uint):void
	{
		_score += n;
		_tfScore.text = "score: " + _score;
	}
	public function setChain(n:uint):void
	{
		if (n < _chain) return;
		_chain = n;
		_tfMaxChain.text = "chain: " + _chain;
	}
	public function reset():void
	{
		_score = 0; _tfScore.text = "score: " + _score;
		_chain = 0; _tfMaxChain.text = "chain: " + _chain;
	}
	private function createTextField():TextField
	{
		var format :TextFormat = new TextFormat("_等幅", 10, 0xffffff);
		format.letterSpacing = 1;
		
		var tf :TextField = new TextField();
		tf.autoSize = "left";
		tf.defaultTextFormat = format;
		
		return tf;
	}
}
class Puyo
{
	public var type:int = 0;
	public var flag:Boolean = false;
	public var x   :int;
	public var y   :int;
}