I want to create a puzzle game where you have the pieces cut in squares and you have to slide the pieces around with one empty space. How can I set this up?
This is a project that first looks like a great use for arrays, lists, etc., but it can really be a lot simpler. The first step is to set up all the pieces and make sure the edges just touch but do not overlap. Director's "snap to grid" features can help a lot in the initial layout. Choose your grid (3X3, 4X4, 5X6, etc.) and make the pieces. For this example we will use simple numbers.
Now that we have our graphics, lets make sure all of them are exactly the same size and center all the registration points. This allows us to swap the cast members without alignment problems. Now we can randomize things a bit. We start off by adding all the pieces to a global list. This is used to track which pieces we have on the board, and to allow them to shuffle to any location, without missing any pieces. In the beginSprite handler we can have each piece add its cast member to the list and also set a property for the default piece. This we will use later to check if all pieces are in the correct location and the user has "won" our game.
Once every piece knows where is should be we start moving them around. By making a duplicate of the master list of pieces we can then get a random piece and delete it from the list. When we are done, every piece has a new graphic and there are no duplicates. Now we need to move them. The only way a piece can move is to slide into the "empty" slot. To do this we can check the current piece and see if it borders an empty space. The initial reaction would be to avoid the intersect() command because the pieces touch, but do not overlap, but with a little modification we can have this work for us and simplify the whole process.
If we set up our board correctly, no 2 pieces intersect, but by passing a modified rectangle for a sprite to the function we can determine if the 2 pieces are touching. We do this by inflating the rectangle we are checking by one pixel in each direction. If we add the rectangle of the sprite we click on to the rectangle rect(-1,-1,1,1) we can then test this against out "empty" space. If the 2 intersect, then the pieces touch. We then add a conditional statement to keep diagonal pieces from being included and the rest solves itself.
Below is the code. Note the use of the sendAllSprites command to broadcast the intersect and solve commands to the sprites, avoiding the need to constantly track where each piece and the blank square are.
--Copyright 1999 Chuck Neal
--chuck@mediamacros.com
--If you find this code helpful, send me an e-mail and let me know. :-)
property spriteNum, piece
global pieceList, pickList
on beginSprite me
--name the pieces by number
piece = sprite(spriteNum).member.name
if pieceList = void then
pieceList = []
end if
if pieceList.getOne(piece) <> 0 then
--old list, reinitialize
pieceList = []
end if
pieceList.add(piece)
end
on shuffle me
if pickList = void then
pickList = duplicate(pieceList)
else if pickList.count = 0 then
pickList = duplicate(pieceList)
end if
thisOne = random(pickList.count)
sprite(spriteNum).member = member(pickList[thisOne])
pickList.deleteAt(thisOne)
end
on swap me, whatRect, whatSprite
--check for lastOne
sort(pieceList)
if sprite(spriteNum).member = member(pieceList[pieceList.count]) and spriteNum <> whatSprite then
--is the "last one" (blank space)
overlap = intersect(sprite(spriteNum).rect, whatRect)
if (overLap.width > 0 or overlap.height > 0) then
--do they overLap?
if overLap.width > 1 or overlap.height > 1 then
--make sure they don;t overlap diagonally
--if they intersect, swap
whatMember = sprite(spriteNum).member
sprite(spriteNum).member = sprite(whatSprite).member
sprite(whatSprite).member = whatMember
end if
end if
end if
end
on checkWin me, winList
if sprite(spriteNum).member.name = piece then
winList.add(1)
else
winList.add(0)
end if
end
on mouseUp me
sendAllSprites(#swap, (sprite(spriteNum).rect + rect(-1,-1,1,1), spriteNum)
winList = []
sendAllSprites(#checkWin, winList)
if winList.getOne(0) = 0 then
--win
go "win"
end if
end
on getBehaviorDescription me
describe = "This behavior can be dropped on a grid of images to create a sliding puzzle game."
describe = describe & return & "Be sure to name your pieces concurrently and name the " & quote & "empty" & quote & " piece so that it will fall at the end of the list when sorted alphabetically."
describe = describe & return & "A working example with full source code can be found in the learning arcade at www.mediamacros.com"
return describe
end
Contact
MMI
36 South Court Sq
Suite 300
Newnan, GA 30263
USA