package { import flash.display.*; import flash.events.*; import flash.net.URLRequest; import flash.geom.*; import flash.utils.Timer; public class JigsawPuzzle extends MovieClip { // number of pieces const numPiecesHoriz:int = 3; const numPiecesVert:int = 3; // size of pieces var pieceWidth:Number; var pieceHeight:Number; // game pieces var puzzleObjects:Array; // two levels of sprites var selectedPieces:Sprite; var otherPieces:Sprite; // pieces being dragged var beingDragged:Array = new Array(); // load picture and set up sprites public function startJigsawPuzzle() { // load the bitmap loadBitmap("jigsawimage.jpg"); // set up two sprites otherPieces = new Sprite(); selectedPieces = new Sprite(); addChild(otherPieces); addChild(selectedPieces); // selected on top } // get the bitmap from an external source public function loadBitmap(bitmapFile:String) { var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingDone); var request:URLRequest = new URLRequest(bitmapFile); loader.load(request); } // bitmap done loading, cut into pieces private function loadingDone(event:Event):void { // create new image to hold loaded bitmap var image:Bitmap = Bitmap(event.target.loader.content); pieceWidth = Math.floor((image.width/numPiecesHoriz)/10)*10; pieceHeight = Math.floor((image.height/numPiecesVert)/10)*10; // place loaded bitmap in image var bitmapData:BitmapData = image.bitmapData; // cut into puzzle pieces makePuzzlePieces(bitmapData); // set up movement and mouse up events addEventListener(Event.ENTER_FRAME,movePieces); stage.addEventListener(MouseEvent.MOUSE_UP,liftMouseUp); } // cut bitmap into pieces private function makePuzzlePieces(bitmapData:BitmapData) { puzzleObjects = new Array(); for(var x:uint=0;x<numPiecesHoriz;x++) { for (var y:uint=0;y<numPiecesVert;y++) { // create new puzzle piece bitmap and sprite var newPuzzlePieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth,pieceHeight)); newPuzzlePieceBitmap.bitmapData.copyPixels(bitmapData,new Rectangle(x*pieceWidth,y*pieceHeight,pieceWidth,pieceHeight),new Point(0,0)); var newPuzzlePiece:Sprite = new Sprite(); newPuzzlePiece.addChild(newPuzzlePieceBitmap); // place in bottom sprite otherPieces.addChild(newPuzzlePiece); // create object to store in array var newPuzzleObject:Object = new Object(); newPuzzleObject.loc = new Point(x,y); // location in puzzle newPuzzleObject.dragOffset = null; // offset from cursor newPuzzleObject.piece = newPuzzlePiece; newPuzzlePiece.addEventListener(MouseEvent.MOUSE_DOWN,clickPuzzlePiece); puzzleObjects.push(newPuzzleObject); } } // randomize locations of pieces shufflePieces(); } // random locations for the pieces public function shufflePieces() { // pick random x and y for(var i in puzzleObjects) { puzzleObjects[i].piece.x = Math.random()*400+50; puzzleObjects[i].piece.y = Math.random()*250+50; } // lock all pieces to 10x10 grid lockPiecesToGrid(); } public function clickPuzzlePiece(event:MouseEvent) { // click location var clickLoc:Point = new Point(event.stageX, event.stageY); beingDragged = new Array(); // find piece clicked for(var i in puzzleObjects) { if (puzzleObjects[i].piece == event.currentTarget) { // this is it // add to drag list beingDragged.push(puzzleObjects[i]); // get offset from cursor puzzleObjects[i].dragOffset = new Point(clickLoc.x - puzzleObjects[i].piece.x, clickLoc.y - puzzleObjects[i].piece.y); // move from bottom sprite to top one selectedPieces.addChild(puzzleObjects[i].piece); // find other pieces locked to this one findLockedPieces(i,clickLoc); break; } } } // move all selected pieces according to mouse location public function movePieces(event:Event) { for (var i in beingDragged) { beingDragged[i].piece.x = mouseX - beingDragged[i].dragOffset.x; beingDragged[i].piece.y = mouseY - beingDragged[i].dragOffset.y; } } // find pieces that should move together public function findLockedPieces(clickedPiece:uint, clickLoc:Point) { // get list of puzzle objects sorted by distance to the clicked object var sortedObjects:Array = new Array(); for (var i in puzzleObjects) { if (i == clickedPiece) continue; sortedObjects.push({dist: Point.distance(puzzleObjects[clickedPiece].loc,puzzleObjects[i].loc), num: i}); } sortedObjects.sortOn("dist",Array.DESCENDING); // loop until all linked piece found do { var oneLinkFound:Boolean = false; // look at each object, starting with closest for(i=sortedObjects.length-1;i>=0;i--) { var n:uint = sortedObjects[i].num; // actual object number // get the position relative to the clicked object var diffX:int = puzzleObjects[n].loc.x - puzzleObjects[clickedPiece].loc.x; var diffY:int = puzzleObjects[n].loc.y - puzzleObjects[clickedPiece].loc.y; // see if this object is appropriately placed to be locked to the clicked one if (puzzleObjects[n].piece.x == (puzzleObjects[clickedPiece].piece.x + pieceWidth*diffX)) { if (puzzleObjects[n].piece.y == (puzzleObjects[clickedPiece].piece.y + pieceHeight*diffY)) { // see if this object is adjacent to one already selected if (isConnected(puzzleObjects[n])) { // add to selection list and set offset beingDragged.push(puzzleObjects[n]); puzzleObjects[n].dragOffset = new Point(clickLoc.x - puzzleObjects[n].piece.x, clickLoc.y - puzzleObjects[n].piece.y); // move to top sprite selectedPieces.addChild(puzzleObjects[n].piece); // link found, remove from array oneLinkFound = true; sortedObjects.splice(i,1); } } } } } while (oneLinkFound); } // takes an object and determines if it is directly next to one already selected public function isConnected(newPuzzleObject:Object):Boolean { for(var i in beingDragged) { var horizDist:int = Math.abs(newPuzzleObject.loc.x - beingDragged[i].loc.x); var vertDist:int = Math.abs(newPuzzleObject.loc.y - beingDragged[i].loc.y); if ((horizDist == 1) && (vertDist == 0)) return true; if ((horizDist == 0) && (vertDist == 1)) return true; } return false; } // stage sends mouse up event, drag is over public function liftMouseUp(event:MouseEvent) { // lock all pieces back to grid lockPiecesToGrid(); // move pieces back to bottom sprite for(var i in beingDragged) { otherPieces.addChild(beingDragged[i].piece); } // clear drag array beingDragged = new Array(); // see if the game is over if (puzzleTogether()) { cleanUpJigsaw(); gotoAndStop("gameover"); } } // take all pieces and lock them to the nearest 10x10 location public function lockPiecesToGrid() { for(var i in puzzleObjects) { puzzleObjects[i].piece.x = 10*Math.round(puzzleObjects[i].piece.x/10); puzzleObjects[i].piece.y = 10*Math.round(puzzleObjects[i].piece.y/10); } } public function puzzleTogether():Boolean { for(var i:uint=1;i<puzzleObjects.length;i++) { // get the position relative to the first object var diffX:int = puzzleObjects[i].loc.x - puzzleObjects[0].loc.x; var diffY:int = puzzleObjects[i].loc.y - puzzleObjects[0].loc.y; // see if this object is appropriately placed to be locked to the first one if (puzzleObjects[i].piece.x != (puzzleObjects[0].piece.x + pieceWidth*diffX)) return false; if (puzzleObjects[i].piece.y != (puzzleObjects[0].piece.y + pieceHeight*diffY)) return false } return true; } public function cleanUpJigsaw() { removeChild(selectedPieces); removeChild(otherPieces); selectedPieces = null; otherPieces = null; puzzleObjects = null; beingDragged = null; removeEventListener(Event.ENTER_FRAME,movePieces); stage.removeEventListener(MouseEvent.MOUSE_UP,liftMouseUp); } } }