效果演示

项目使用

部分源码如下

package piratepig;


import motion.easing.Quad;
import motion.Actuate;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.events.Event;
import openfl.events.MouseEvent;
import openfl.filters.BlurFilter;
import openfl.filters.DropShadowFilter;
import openfl.geom.Point;
import openfl.media.Sound;
import openfl.text.TextField;
import openfl.text.TextFormat;
import openfl.text.TextFormatAlign;
import openfl.Assets;
import openfl.Lib;

#if (!flash || enable_gamepad_support)
import openfl.events.GameInputEvent;
import openfl.ui.GameInput;
import openfl.ui.GameInputDevice;
import openfl.ui.GameInputControl;
#end


class PiratePigGame extends Sprite {
	
	
	private static var NUM_COLUMNS = 8;
	private static var NUM_ROWS = 8;
	
	private static var tileImages = [ "images/game_bear.png", "images/game_bunny_02.png", "images/game_carrot.png", "images/game_lemon.png", "images/game_panda.png", "images/game_piratePig.png" ];
	
	private var Background:Sprite;
	private var Cursor:Bitmap;
	private var CursorHighlight:Bitmap;
	private var IntroSound:Sound;
	private var Logo:Bitmap;
	private var Score:TextField;
	private var Sound3:Sound;
	private var Sound4:Sound;
	private var Sound5:Sound;
	private var TileContainer:Sprite;
	
	public var currentScale:Float;
	public var currentScore:Int;
	
	private var cacheMouse:Point;
	private var cursorPosition:Point;
	private var gamepads:Array<GamepadWrapper>;
	private var needToCheckMatches:Bool;
	private var selectedTile:Tile;
	private var tiles:Array<Array<Tile>>;
	private var usedTiles:Array<Tile>;
	
	#if (!flash || enable_gamepad_support)
	private var gameInput:GameInput;
	#end
	
	
	public function new () {
		
		super ();
		
		initialize ();
		construct ();
		
		newGame ();
		
	}
	
	
	private function addTile (row:Int, column:Int, animate:Bool = true):Void {
		
		var tile = null;
		var type = Math.round (Math.random () * (tileImages.length - 1));
		
		for (usedTile in usedTiles) {
			
			if (usedTile.removed && usedTile.parent == null && usedTile.type == type) {
				
				tile = usedTile;
				
			}
			
		}
		
		if (tile == null) {
			
			tile = new Tile (tileImages[type]);
			
		}
		
		tile.initialize ();
		
		tile.type = type;
		tile.row = row;
		tile.column = column;
		tiles[row][column] = tile;
		
		var position = getPosition (row, column);
		
		if (animate) {
			
			var firstPosition = getPosition (-1, column);
			
			tile.alpha = 0;
			tile.x = firstPosition.x;
			tile.y = firstPosition.y;
			
			tile.moveTo (0.15 * (row + 1), position.x, position.y);
			Actuate.tween (tile, 0.3, { alpha: 1 } ).delay (0.15 * (row - 2)).ease (Quad.easeOut);
			
		} else {
			
			tile.x = position.x;
			tile.y = position.y;
			
		}
		
		TileContainer.addChild (tile);
		needToCheckMatches = true;
		
	}
	
	
	private function construct ():Void {
		
		Logo.smoothing = true;
		addChild (Logo);
		
		var font = Assets.getFont ("fonts/FreebooterUpdated.ttf");
		var defaultFormat = new TextFormat (font.fontName, 60, 0x000000);
		defaultFormat.align = TextFormatAlign.RIGHT;
		
		var contentWidth = 75 * NUM_COLUMNS;
		
		Score.x = contentWidth - 200;
		Score.width = 200;
		Score.y = 12;
		Score.selectable = false;
		Score.defaultTextFormat = defaultFormat;
		Score.embedFonts = true;
		addChild (Score);
		
		Background.y = 85;
		Background.graphics.beginFill (0xFFFFFF, 0.4);
		Background.graphics.drawRect (0, 0, contentWidth, 75 * NUM_ROWS);
		Background.filters = [ new BlurFilter (10, 10) ];
		addChild (Background);
		
		TileContainer.x = 14;
		TileContainer.y = Background.y + 14;
		TileContainer.addEventListener (MouseEvent.MOUSE_DOWN, TileContainer_onMouseDown);
		Lib.current.stage.addEventListener (MouseEvent.MOUSE_UP, stage_onMouseUp);
		addChild (TileContainer);
		
		IntroSound = Assets.getSound ("soundTheme");
		Sound3 = Assets.getSound ("sound3");
		Sound4 = Assets.getSound ("sound4");
		Sound5 = Assets.getSound ("sound5");
		
		Cursor.visible = false;
		Cursor.alpha = 0.7;
		CursorHighlight.visible = false;
		CursorHighlight.alpha = 0.7;
		
		TileContainer.addChild (Cursor);
		TileContainer.addChild (CursorHighlight);
		
		#if (!flash || enable_gamepad_support)
		gameInput = new GameInput ();
		gameInput.addEventListener (GameInputEvent.DEVICE_ADDED, gameInput_onDeviceAdded);
		gameInput.addEventListener (GameInputEvent.DEVICE_REMOVED, gameInput_onDeviceRemoved);
		#end
		
	}
	
	
	private function dropTiles ():Void {
		
		for (column in 0...NUM_COLUMNS) {
			
			var spaces = 0;
			
			for (row in 0...NUM_ROWS) {
				
				var index = (NUM_ROWS - 1) - row;
				var tile = tiles[index][column];
				
				if (tile == null) {
					
					spaces++;
					
				} else {
					
					if (spaces > 0) {
						
						var position = getPosition (index + spaces, column);
						tile.moveTo (0.15 * spaces, position.x,position.y);
						
						tile.row = index + spaces;
						tiles[index + spaces][column] = tile;
						tiles[index][column] = null;
						
						needToCheckMatches = true;
						
					}
					
				}
				
			}
			
			for (i in 0...spaces) {
				
				var row = (spaces - 1) - i;
				addTile (row, column);
				
			}
			
		}
		
	}
	
	
	private function findMatches (byRow:Bool, accumulateScore:Bool = true):Array <Tile> {
		
		var matchedTiles = new Array <Tile> ();
		
		var max:Int;
		var secondMax:Int;
		
		if (byRow) {
			
			max = NUM_ROWS;
			secondMax = NUM_COLUMNS;
			
		} else {
			
			max = NUM_COLUMNS;
			secondMax = NUM_ROWS;
			
		}
		
		for (index in 0...max) {
			
			var matches = 0;
			var foundTiles = new Array <Tile> ();
			var previousType = -1;
			
			for (secondIndex in 0...secondMax) {
				
				var tile:Tile;
				
				if (byRow) {
					
					tile = tiles[index][secondIndex];
					
				} else {
					
					tile = tiles[secondIndex][index];
					
				}
				
				if (tile != null && !tile.moving) {
					
					if (previousType == -1) {
						
						previousType = tile.type;
						foundTiles.push (tile);
						continue;
						
					} else if (tile.type == previousType) {
						
						foundTiles.push (tile);
						matches++;
						
					}
					
				}
				
				if (tile == null || tile.moving || tile.type != previousType || secondIndex == secondMax - 1) {
					
					if (matches >= 2 && previousType != -1) {
						
						if (accumulateScore) {
							
							if (matches > 3) {
								
								Sound5.play ();
								
							} else if (matches > 2) {
								
								Sound4.play ();
								
							} else {
								
								Sound3.play ();
								
							}
							
							currentScore += Std.int (Math.pow (matches, 2) * 50);
							
						}
						
						matchedTiles = matchedTiles.concat (foundTiles);
						
					}
					
					matches = 0;
					foundTiles = new Array <Tile> ();
					
					if (tile == null || tile.moving) {
						
						needToCheckMatches = true;
						previousType = -1;
						
					} else {
						
						previousType = tile.type;
						foundTiles.push (tile);
						
					}
					
				}
				
			}
			
		}
		
		return matchedTiles;
		
	}
	
	
	private function getPosition (row:Int, column:Int):Point {
		
		return new Point (column * (57 + 16), row * (57 + 16));
		
	}
	
	
	private function initialize ():Void {
		
		currentScale = 1;
		currentScore = 0;
		
		tiles = new Array <Array <Tile>> ();
		usedTiles = new Array <Tile> ();
		gamepads = new Array ();
		
		for (row in 0...NUM_ROWS) {
			
			tiles[row] = new Array <Tile> ();
			
			for (column in 0...NUM_COLUMNS) {
				
				tiles[row][column] = null;
				
			}
			
		}
		
		Background = new Sprite ();
		Logo = new Bitmap (Assets.getBitmapData ("images/logo.png"));
		Score = new TextField ();
		TileContainer = new Sprite ();
		Cursor = new Bitmap (Assets.getBitmapData ("images/cursor.png"));
		CursorHighlight = new Bitmap (Assets.getBitmapData ("images/cursor_highlight.png"));
		
	}
	
	
	private function moveCursor (x:Int, y:Int, aPressed:Bool):Void {
		
		if (cursorPosition == null) cursorPosition = new Point();
		
		var oldTile = tiles[Std.int (cursorPosition.y)][Std.int (cursorPosition.x)];
		
		cursorPosition.x += x;
		cursorPosition.y += y;
		
		if (cursorPosition.y > tiles.length - 1) cursorPosition.y = tiles.length - 1;
		if (cursorPosition.x > tiles[0].length - 1) cursorPosition.x = tiles[0].length - 1;
		if (cursorPosition.y < 0) cursorPosition.y = 0;
		if (cursorPosition.x < 0) cursorPosition.x = 0;
		
		var tile = tiles[Std.int (cursorPosition.y)][Std.int (cursorPosition.x)];
		
		if (tile != null) {
			
			var targetTilePosition = getPosition (Std.int (cursorPosition.y), Std.int (cursorPosition.x));
			
			Cursor.x = targetTilePosition.x;
			Cursor.y = targetTilePosition.y;
			CursorHighlight.x = Cursor.x;
			CursorHighlight.y = Cursor.y;
			
			if (aPressed && oldTile != tile && oldTile != null) {
				
				swapTile (oldTile, Std.int (cursorPosition.y), Std.int (cursorPosition.x));
				
			}
			
		}
		
	}
	
	
	public function newGame ():Void {
		
		currentScore = 0;
		Score.text = "0";
		
		for (row in 0...NUM_ROWS) {
			
			for (column in 0...NUM_COLUMNS) {
				
				removeTile (row, column, false);
				
			}
			
		}
		
		for (row in 0...NUM_ROWS) {
			
			for (column in 0...NUM_COLUMNS) {
				
				addTile (row, column, false);
				
			}
			
		}
		
		IntroSound.play ();
		
		removeEventListener (Event.ENTER_FRAME, this_onEnterFrame);
		addEventListener (Event.ENTER_FRAME, this_onEnterFrame);
		
	}
	
	
	public function removeTile (row:Int, column:Int, animate:Bool = true):Void {
		
		var tile = tiles[row][column];
		
		if (tile != null) {
			
			tile.remove (animate);
			usedTiles.push (tile);
			
		}
		
		tiles[row][column] = null;
		
	}
	
	
	public function resize (newWidth:Int, newHeight:Int):Void {
		
		var maxWidth = newWidth * 0.90;
		var maxHeight = newHeight * 0.86;
		
		currentScale = 1;
		scaleX = 1;
		scaleY = 1;
		
		var currentWidth = width;
		var currentHeight = height;
		
    var maxScaleX = maxWidth / currentWidth;
    var maxScaleY = maxHeight / currentHeight;
    
    if (maxScaleX < maxScaleY) {
      
      currentScale = maxScaleX;
      
    } else {
      
      currentScale = maxScaleY;
      
    }
			
    scaleX = currentScale;
    scaleY = currentScale;
		
		x = newWidth / 2 - (currentWidth * currentScale) / 2;
		
	}
	
	
	private function swapTile (tile:Tile, targetRow:Int, targetColumn:Int):Void {
		
		if (targetColumn >= 0 && targetColumn < NUM_COLUMNS && targetRow >= 0 && targetRow < NUM_ROWS) {
			
			var targetTile = tiles[targetRow][targetColumn];
			
			if (targetTile != null && !targetTile.moving) {
				
				tiles[targetRow][targetColumn] = tile;
				tiles[tile.row][tile.column] = targetTile;
				
				if (findMatches (true, false).length > 0 || findMatches (false, false).length > 0) {
					
					targetTile.row = tile.row;
					targetTile.column = tile.column;
					tile.row = targetRow;
					tile.column = targetColumn;
					var targetTilePosition = getPosition (targetTile.row, targetTile.column);
					var tilePosition = getPosition (tile.row, tile.column);
					
					targetTile.moveTo (0.3, targetTilePosition.x, targetTilePosition.y);
					tile.moveTo (0.3, tilePosition.x, tilePosition.y);
					
					needToCheckMatches = true;
					
				} else {
					
					tiles[targetRow][targetColumn] = targetTile;
					tiles[tile.row][tile.column] = tile;
					
				}
				
			}
			
		}
		
	}
	
	
	private function updateGamepadInput ():Void {
		
		#if (!flash || enable_gamepad_support)
		
		for (gamepad in gamepads) {
			
			gamepad.update ();
			
		}
		
		if (gamepads.length > 0) {
			
			var aPressed = gamepads[0].a.pressed;
			
			if (gamepads[0].up.justPressed) {
				
				moveCursor (0, -1, aPressed);
				
			} else if (gamepads[0].down.justPressed) {
				
				moveCursor (0, 1, aPressed);
				
			} else if (gamepads[0].left.justPressed) {
				
				moveCursor (-1, 0, aPressed);
				
			} else if (gamepads[0].right.justPressed) {
				
				moveCursor (1, 0, aPressed);
				
			}
			
			Cursor.visible = !aPressed;
			CursorHighlight.visible = aPressed;
			
		} else {
			
			Cursor.visible = false;
			CursorHighlight.visible = false;
			
		}
		
		#end
		
	}
	
	
	
	
	// Event Handlers
	
	
	
	
	
	#if (!flash || enable_gamepad_support)
	
	private function gameInput_onDeviceAdded (event:GameInputEvent):Void {
		
		var device = event.device;
		device.enabled = true;
		
		gamepads.push (new GamepadWrapper (device));
		
	}
	
	
	private function gameInput_onDeviceRemoved (event:GameInputEvent):Void {
		
		var device = event.device;
		device.enabled = false;
		
		for (gamepad in gamepads) {
			
			if (gamepad.device == device) {
				
				gamepad.destroy ();
				gamepads.remove (gamepad);
				return;
				
			}
			
		}
		
	}
	
	#end
	
	
	private function stage_onMouseUp (event:MouseEvent):Void {
		
		if (cacheMouse != null && selectedTile != null && !selectedTile.moving) {
			
			var differenceX = event.stageX - cacheMouse.x;
			var differenceY = event.stageY - cacheMouse.y;
			
			if (Math.abs (differenceX) > 10 || Math.abs (differenceY) > 10) {
				
				var swapToRow = selectedTile.row;
				var swapToColumn = selectedTile.column;
				
				if (Math.abs (differenceX) > Math.abs (differenceY)) {
					
					if (differenceX < 0) {
						
						swapToColumn --;
						
					} else {
						
						swapToColumn ++;
						
					}
					
				} else {
					
					if (differenceY < 0) {
						
						swapToRow --;
						
					} else {
						
						swapToRow ++;
						
					}
					
				}
				
				swapTile (selectedTile, swapToRow, swapToColumn);
				
			}
			
		}
		
		selectedTile = null;
		cacheMouse = null;
		
	}
	
	
	private function this_onEnterFrame (event:Event):Void {
		
		updateGamepadInput ();
		
		if (needToCheckMatches) {
			
			var matchedTiles = new Array <Tile> ();
			
			matchedTiles = matchedTiles.concat (findMatches (true));
			matchedTiles = matchedTiles.concat (findMatches (false));
			
			for (tile in matchedTiles) {
				
				removeTile (tile.row, tile.column);
				
			}
			
			if (matchedTiles.length > 0) {
				
				Score.text = Std.string (currentScore);
				dropTiles ();
				
			}
			
		}
		
	}
	
	
	private function TileContainer_onMouseDown (event:MouseEvent):Void {
		
		if (Std.is (event.target, Tile)) {
			
			selectedTile = cast event.target;
			cacheMouse = new Point (event.stageX, event.stageY);
			
		} else {
			
			cacheMouse = null;
			selectedTile = null;
			
		}
		
	}
	
	
}