最近在研究Flash游戏的算法,发现同一种游戏能有很多种算法,而我比较喜欢面向对象和事件通知方式的算法,清清爽爽的程序结构。。。
[运行效果]
[FLASH=550,400,True]upload/SlidingPuzzle.swf[/FLASH]
[主程序类]
package {
import com.klstudio.puzzles.slider.PuzzleBoard;
import flash.display.Sprite;
/**
* SlidingPuzzle
* @author Kinglong([email protected])
* @since:2010-9-13
*/
public class SlidingPuzzle extends Sprite {
[Embed(source="image.jpg")]
private var embeddedImage : Class;
private var _board:PuzzleBoard;
public function SlidingPuzzle() {
_board = new PuzzleBoard(300,300,4);
addChild(_board);
_board.createPuzzle(new embeddedImage());
_board.startGame();
}
}
}
[PuzzleBoard类]
package com.klstudio.puzzles.slider {
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.display.Bitmap;
import flash.geom.Matrix;
import flash.display.BitmapData;
import flash.display.Sprite;
/**
* PuzzleBoard
* @author Kinglong([email protected])
* @since:2010-9-13
*/
public class PuzzleBoard extends Sprite {
private var _pieces : Array;
private var _moving : Boolean;
private var _boardWidth : int;
private var _boardHeight : int;
private var _pieceWidth : Number;
private var _pieceHeight : Number;
private var _subdivisions : uint;
private var _space : uint;
private var _padding : uint;
public function PuzzleBoard(width : uint,height : uint,subdivisions : uint = 3,padding : uint = 1,space : int = -1) {
_pieces = [];
_moving = true;
_boardWidth = width;
_boardHeight = height;
_subdivisions = subdivisions = (subdivisions < 3) ? 3 : subdivisions;
_space = (space < subdivisions * subdivisions && space > -1) ? space : subdivisions - 1;
_padding = padding;
_pieceWidth = _boardWidth / subdivisions;
_pieceHeight = _boardHeight / subdivisions;
}
public function get subdivisions() : uint {
return _subdivisions;
}
public function get padding() : uint {
return _padding;
}
private function scaleImage(bitmap : Bitmap) : BitmapData {
var bd : BitmapData = new BitmapData(_boardWidth, _boardHeight);
var bRate : Number = _boardWidth / _boardHeight;
var iRate : Number = bitmap.width / bitmap.height;
var matrix : Matrix = new Matrix();
if(bRate < iRate) {
matrix.scale(_boardHeight * iRate / bitmap.width, _boardHeight / bitmap.height);
} else {
matrix.scale(_boardWidth / bitmap.width, _boardWidth / iRate / bitmap.height);
}
bd.draw(bitmap, matrix, null, null, null, true);
return bd;
}
public function createPuzzle(bitmap : Bitmap) : void {
clearBoard();
var bd : BitmapData = scaleImage(bitmap);
var pbd : BitmapData;
var len : uint = subdivisions * subdivisions;
var rect : Rectangle = new Rectangle(0, 0, _pieceWidth, _pieceHeight);
var point : Point = new Point();
for(var i : uint = 0;i < len;i++) {
if(i == _space) {
continue;
}
rect.x = (i % subdivisions) * _pieceWidth;
rect.y = Math.floor(i / subdivisions) * _pieceHeight;
pbd = new BitmapData(_pieceWidth, _pieceHeight);
pbd.copyPixels(bd, rect, point);
var piece : PuzzlePiece = new PuzzlePiece(pbd, new Point(i % subdivisions, Math.floor(i / subdivisions)), padding);
piece.addEventListener(PuzzleEvent.CLICK, clickHandler);
piece.addEventListener(PuzzleEvent.MOVE, moveHandler);
piece.addEventListener(PuzzleEvent.READY, moveHandler);
addChild(piece);
_pieces.push(piece);
}
}
public function startGame() : void {
var count : uint = 0;
var piece : PuzzlePiece;
var position : int;
while (count < 100) {
do {
piece = _pieces[int(Math.random() * _pieces.length - 1)];
position = checkNeighbours(piece);
}while (position == -1);
piece.move(position, false);
count++;
}
_moving = false;
}
private function clickHandler(event : PuzzleEvent) : void {
if(_moving) {
return;
}
var position : int = checkNeighbours(event.piece);
if(position > -1) {
event.piece.move(position);
}
}
private function moveHandler(event : PuzzleEvent) : void {
switch(event.type) {
case PuzzleEvent.READY:
_moving = false;
break;
case PuzzleEvent.MOVE:
_moving = true;
break;
}
}
private function clearBoard() : void {
if(_pieces.length == 0) {
return;
}
for each(var piece:PuzzlePiece in _pieces) {
piece.removeEventListener(PuzzleEvent.CLICK, clickHandler);
piece.removeEventListener(PuzzleEvent.READY, moveHandler);
piece.removeEventListener(PuzzleEvent.MOVE, moveHandler);
removeChild(piece);
}
_pieces = [];
}
private function isEmptySpace(x : int,y : int) : Boolean {
for each (var piece:PuzzlePiece in _pieces) {
if(piece.point.x == x && piece.point.y == y) {
return false;
}
}
return true;
}
private function checkNeighbours(piece : PuzzlePiece) : int {
if (piece.point.x > 0 && isEmptySpace(piece.point.x - 1, piece.point.y)) {
return PuzzlePiece.LEFT;
}
if (piece.point.x < subdivisions - 1 && isEmptySpace(piece.point.x + 1, piece.point.y)) {
return PuzzlePiece.RIGHT;
}
if (piece.point.y > 0 && isEmptySpace(piece.point.x, piece.point.y - 1)) {
return PuzzlePiece.UP;
}
if (piece.point.y < subdivisions - 1 && isEmptySpace(piece.point.x, piece.point.y + 1)) {
return PuzzlePiece.DOWN;
}
return -1;
}
}
}
[PuzzleEvent类]
package com.klstudio.puzzles.slider {
import flash.events.Event;
/**
* PuzzleEvent
* @author Kinglong([email protected])
* @since:2010-9-13
*/
public class PuzzleEvent extends Event {
private var _piece : PuzzlePiece;
public static const MOVE : String = "MOVE";
public static const READY : String = "READY";
public static const CLICK : String = "CLICK";
public function PuzzleEvent(type : String, piece : PuzzlePiece = null) {
super(type);
_piece = piece;
}
public function get piece() : PuzzlePiece {
return _piece;
}
override public function clone() : Event {
return new PuzzleEvent(type, piece);
}
}
}
[PuzzlePiece类]
package com.klstudio.puzzles.slider {
import flash.filters.GradientBevelFilter;
import flash.filters.BitmapFilter;
import flash.filters.BitmapFilterType;
import flash.filters.BitmapFilterQuality;
import flash.events.MouseEvent;
import gs.TweenLite;
import gs.easing.Circ;
import flash.display.Bitmap;
import flash.display.Shape;
import flash.geom.Point;
import flash.display.BitmapData;
import flash.display.Sprite;
/**
* PuzzlePiece
* @author Kinglong([email protected])
* @since:2010-9-13
*/
public class PuzzlePiece extends Sprite {
public static const DOWN : int = 3;
public static const LEFT : int = 1;
public static const UP : int = 4;
public static const RIGHT : int = 2;
private var _padding : uint;
private var _ease : Function;
private var _point : Point;
private var _oPoint : Point;
private var _bmp : Bitmap;
private var _mask : Shape;
public function PuzzlePiece(bitmapData : BitmapData,point : Point,padding : uint = 1) {
mouseChildren = false;
_ease = Circ.easeInOut;
_padding = padding;
_oPoint = point.clone();
_point = point.clone();
_bmp = new Bitmap(bitmapData);
addChild(_bmp);
_mask = new Shape();
_mask.graphics.beginFill(0xFF0000);
_mask.graphics.drawRoundRect(_padding, _padding, _bmp.width - _padding * 2, _bmp.height - _padding * 2, 8, 8);
_mask.graphics.endFill();
addChild(_mask);
_bmp.mask = _mask;
x = point.x * _bmp.width;
y = point.y * _bmp.height;
addEventListener(MouseEvent.CLICK, clickHandler);
_bmp.filters = [getBitmapFilter()];
}
public function move(position : int,tweened : Boolean = true) : void {
var params : Object = {ease:_ease, onComplete:tweenCompleteHandler};
var duration : Number = 0.4;
switch(position) {
case LEFT:
updatePoint(point.x - 1, point.y);
if(tweened) {
params["x"] = point.x * _bmp.width;
TweenLite.to(this, duration, params);
dispatchEvent(new PuzzleEvent(PuzzleEvent.MOVE));
} else {
x = point.x * _bmp.width;
}
break;
case RIGHT:
updatePoint(point.x + 1, point.y);
if(tweened) {
params["x"] = point.x * _bmp.width;
TweenLite.to(this, duration, params);
dispatchEvent(new PuzzleEvent(PuzzleEvent.MOVE));
} else {
x = point.x * _bmp.width;
}
break;
case UP:
updatePoint(point.x, point.y - 1);
if(tweened) {
params["y"] = point.y * _bmp.height;
TweenLite.to(this, duration, params);
dispatchEvent(new PuzzleEvent(PuzzleEvent.MOVE));
} else {
y = point.y * _bmp.height;
}
break;
case DOWN:
updatePoint(point.x, point.y + 1);
if(tweened) {
params["y"] = point.y * _bmp.height;
TweenLite.to(this, duration, params);
dispatchEvent(new PuzzleEvent(PuzzleEvent.MOVE));
} else {
y = point.y * _bmp.height;
}
break;
}
}
public function get point() : Point {
return _point;
}
public function reset() : void {
updatePoint(_oPoint.x, _oPoint.y);
x = point.x * _bmp.width;
y = point.y * _bmp.height;
}
private function updatePoint(x : int,y : int) : void {
_point.x = x;
_point.y = y;
if(hasCompleted()) {
_bmp.filters = null;
}else{
_bmp.filters = [getBitmapFilter()];
}
}
private function getBitmapFilter() : BitmapFilter {
return new GradientBevelFilter(5, 225, [16777215, 13421772, 0], [0.4, 0, 0.4], [0, 128, 255], 8, 8, 2, BitmapFilterQuality.HIGH, BitmapFilterType.INNER, false);
}
public function hasCompleted() : Boolean {
return _point.equals(_oPoint);
}
private function clickHandler(event : MouseEvent) : void {
dispatchEvent(new PuzzleEvent(PuzzleEvent.CLICK, this));
}
private function tweenCompleteHandler() : void {
dispatchEvent(new PuzzleEvent(PuzzleEvent.READY));
}
}
}