效果演示
项目使用
部分源码如下
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;
}
}
}