|
Page 5 of 9 In Game Functions /** If the player destroys more than 6 tiles, they get a special bonus * */ private function calculateInGameBonus(tiles:int):Number { if(tiles > 6) { return tiles + Math.round(tiles * (2 / 3)); } return tiles; }
/** Make sure that all tiles are in their correct positions * */ private function showTiles():void { for(var col:int = 0; col < tileList.length; col ++) { for(var row:int = 0; row < tileList[col].length; row ++) { if(tileList[col][row] != null) { var tile:Tile = tileList[col][row]; var targetX:Number = (tile.width * col) + 15; var targetY:Number = (tile.height * row) + 150; if(tile.x != targetX) { tile.x = targetX; } if(tile.y != targetY) { tile.tween = new Tween(tile, "y", None.easeNone, tile.y, targetY, 2, false); tile.tween.addEventListener (TweenEvent.MOTION_FINISH, motionEnd); //moveTileY.addEventListener(TweenEvent.MOTION_STOP, motionChange); //moveTileY.addEventListener(TweenEvent.MOTION_CHANGE, motionChange); } else { tile.y = targetY; } } } } }
private function tileCount():int { var total:int = 0; for(var col:int = 0; col < tileList.length; col ++) { for(var row:int = 0; row < tileList[col].length; row ++) { if(tileList[col][row].currentFrame < tileList[col][row].totalFrames) { total ++; } } } return total; }
/** Make sure when the tile animations stop that they're in the right place * */ private function motionEnd (e:Event):void { if(! (e.target.obj is Tile)) throw new Error("Not a tile!"); var tile:Tile = e.target.obj as Tile; var targetX:Number = (tile.width * tile.column) + 15; var targetY:Number = (tile.height * tile.row) + 150; if(tile.x != targetX) { trace(tile + "[" + tile.column + "][" + tile.row + "] is not at the correct X-Coordinate"); tile.x = targetX; } if(tile.y != targetY) { trace(tile + "[" + tile.column + "][" + tile.row + "] is not at the correct Y-Coordinate"); tile.y = targetY; } delete this; }
If you haven't seen these two operators before: is and as, they are new to AS3. Since "instanceof" has been deprecated, "is" has taken over. The "as" operator works for type casting. Back to the code private function motionChange (e:Event):void { //trace("motion stopped: " + e); }
private function tileClickHandler(e:MouseEvent):void { var tile:Tile = Tile(e.target); //trace("(" + tile.column + " ," + tile.row + ")"); if( ! tile.isHighLighted() ) { dimAll(); } else { var justScored = calculateInGameBonus( getNumberHighLighted() ); score += justScored; currentLevelScore += justScored; destroyHighLighted(); showTiles(); if( ! anyMovesLeft() ) { gameState = NEXTLEVEL; } } findSurrounding( tile , tile.currentFrame ); if(getNumberHighLighted() < 2) { dimAll(); } }
/** Make sure all of the tiles are not highlighted * **/ private function dimAll():void { for(var col:int = 0; col < tileList.length; col ++) { for(var row:int = 0; row < tileList[col].length; row ++) { if(tileList[col][row] != null) { tileList[col][row].turnOff(); } } } }
/** Recursively find all the surrounding tiles that are of the same color * This is where that small optimization came in where it doesn't check * the same tile twice when searching. Not so much an optimization as it * is a smart function. **/ private function findSurrounding(tile:Tile, tileFrameNumber:int):void { if(tile.currentFrame == tileFrameNumber) { var row = tile.row; var col = tile.column; tile.markAsChecked(); tile.turnOn(); //check bottom if(row < rowMax - 1) { if(tileList[col][row + 1] != null) { if( ! tileList[col][row + 1].isHighLighted() ) { findSurrounding(tileList[col][row + 1], tileFrameNumber); } } } //else trace("bottom reached"); //check right if(col < colMax - 1) { if(tileList[col + 1][row] != null) { if( ! tileList[col + 1][row].isHighLighted() ) { findSurrounding(tileList[col + 1][row], tileFrameNumber); } } } //else trace("right reached"); //check top if(row > 0) { if(tileList[col][row - 1] != null) { if( ! tileList[col][row - 1].isHighLighted() ) { findSurrounding(tileList[col][row - 1], tileFrameNumber); } } } //else trace("top reached"); //check left if(col > 0) { if(tileList[col - 1][row] != null) { if( ! tileList[col - 1][row].isHighLighted() ) { findSurrounding(tileList[col - 1][row], tileFrameNumber); } } } //else trace("left reached"); } }
/** Retrieves all the tiles that are currently highlighted * **/ private function getNumberHighLighted():int { var total:int = 0; for(var col:int = 0; col < tileList.length; col ++) { for(var row:int = 0; row < tileList[col].length; row ++) { if(tileList[col][row] != null) { if(tileList[col][row].isHighLighted()) { total ++; } } } } return total; }
private function destroyHighLighted():int { var total:int = 0; for(var col:int = 0; col < tileList.length; col ++) { for(var row:int = 0; row < tileList[col].length; row ++) { if(tileList[col][row] != null) { if(tileList[col][row].isHighLighted()) { tileList[col][row].removeEventListener(MouseEvent.CLICK, tileClickHandler); tileList[col][row].gotoAndStop("blank"); tileList[col][row].destroy(); // move blocks down for(var i:int = row; i > 0; i --) { var temp:Tile = tileList[col][i]; temp.row --; tileList[col][i] = tileList[col][i - 1]; tileList[col][i].row ++; tileList[col][i - 1] = temp; } } } } } compressColumns(); dimAll(); return total; }
private function anyMovesLeft():Boolean { dimAll(); for(var col:int = 0; col < tileList.length; col ++) { for(var row:int = 0; row < tileList[col].length; row ++) { var tile:Tile = tileList[col][row]; //trace("checking: " + col +":"+ row); if(tile.currentFrame < tile.totalFrames) { findSurrounding( tile , tile.currentFrame ); //trace("highlighted:" + getNumberHighLighted()); if( getNumberHighLighted() > 1 ) { dimAll(); return true; } } dimAll(); } } return false; }
private function destroyAll():void { for(var col:int = 0; col < tileList.length; col ++) { for(var row:int = 0; row < tileList[col].length; row ++) { tileList[col][row].destroy(); } } }
Phew! That was a good chunk of code. These functions took a little bit of thinking and testing before getting right. Sit down, take a piece of paper and draw out what needs to be done before sitting down to program. This is always the best way to go about things. Even though I didn't have a huge stack of use cases and sequence diagrams, I still managed to do an O.K. job only because I programmed this by myself. It's best to have a PLAN!
|