flash on 2009-5-9
package
{
import flash.display.*;
import flash.events.Event;
[SWF(backgroundColor = "0x000000", width = "465", height = "465", framerate = "24")]
public class Main extends Sprite
{
private var myIniPhase:InitialPhase;
private var myGamePhase:GamePhase;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
/// タイトル画面
myIniPhase = new InitialPhase();
myIniPhase.addEventListener(InitialPhase.START, onStart);
addChild(myIniPhase);
myIniPhase.Start();
}
/// ゲームをスタートさせる
private function onStart(event:Event) : void
{
myGamePhase = new GamePhase();
if ( stage.contains(myIniPhase) ) { removeChild(myIniPhase); }
if ( !stage.contains(myGamePhase) ) { addChild(myGamePhase); }
myGamePhase.Start();
}
}
}
import flash.display.*;
import flash.events.MouseEvent;
import flash.ui.Mouse;
class Block extends Sprite
{
private var myShape:Shape;
private var mySelectedShape:Shape;
private var mySize:uint = 50;
private var myColor:uint;
private var myOffset:uint;
// プロパティ
public function get Color(): uint {
return myColor;
}
public function Block(size:uint, offset:uint, color:uint)
{
// initialization
mySize = size;
myColor = color;
myOffset = offset;
draw();
mySelectedShape.visible = false; // デフォルト
}
/// 色を変えて再描画
public function ChangeColor( sColor:uint ):void {
myColor = sColor;
draw();
}
/// blockの描画
private function draw():void {
// childをクリア
while ( this.numChildren ) {
this.removeChildAt(0);
}
/// 簡単な表示オブジェクトで当面は代用
myShape = new Shape();
mySelectedShape = new Shape();
myShape.graphics.beginFill(myColor, 0.8);
myShape.graphics.drawRoundRect( myOffset-mySize, myOffset-mySize, (mySize-myOffset)*2, (mySize-myOffset)*2, (mySize-myOffset*2) / 2);
myShape.graphics.endFill();
var pushedColor:uint = UpBrightness(myColor, 80);
mySelectedShape.graphics.beginFill(pushedColor, 0.8);
mySelectedShape.graphics.drawRoundRect( myOffset-mySize, myOffset-mySize, (mySize-myOffset)*2, (mySize-myOffset)*2, (mySize-myOffset*2) / 2);
mySelectedShape.graphics.endFill();
mySelectedShape.graphics.lineStyle(myOffset, 0xffffff);
mySelectedShape.graphics.drawRoundRect( myOffset / 2 - mySize, myOffset / 2 - mySize, mySize * 2 - myOffset, mySize * 2 - myOffset, (mySize-myOffset * 2) / 2);
this.addChild(myShape);
this.addChild(mySelectedShape);
mySelectedShape.visible = false;
}
private function UpBrightness (color:uint, gain:int) : uint {
var b:uint = 0xff, y:uint = 0;
for ( var i:uint = 0 ; i < 3 ; i++ ) {
var x:uint = color;
x >>= i * 8;
x &= b;
if ( gain > 0 ) {
x += gain;
if ( x > b ) x = b;
} else {
if ( -gain > x ) x = 0;
else x += gain;
}
y += x << i * 8;
}
return y;
}
public function Select() : void {
mySelectedShape.visible = true;
myShape.visible = false;
}
public function UnSelect() : void {
myShape.visible = true;
mySelectedShape.visible = false;
}
}
class BlockColor
{
public static const RED:uint = 0xff0000;
public static const BLUE:uint = 0x0000ff;
public static const YELLOW:uint = 0xffff00;
public static const GREEN:uint = 0x008000;
public static const PURPLE:uint = 0x800080;
//public static const OLIVE:uint = 0x804000;
private static const myColorList:Array = [RED, BLUE, YELLOW, GREEN, PURPLE, /*OLIVE*/];
public function BlockColor() { }
public static function GetColorList() : Array {
return myColorList;
}
}
class BlockEvent extends Event
{
/*** イベントメッセージ定数 ***/
public static const ROTATION_ENDING:String = "BlockEvent.RotationEnding";
public static const FALLING_ENDING:String = "BlockEvent.FallingEnding";
// イベントのプロパティ
private var myIsRotationDirRight:Boolean;
public function get IsRotationDirRight():Boolean { return myIsRotationDirRight; }
public function BlockEvent(type:String, sIsRotationDirRight:Boolean = false, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
myIsRotationDirRight = sIsRotationDirRight;
}
public override function clone():Event
{
return new BlockEvent(type, myIsRotationDirRight, bubbles, cancelable);
}
public override function toString():String
{
return formatToString("BlockEvent", "type", "bubbles", "cancelable", "eventPhase");
}
}
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
/**
* 現在の仕様ではブロックの縦×横サイズは固定。
*/
class BlockTable extends Shape // Shapeでいいの? > DisplayObject クラスがEventDispatcherを持つ
{
/// private variables
private var myWidth:uint;
private var myHeight:uint;
private var myBlockSize:uint = 25; // [TODO] setter
private var myBlockOffset:uint = 2; // [TODO] setter
private var myBlocks:Vector.<Vector.<Block>>; // ブロックの二次元配列
/*** アニメーション用変数 ***/
private var myRotateCounter:uint = 0; // ブロックの回転アニメーションで使用するフレームカウンタ
private var myRotateTargetX:uint; // 回転ブロックの左上ブロックの位置(横軸)
private var myRotateTargetY:uint; // 回転ブロックの左上ブロックの位置(縦軸)
private var myFrameNumRotate:uint; // アニメーションが終了するまでのフレーム数
private var mySelfRotation:uint; // ブロックの自転角度(等角速度)
//
private var myEraseCounter:uint = 0;
private var myFallCounter:uint = 0;
private var myEraseBlocks:Vector.<Block>;
private var myFramNumErase:uint;
private var myFallSpeed:uint;
private var myFallingBlocks:Vector.<Array>; // Vector.<[Block,Point,Point]>での動作を前提とする
/// constructor
/** [TODO] サイズが(0,0)だったときの処理
*/
public function BlockTable(widthSize:uint, heightSize:uint, blockSize:uint, blockOffset:uint = 0 )
{
// 変数初期化
myWidth = widthSize;
myHeight = heightSize;
myBlockSize = blockSize;
myBlockOffset = blockOffset;
myBlocks = new Vector.<Vector.<Block>>(widthSize, true);
for (var i:uint = 0; i < widthSize ; i++ ) {
myBlocks[i] = new Vector.<Block>(heightSize, true);
}
}
/// ある座標のブロックを作成する。
/** 色の指定が無い場合、色はランダムに選ばれる。
* その座標にすでにブロックが存在していた場合、何も行われない([TODO] エラーを投げる?)
*/
public function CreateBlock(sX:uint, sY:uint, sColor:uint = 0):Block {
var color:uint = sColor;
if ( arguments.length == 2 ) {
const colorList:Array = BlockColor.GetColorList();
color = colorList[Math.floor(Math.random() * colorList.length)];
}
var retBlock:Block = new Block(myBlockSize, myBlockOffset, color);
myBlocks[sX][sY] = retBlock;
// ブロックの位置を決める(ブロック座標はブロックの中心)
var coodinate:Point = GetCoodinate(sX, sY);
retBlock.x = coodinate.x;
retBlock.y = coodinate.y;
return retBlock;
}
/// 管理インデックスから実際の座標を取得する
private function GetCoodinate(sX:int, sY:int) :Point{
return new Point( myBlockSize + sX * myBlockSize * 2,
myBlockSize + sY * myBlockSize * 2);
}
/// 引数で指定された座標のブロックを選択状態に変化させる [TODO] true:Block/false:nullを返す?
public function SelectBlock(sX:uint, sY:uint) : void {
myBlocks[sX][sY].Select();
}
/// 引数で指定された座標のブロックを非選択状態に変化させる [TODO] true:Block/false:nullを返す?
public function UnSelectBlock(sX:uint, sY:uint) : void {
myBlocks[sX][sY].UnSelect();
}
/// 引数で渡されたブロックを消去し、消えてなくなったブロックの隙間にブロックを落下させる
/** @param sVec 消去するブロックのリスト
* @param sFramNumErase ブロックが消えるまでに要するフレーム数
* @param sFramNumFall ブロックがひとつ分落下するのに要するフレーム数
*/
public function EraseAndFallBlocks(sVec:Vector.<Block>, sFramNumErase:uint, sFallSpeed:uint):void {
// もし他のアニメーションが走っていたら何もしない
// これは期待する動作ではない。
//if ( this.hasEventListener(Event.ENTER_FRAME) ) return;
myEraseBlocks = sVec;
myFramNumErase = sFramNumErase, myFallSpeed = sFallSpeed;
myEraseCounter = 0;
myFallCounter = 0;
// 表示順序を前面に移動する
if ( sVec.length ) {
var parent:DisplayObjectContainer = DisplayObjectContainer(sVec[0].parent)
if ( parent ) {
var numChildren:uint = parent.numChildren;
for each ( var lblock1:Block in myEraseBlocks ) {
parent.setChildIndex(lblock1, numChildren-1);
}
this.addEventListener(Event.ENTER_FRAME, EraseBlocksAnimation);
}
}
}
/// ブロック消去アニメーションの実体
private function EraseBlocksAnimation(event:Event):void {
myEraseCounter++;
for each ( var lblock1:Block in myEraseBlocks ) {
lblock1.scaleX *= 1.10;
lblock1.scaleY *= 1.10;
lblock1.alpha *= 0.8;
}
if ( myEraseCounter == myFramNumErase ) {
for each ( var lblock2:Block in myEraseBlocks ) {
lblock2.alpha = 0;
}
this.removeEventListener(Event.ENTER_FRAME, arguments.callee);
FallBlocks();
}
}
/// 消すブロックの登録を削除し、隙間を埋め、新しいブロックを上から降らす
private function FallBlocks():void {
var parent:DisplayObjectContainer = DisplayObjectContainer(myEraseBlocks[0].parent)
if ( parent ) {
// ブロックを登録から削除、そしてparentから削除する
for each ( var lblock1:Block in myEraseBlocks ) {
parent.removeChild(lblock1);
var bPoint:Point = FindBlockIndex(lblock1);
if ( bPoint ) myBlocks[bPoint.x][bPoint.y] = null;
}
myFallingBlocks = new Vector.<Array>(); //落下ブロック初期化
// ブロックを縦に走査する
for ( var i:uint = 0; i < myWidth ; i++) {
var newVector:Vector.<Block> = new Vector.<Block>(); // 新しく作るblockはここ
// ブロックがどの場所からどの場所へ移動するのかを保持する
for ( var j:int = myHeight - 1; j >= 0 ; j-- ) {
if ( !myBlocks[i][j] ) {
var finPoint:Point = GetCoodinate(i, j);
var iniPoint:Point = null;
var tarBlock:Block = null;
for ( var k:int = j - 1 ; k >= 0 ; k-- ) {
if ( myBlocks[i][k] ) {
iniPoint = GetCoodinate(i, k);
tarBlock = myBlocks[i][k];
myBlocks[i][k] = null; // この場所の登録を削除
break;
}
}
// ブロックは新規作成されるべき
if ( !iniPoint ) {
const colorList:Array = BlockColor.GetColorList();
var color:uint = colorList[Math.floor(Math.random() * colorList.length)];
var nIndexY:int = - newVector.length - 1;
iniPoint = GetCoodinate(i, nIndexY);
tarBlock = new Block(myBlockSize, myBlockOffset, color);
tarBlock.x = iniPoint.x;
tarBlock.y = iniPoint.y;
parent.addChild(tarBlock);
newVector.push(tarBlock); // newVectorにpush
}
myBlocks[i][j] = tarBlock; // 空だった(最終的な)登録場所
myFallingBlocks.push(new Array(tarBlock, iniPoint, finPoint));
}
}
}
// debug
for each ( var arr:Array in myFallingBlocks) {
}
// アニメーションを行う(EnterFrameにトリガする)
this.addEventListener(Event.ENTER_FRAME, FallBlocksAnimation );
}
}
private function FindBlockIndex(block:Block):Point {
var len:uint = myBlocks.length;
for ( var i:uint; i < len; i++ ) {
var j:int = myBlocks[i].indexOf(block);
if ( j > -1 ) return new Point(i, j);
}
return null; // ブロックは存在しない
}
/// FallBlocksのアニメーションの実体
private function FallBlocksAnimation(event:Event):void {
myFallCounter++;
var tempVector:Vector.<Array> = new Vector.<Array>();
for each ( var arr:Array in myFallingBlocks ) {
var block:Block = arr[0];
var iniPoint:Point = arr[1];
var finPoint:Point = arr[2];
block.y += myFallSpeed - myFallSpeed * Math.exp( - 0.5 * (myFallCounter-1));
if ( block.y > finPoint.y ) {
block.y = finPoint.y;
} else {
tempVector.push(arr); // 次も移動する
}
}
if ( !tempVector.length ) {
removeEventListener(Event.ENTER_FRAME, arguments.callee);
this.dispatchEvent(new BlockEvent(BlockEvent.FALLING_ENDING));
} else {
// vectorの置き換え
myFallingBlocks = tempVector;
}
}
/// 引数で指定された
/// ある引数で指定された個数以上の塊になっているブロックのリストを返す。
/** もしsX,sYが引数として渡された場合には、その周り(その場所のブロックを左上とした4つのブロックの塊)
* を含む塊だけを調べる
*/
public function GetBlockClusters(sCNum:uint, sX:uint = 0, sY:uint = 0):Vector.<Vector.<Block>> {
var retBlockClusters:Vector.<Vector.<Block>> = new Vector.<Vector.<Block>>();
if (arguments.length == 3) {
var tempVector:Vector.<Point> = Vector.<Point>([new Point(sX,sY), new Point(sX+1,sY), new Point(sX+1,sY+1), new Point(sX,sY+1)]);
for each ( var point:Point in tempVector ) {
if (
!retBlockClusters.some(
function(item:Vector.<Block>, index:int, vector:Vector.<Vector.<Block>>):Boolean {
return item.indexOf(myBlocks[point.x][point.y]) > -1 ? true : false;
}
)
) {
var blockCluster1:Vector.<Block> = new Vector.<Block>();
GetBlockCluster(point.x, point.y, blockCluster1);
if ( blockCluster1.length >= sCNum ) retBlockClusters.push(blockCluster1);
}
}
} else if (arguments.length == 1 ) {
for ( var i:uint = 0; i < myWidth ; i++ ) {
for ( var j:uint = 0; j < myWidth ; j++ ) {
if (
!retBlockClusters.some(
function(item:Vector.<Block>, index:int, vector:Vector.<Vector.<Block>>):Boolean {
return item.indexOf(myBlocks[i][j]) > -1 ? true : false;
}
)
) {
var blockCluster2:Vector.<Block> = new Vector.<Block>();
GetBlockCluster(i, j, blockCluster2);
if ( blockCluster2.length >= sCNum ) retBlockClusters.push(blockCluster2);
}
}
}
}
return retBlockClusters;
}
/// 引数で指定されたブロックを含む塊を引数で与えられたリストに詰め込む
private function GetBlockCluster(sX:uint, sY:uint, sCluster:Vector.<Block>):void {
var block:Block = myBlocks[sX][sY];
if ( sCluster.length == 0 ) {
sCluster.push(block);
} else {
var color:uint = block.Color;
if ( block.Color == sCluster[0].Color && sCluster.indexOf(block) == -1 ) {
sCluster.push(block);
} else {
return; // この場合はここで終わり
}
}
// 再帰呼び出し
if ( sX > 0 ) GetBlockCluster(sX - 1, sY, sCluster); // 左に行く
if ( sY > 0 ) GetBlockCluster(sX, sY - 1, sCluster); // 上に行く
if ( sX < myWidth - 1 ) GetBlockCluster(sX + 1, sY, sCluster); // 右に行く
if ( sY < myHeight - 1 ) GetBlockCluster(sX, sY + 1, sCluster); // 下に行く
}
/// 選択されたブロックを左上のブロックとする4つのブロックを回転させるアニメーションを行う。
/** もしアニメーションの最中に関数が呼ばれた場合には、何も行わない。
* 引数sFrameNum は、アニメーションが完了するまでのフレーム数
* 引数sSelfRotationで、ブロック自身が回転を行う角度を指定する。負の場合左、正の場合右回転。
* また、引数sDirIsRightがtrueの時、右回転を行う。falseの時左回転を行う。デフォルトはtrue。
*/
public function RotateBlocks(sX:uint, sY:uint, sFrameNum:uint, sSelfRotation:int = 0, sDirIsRight:Boolean = true) :void {
// イベントがまだいたら何もしない [TODO] sX,sYの範囲チェック?
if ( this.hasEventListener(Event.ENTER_FRAME) ) return;
myRotateTargetX = sX, myRotateTargetY = sY;
myFrameNumRotate = sFrameNum;
mySelfRotation = sSelfRotation;
myRotateCounter = 0;
if ( sDirIsRight ) this.addEventListener(Event.ENTER_FRAME, RotateBlocksAnimationRight);
else this.addEventListener(Event.ENTER_FRAME, RotateBlocksAnimationLeft);
}
/* アニメーション
*/
/// RotateBlocksの実体(右回転)
private function RotateBlocksAnimationRight(event:Event):void {
myRotateCounter++;
// 以下の4つの変数はアニメーションの最中で不変
var iniX:uint = myBlocks[myRotateTargetX][myRotateTargetY + 1].x;
var iniY:uint = myBlocks[myRotateTargetX][myRotateTargetY].y;
var finX:uint = myBlocks[myRotateTargetX + 1][myRotateTargetY].x;
var finY:uint = myBlocks[myRotateTargetX + 1][myRotateTargetY + 1].y;
// 移動
myBlocks[myRotateTargetX][myRotateTargetY].x = iniX + (finX - iniX) * myRotateCounter / myFrameNumRotate;
myBlocks[myRotateTargetX + 1][myRotateTargetY].y = iniY + (finY - iniY) * myRotateCounter / myFrameNumRotate;
myBlocks[myRotateTargetX + 1][myRotateTargetY + 1].x = finX - (finX - iniX) * myRotateCounter / myFrameNumRotate;
myBlocks[myRotateTargetX][myRotateTargetY + 1].y = finY - (finY - iniY) * myRotateCounter / myFrameNumRotate;
// [TODO]自転
if ( myRotateCounter == myFrameNumRotate ) {
myBlocks[myRotateTargetX][myRotateTargetY].x = finX;
myBlocks[myRotateTargetX + 1][myRotateTargetY].y = finY;
myBlocks[myRotateTargetX + 1][myRotateTargetY + 1].x = iniX;
myBlocks[myRotateTargetX][myRotateTargetY + 1].y = iniY;
// [TODO]自転
var tempBlockRef:Block = myBlocks[myRotateTargetX+1][myRotateTargetY];
myBlocks[myRotateTargetX + 1][myRotateTargetY] = myBlocks[myRotateTargetX][myRotateTargetY];
myBlocks[myRotateTargetX][myRotateTargetY] = myBlocks[myRotateTargetX][myRotateTargetY+1];
myBlocks[myRotateTargetX][myRotateTargetY+1] = myBlocks[myRotateTargetX+1][myRotateTargetY+1];
myBlocks[myRotateTargetX + 1][myRotateTargetY + 1] = tempBlockRef;
removeEventListener(Event.ENTER_FRAME, arguments.callee);
// 回転が終わったイベントを投げる
var dEvent:BlockEvent = new BlockEvent(BlockEvent.ROTATION_ENDING, true);
this.dispatchEvent(dEvent);
}
}
/// RotateBLocksの実体(左回転)
private function RotateBlocksAnimationLeft(event:Event):void {
myRotateCounter++;
// 以下の4つの変数はアニメーションの最中で不変
var iniX:uint = myBlocks[myRotateTargetX][myRotateTargetY].x;
var iniY:uint = myBlocks[myRotateTargetX+1][myRotateTargetY].y;
var finX:uint = myBlocks[myRotateTargetX + 1][myRotateTargetY+1].x;
var finY:uint = myBlocks[myRotateTargetX][myRotateTargetY + 1].y;
// 移動
myBlocks[myRotateTargetX][myRotateTargetY+1].x = iniX + (finX - iniX) * myRotateCounter / myFrameNumRotate;
myBlocks[myRotateTargetX][myRotateTargetY].y = iniY + (finY - iniY) * myRotateCounter / myFrameNumRotate;
myBlocks[myRotateTargetX+1][myRotateTargetY].x = finX - (finX - iniX) * myRotateCounter / myFrameNumRotate;
myBlocks[myRotateTargetX+1][myRotateTargetY+1].y = finY - (finY - iniY) * myRotateCounter / myFrameNumRotate;
// [TODO]自転
if ( myRotateCounter == myFrameNumRotate ) {
myBlocks[myRotateTargetX][myRotateTargetY+1].x = finX;
myBlocks[myRotateTargetX][myRotateTargetY].y = finY;
myBlocks[myRotateTargetX+1][myRotateTargetY].x = iniX;
myBlocks[myRotateTargetX+1][myRotateTargetY+1].y = iniY;
// [TODO]自転
var tempBlockRef:Block = myBlocks[myRotateTargetX+1][myRotateTargetY];
myBlocks[myRotateTargetX + 1][myRotateTargetY] = myBlocks[myRotateTargetX+1][myRotateTargetY+1];
myBlocks[myRotateTargetX+1][myRotateTargetY+1] = myBlocks[myRotateTargetX][myRotateTargetY+1];
myBlocks[myRotateTargetX][myRotateTargetY+1] = myBlocks[myRotateTargetX][myRotateTargetY];
myBlocks[myRotateTargetX][myRotateTargetY] = tempBlockRef;
removeEventListener(Event.ENTER_FRAME, arguments.callee);
// 回転が終わったイベントを投げる
var dEvent:BlockEvent = new BlockEvent(BlockEvent.ROTATION_ENDING, false);
this.dispatchEvent(dEvent);
}
}
}
import flash.display.*;
import flash.events.FocusEvent;
import flash.geom.Point;
import flash.text.*;
class GamePhase extends Sprite
{
/// 定数
private const myOffset:uint = 10;
private const myScoreFontSize:uint = 12;
private const myScoreFontColor:uint = 0xffffff;
private const myTextScore:String = "SCORE";
private const myTextScoreX:uint = 10;
private const myTextScoreY:uint = 440;
private const myScoreRensaRate:uint = 2;
private const myScoreBlockRate:uint = 2;
/// ゲームステージ
private var myGStage:GameStage = new GameStage();
private var myTextScoreField:TextField = new TextField();
private var myScoreField:TextField = new TextField();
private var myScore:int = 0;
public function GamePhase()
{
}
/// ゲームスタート
public function Start() : void
{
var tFormat:TextFormat = new TextFormat();
tFormat.size = myScoreFontSize;
tFormat.color = myScoreFontColor;
myScoreField.defaultTextFormat = tFormat;
myTextScoreField.defaultTextFormat = tFormat;
myTextScoreField.text = myTextScore;
myTextScoreField.x = myTextScoreX;
myTextScoreField.y = myTextScoreY;
myScoreField.x = myTextScoreField.x + myTextScoreField.width + int(tFormat.size);
myScoreField.y = myTextScoreField.y;
myScoreField.text = myScore.toString();
addChild(myTextScoreField);
addChild(myScoreField);
myGStage.x = myOffset;
myGStage.y = myOffset;
myGStage.addEventListener(ScoreEvent.GET_RENSA, onEvaluateRensaScore);
addChild(myGStage);
// スタート
stage.focus = stage;
myGStage.Start();
}
/// 連鎖が起こった時の得点を計算し、加点する
private function onEvaluateRensaScore(event:ScoreEvent):void {
var rensaInfo:Vector.<Point> = event.RensaInfo;
for each ( var point:Point in rensaInfo ) {
myScore += 20 * Math.floor( Math.pow(2, point.x - 2 + point.y));
}
// スコアを表示
myScoreField.text = myScore.toString();
trace(myScore);
}
}
import adobe.utils.CustomActions;
import flash.display.*;
import flash.events.*;
import flash.ui.Keyboard;
import flash.geom.Point;
class GameStage extends Sprite
{
/// 定数
private static const myBACKGROUND_COLOR:uint = 0xffffff;
private static const myBLOCK_SIZE:uint = 25;
private static const myBLOCK_NUMBER_W:uint = 7;
private static const myBLOCK_NUMBER_H:uint = 8;
private static const myBLOCK_OFFSET:uint = 2;
private static const myBLOCK_ERASE_THRESHOLD:uint = 4;
/// ブロックを管理するクラス
private var myBlockTable:BlockTable;
/// ブロックの選択をあらわすインデックス(pair)
private var mySelectedIndex:Vector.<uint> = new Vector.<uint>(2, true);
/// 回転の往復を表すフラグ
private var myIsRotationReturn:Boolean = false;
///
private var myRensaCount:uint = 0; // 現在の連鎖数を表す
private var myRensaInfo:Vector.<Point>; // Point(一塊あたりの消されたブロック数,何連鎖目か)
/// ブロックを選択する選択ボックス
public function GameStage()
{
// block table 初期化
myBlockTable = new BlockTable(myBLOCK_NUMBER_W, myBLOCK_NUMBER_H, myBLOCK_SIZE, myBLOCK_OFFSET);
// 背景描画
graphics.beginFill(myBACKGROUND_COLOR, 0.7);
graphics.drawRect(0, 0, myBLOCK_NUMBER_W*myBLOCK_SIZE*2, myBLOCK_NUMBER_H*myBLOCK_SIZE*2);
graphics.endFill();
}
/// ゲーム開始
public function Start() : void
{
// ブロックの生成
for ( var i:uint = 0 ; i < myBLOCK_NUMBER_W ; i++ ) {
for ( var j:uint = 0 ; j < myBLOCK_NUMBER_H ; j++ ) {
var block:Block = myBlockTable.CreateBlock(i, j);
if ( block != null ) this.addChild(block);
}
}
// キーボードイベントの追加
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
// ブロックの回転が終了したイベントの追加
myBlockTable.addEventListener(BlockEvent.ROTATION_ENDING, onRotationEnd);
// ブロックの降下が(一回)終了したイベントの追加
myBlockTable.addEventListener(BlockEvent.FALLING_ENDING, onFallingEnd);
// 初回のブロッククラスタチェック
var vec:Vector.<Vector.<Block>> = myBlockTable.GetBlockClusters(myBLOCK_ERASE_THRESHOLD);
const colorList:Array = BlockColor.GetColorList();
while ( vec.length > 0 ) {
for each ( var vecl1:Vector.<Block> in vec ) {
for each (var blockl1:Block in vecl1 ) {
var color:uint = colorList[Math.floor(Math.random() * colorList.length)];
blockl1.ChangeColor(color);
}
}
vec = myBlockTable.GetBlockClusters(myBLOCK_ERASE_THRESHOLD);
}
// 選択状態の表示
SelectBlocks();
}
private function SelectBlocks() : void {
var lX:uint = mySelectedIndex[0];
var lY:uint = mySelectedIndex[1];
// [TODO] lX, lYの範囲チェックは?
myBlockTable.SelectBlock(lX, lY);
myBlockTable.SelectBlock(lX+1, lY);
myBlockTable.SelectBlock(lX, lY+1);
myBlockTable.SelectBlock(lX+1, lY+1);
}
private function UnselectBlocks() : void {
var lX:uint = mySelectedIndex[0];
var lY:uint = mySelectedIndex[1];
// [TODO] lX, lYの範囲チェックは?
myBlockTable.UnSelectBlock(lX, lY);
myBlockTable.UnSelectBlock(lX+1, lY);
myBlockTable.UnSelectBlock(lX, lY+1);
myBlockTable.UnSelectBlock(lX+1, lY+1);
}
/// キーボードイベント
private function onKeyDown(event:KeyboardEvent):void {
switch (event.keyCode) {
case Keyboard.RIGHT:
UnselectBlocks();
if ( mySelectedIndex[0] < myBLOCK_NUMBER_W-2) ++mySelectedIndex[0];
SelectBlocks();
break;
case Keyboard.DOWN:
UnselectBlocks();
if ( mySelectedIndex[1] < myBLOCK_NUMBER_H-2) ++mySelectedIndex[1];
SelectBlocks();
break;
case Keyboard.LEFT:
UnselectBlocks();
if ( mySelectedIndex[0] > 0 ) --mySelectedIndex[0];
SelectBlocks();
break;
case Keyboard.UP:
UnselectBlocks();
if ( mySelectedIndex[1] > 0 ) --mySelectedIndex[1];
SelectBlocks();
break;
case 90: // Z
myBlockTable.RotateBlocks(mySelectedIndex[0], mySelectedIndex[1], 5, 0, false);
break;
case 67:
myBlockTable.RotateBlocks(mySelectedIndex[0], mySelectedIndex[1], 5, 0, true);
break;
}
}
/// 回転アニメーションが終了した時にトリガされるイベント
private function onRotationEnd(event:BlockEvent):void {
// 回転したブロックの周りでのブロックの塊具合を調べる
var blockCluster:Vector.<Vector.<Block>> =
myBlockTable.GetBlockClusters(myBLOCK_ERASE_THRESHOLD, mySelectedIndex[0], mySelectedIndex[1]);
if (blockCluster.length > 0) {
myRensaCount = 1;
myRensaInfo = new Vector.<Point>();
var vecl1:Vector.<Block> = new Vector.<Block>();
for each ( var lvec1:Vector.<Block> in blockCluster ) {
myRensaInfo.push( new Point(lvec1.length, myRensaCount));
for each ( var lblock1:Block in lvec1 ) {
vecl1.push(lblock1);
}
}
UnselectBlocks();
myBlockTable.EraseAndFallBlocks(vecl1, 10, 20);
} else {
if ( !myIsRotationReturn ) {
myIsRotationReturn = true;
myBlockTable.RotateBlocks(mySelectedIndex[0], mySelectedIndex[1], 5, 0, !event.IsRotationDirRight);
} else {
myIsRotationReturn = false;
}
}
}
/// ブロックの降下が終了した時に呼ばれるイベント
private function onFallingEnd(event:BlockEvent):void {
// もう一度全体に塊が無いか検査する
var blockCluster:Vector.<Vector.<Block>> = myBlockTable.GetBlockClusters(myBLOCK_ERASE_THRESHOLD);
if ( blockCluster.length > 0 ) {
myRensaCount++;
var vecl1:Vector.<Block> = new Vector.<Block>();
for each ( var lvec1:Vector.<Block> in blockCluster ) {
myRensaInfo.push(new Point(lvec1.length, myRensaCount));
for each ( var lblock1:Block in lvec1 ) {
vecl1.push(lblock1);
}
}
myBlockTable.EraseAndFallBlocks(vecl1, 10, 20);
} else {
SelectBlocks();
var dEvent:ScoreEvent = new ScoreEvent(ScoreEvent.GET_RENSA, myRensaInfo);
this.dispatchEvent(dEvent); // スコア(の元)を送る
}
}
}
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.*;
import flash.text.TextField;
import flash.text.*;
class InitialPhase extends Sprite
{
// イベント名
public static const START:String = "START";
// メンバ変数
private var myTitleField:TextField = new TextField(); // タイトル
private var myTitleString:String = "Puzzle"; // タイトル名
private var myButtonStart:SimpleButton; // スタートボタン
private var myButtonText:String = "Start";
/// コンストラクタ
public function InitialPhase()
{
}
/// スタート画面の表示
public function Start() : void
{
// タイトルのテキスト
myTitleField.autoSize = TextFieldAutoSize.CENTER;
var textFormat:TextFormat = new TextFormat(null, 80, 0xcc9999, true);
myTitleField.defaultTextFormat = textFormat;
myTitleField.x = stage.stageWidth / 2;
myTitleField.y = 40;
myTitleField.text = myTitleString;
addChild(myTitleField);
// スタートボタン
myButtonStart = new SimpleButton();
makeButton(myButtonStart, 50, 0xffffff, 0xaaaaaa, 0xff55ff, myButtonText);
myButtonStart.x = stage.stageWidth / 2;
myButtonStart.y = stage.stageHeight - 80;
myButtonStart.addEventListener(MouseEvent.CLICK, onButtonStartClick);
addChild(myButtonStart);
}
private function makeButton(button:SimpleButton, size:uint, upColor:uint, overColor:uint, downColor:uint, text:String) :void
{
button.upState = makeState(size, upColor, text);
button.overState = makeState(size, overColor, text);
button.downState = makeState(size, downColor, text);
button.hitTestState = button.overState;
}
private function makeState(size:uint, color:uint, text:String) : Sprite
{
// テキスト部分
var tField:TextField = new TextField();
var sprite:Sprite = new Sprite();
var offset:uint = 10;
tField.autoSize = TextFieldAutoSize.LEFT;
tField.defaultTextFormat = new TextFormat(null, size, 0xcc9999, true);
tField.text = text;
sprite.addChild(tField);
tField.x = - tField.width / 2;
tField.y = - tField.height / 2;
// ボタン部分
sprite.graphics.beginFill(color);
sprite.graphics.drawRoundRect( - tField.width / 2 - offset,
- tField.height / 2,
tField.width + offset * 2,
tField.height,
tField.height / 4);
sprite.graphics.endFill();
return sprite;
}
private function onButtonStartClick(event:MouseEvent) : void
{
dispatchEvent( new Event(InitialPhase.START) ); // イベントの送出
}
}
import flash.events.Event;
import flash.geom.Point;
import flash.display.*;
class ScoreEvent extends Event
{
public static const GET_RENSA:String = "ScoreEvent.GetRensa";
private var myGettingRensaInfo:Vector.<Point>; //Point(消えたブロックの1塊あたりの数,何連鎖目か)
public function get RensaInfo():Vector.<Point>{ return myGettingRensaInfo; }
public function ScoreEvent(type:String, gettingRensaInfo:Vector.<Point>, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
myGettingRensaInfo = gettingRensaInfo;
}
public override function clone():Event
{
return new ScoreEvent(type, myGettingRensaInfo, bubbles, cancelable);
}
public override function toString():String
{
return formatToString("ScoreEvent", "type", "bubbles", "cancelable", "eventPhase");
}
}