|
PuzzlePartList |
|
/*
* A puzzle game written in Java.
*
* Please read "http://juzzle.sourceforge.net/juzzle_licence.txt" for copyrights.
*
* The sourcecode is designed and created with
* Sun J2SDK 1.3 and Microsoft Visual J++ 6.0
*
* Juzzle homepage: http://juzzle.sourceforge.net
*
* autor: Slawa Weis
* email: slawaweis@animatronik.net
*
*/
package org.game.Juzzle;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
/**
* PuzzlePartList create the pieces of the image and controls these
*/
public class PuzzlePartList implements IPuzzlePartList
{
/**
* reference to the current game image
*/
protected BufferedImage bimage = null;
/**
* current game image width
*/
protected int imageWidth = -1;
/**
* current game image height
*/
protected int imageHeight = -1;
/**
* anchor for first and last part of list
*/
protected PuzzlePartList.PuzzlePart first, last = null;
/**
* array of parts
*/
protected PuzzlePartList.PuzzlePart pz_array [] = null;
/**
* solved parts
*/
protected int puzzleCount = 1;
/**
* selected part to drag. The part can be a member of a group or be self a group
*/
protected PuzzlePartList.PuzzlePart dragPart = null;
/**
* selected group to drag. dragPart is a member of this group
*/
protected PuzzlePartList.PuzzlePart dragGroup = null;
/**
* simply constructor
*
* @param bimage reference to the game image
* @param x_parts horizontal divirion
* @param y_parts vertical division
* @param random_size max width and height for the random calculation
*/
public PuzzlePartList(BufferedImage bimage, int x_parts, int y_parts, Dimension random_size)
{
super();
this.bimage = bimage;
imageWidth = bimage.getWidth();
imageHeight = bimage.getHeight();
Random random = new Random();
// part width and height
int partWidth = imageWidth /x_parts;
int partHeight = imageHeight/y_parts;
// last part width and height
int lastPartWidth = imageWidth - partWidth *(x_parts-1);
int lastPartHeight = imageHeight - partHeight*(y_parts-1);
// help variables
int currentImageWidth = 0;
int currentImageHeight = 0;
int i, j, k;
int random_max_x = random_size.width - partWidth - 60;
int random_max_y = random_size.height - partHeight - 60;
// create the array for parts
pz_array = new PuzzlePartList.PuzzlePart[x_parts * y_parts];
// help variables
PuzzlePartList.PuzzlePart node = null;
PuzzlePartList.PuzzlePart node_prev = null;
// creates the parts itself
for(j = k = 0; j < y_parts; j++)
{
// if last vertical part or not
if(j == y_parts-1)
currentImageHeight = lastPartHeight;
else
currentImageHeight = partHeight;
for(i = 0; i < x_parts; i++, k++)
{
// if last horizontal part or not
if(i == x_parts-1)
currentImageWidth = lastPartWidth;
else
currentImageWidth = partWidth;
// node = new PuzzlePart(i*iw + /*i*10 +*/ 10, j*ih + /*j*10 +*/ 10, i*iw, j*ih, iw, ih);
// node = new PuzzlePart(random.nextInt(780)+10, random.nextInt(780)+10, 0, 0, iw, ih);
// creates the part
node = new PuzzlePartList.PuzzlePart(bimage, random.nextInt(random_max_x)+30, random.nextInt(random_max_y)+30,
i*partWidth, j*partHeight,
currentImageWidth, currentImageHeight);
// add to array
pz_array[k] = node;
// reference the list anchors to the neighbourhood
if(j > 0)
{
node.north = pz_array[k-x_parts];
pz_array[k-x_parts].south = node;
}
// reference the list anchors to the neighbourhood
if(i > 0)
{
node.west = pz_array[k-1];
pz_array[k-1].east = node;
}
// set the first node
if(node_prev == null)
{
first = node;
}
// link the list
else
{
node_prev.next = node;
node.prev = node_prev;
}
// save the previous node
node_prev = node;
}
}
// set the last node
last = node;
// this code part creates the shape for the puzzle parts, i will rewrite this part of code in the next version
Rectangle destDraw = null;
Shape drawShape = null;
AffineTransform at = null;
for(i = 0; i < pz_array.length; i++)
{
node = pz_array[i];
destDraw = new Rectangle(node.boundsIn.x, node.boundsIn.y, node.boundsIn.width, node.boundsIn.height);
drawShape = destDraw;
at = new AffineTransform();
at.translate(node.boundsIn.x, node.boundsIn.y);
if(node.west != null)
{
Area area = new Area(drawShape);
GeneralPath gp = new GeneralPath();
float ys = (float)(destDraw.height/2.0 - 5.0);
float ys2 = ys - 5;
float center = ys + 5;
float yf = (float)(destDraw.height/2.0 + 5.0);
float yf2 = yf + 5;
gp.moveTo (0, ys);
gp.curveTo(-6, ys, -6, ys2, -13, ys2);
gp.curveTo(-16, ys2, -20, ys, -20, center);
gp.curveTo(-20, yf, -16, yf2, -13, yf2);
gp.curveTo(-6, yf2, -6, yf, 0, yf);
gp.transform(at);
area.add(new Area(gp));
drawShape = area;
node.boundsImage.translate(-20, 0);
node.boundsImage.width += 20;
}
if(node.east != null)
{
Area area = new Area(drawShape);
GeneralPath gp = new GeneralPath();
float ys = (float)(destDraw.height/2.0 - 5.0);
float ys2 = ys - 5;
float center = ys + 5;
float yf = (float)(destDraw.height/2.0 + 5.0);
float yf2 = yf + 5;
float x = destDraw.width;
gp.moveTo (x, ys);
gp.curveTo(x-6, ys, x-6, ys2, x-13, ys2);
gp.curveTo(x-16, ys2, x-20, ys, x-20, center);
gp.curveTo(x-20, yf, x-16, yf2, x-13, yf2);
gp.curveTo(x-6, yf2, x-6, yf, x, yf);
gp.transform(at);
area.subtract(new Area(gp));
drawShape = area;
}
if(node.north != null)
{
Area area = new Area(drawShape);
GeneralPath gp = new GeneralPath();
float xs = (float)(destDraw.width/2.0 - 5.0);
float xs2 = xs - 5;
float center = xs + 5;
float xf = (float)(destDraw.width/2.0 + 5.0);
float xf2 = xf + 5;
gp.moveTo (xs, 0);
gp.curveTo(xs, -6, xs2, -6, xs2, -13);
gp.curveTo(xs2, -16, xs, -20, center, -20);
gp.curveTo(xf, -20, xf2, -16, xf2, -13);
gp.curveTo(xf2, -6, xf, -6, xf, 0);
gp.transform(at);
area.add(new Area(gp));
drawShape = area;
node.boundsImage.translate(0, -20);
node.boundsImage.height += 20;
}
if(node.south != null)
{
Area area = new Area(drawShape);
GeneralPath gp = new GeneralPath();
float xs = (float)(destDraw.width/2.0 - 5.0);
float xs2 = xs - 5;
float center = xs + 5;
float xf = (float)(destDraw.width/2.0 + 5.0);
float xf2 = xf + 5;
float y = destDraw.height;
gp.moveTo (xs, y);
gp.curveTo(xs, y-6, xs2, y-6, xs2, y-13);
gp.curveTo(xs2, y-16, xs, y-20, center, y-20);
gp.curveTo(xf, y-20, xf2, y-16, xf2, y-13);
gp.curveTo(xf2, y-6, xf, y-6, xf, y);
gp.transform(at);
area.subtract(new Area(gp));
drawShape = area;
}
// creates the GeneralPath
node.generalPath = new GeneralPath(drawShape);
// out bounds for part
node.boundsOut = new Rectangle(node.generalPath.getBounds());
// out bounds for geometry
node.shapeBounds = new Rectangle(node.generalPath.getBounds());
//System.out.println(node.boundsIn);
//System.out.println(node.shapeBounds);
// location of out bounds
node.updateLocationOut();
// set the Paint rect of the image
node.puzzlePaint.setViewRect(node.boundsImage);
//System.out.println(node.locationIn);
//System.out.println(node.locationOut);
}
}
/**
* return the puzzle part count
*
* @return the puzzle part count
*/
public int getPartsCount()
{
return pz_array.length;
}
/**
* return the solved puzzle part count
*
* @return the solved puzzle part count
*/
public int getSolvedPartsCount()
{
return puzzleCount;
}
/**
* return the first node
*
* @return the first node
*/
public PuzzlePartList.PuzzlePart getFirstNode()
{
return first;
}
/**
* get the array with all parts, the array is never changing for a game, only the list is changing
*
* @return a array with all parts
*/
public PuzzlePartList.PuzzlePart [] getPartArray()
{
return pz_array;
}
/**
* is the part the selected part or not
*
* @param part the part to compare
* @return true if the same part or false if not
*/
public boolean isSelectedPart(PuzzlePartList.PuzzlePart part)
{
return (dragGroup == part);
}
/**
* select part at the point
*
* @param point point for selection
* @return true if selected or false if not
*/
public boolean selectPart(Point point)
{
Rectangle target = new Rectangle();
PuzzlePartList.PuzzlePart nodeGroup = null, nodeGroupPrev = null;
PuzzlePartList.PuzzlePart bestHitGroup = null, bestHitGroupPrev = null;
PuzzlePartList.PuzzlePart node = null, nodePrev = null;
PuzzlePartList.PuzzlePart bestHit = null, bestHitPrev = null;
// select the part and group of this part
nodeGroup = first;
while(nodeGroup != null)
{
nodePrev = null;
node = nodeGroup;
while(node != null)
{
target.setFrame(node.locationIn, node.boundsIn.getSize());
if(target.contains(point))
{
bestHitPrev = nodePrev;
bestHit = node;
bestHitGroupPrev = nodeGroupPrev;
bestHitGroup = nodeGroup;
}
nodePrev = node;
node = node.nextInGroup;
}
nodeGroupPrev = nodeGroup;
nodeGroup = nodeGroup.next;
}
// if found, move group on end of the list, what mean on top on the screen
if(bestHitGroup != null)
{
nodeGroup = bestHitGroup;
if(nodeGroup != last)
{
if(nodeGroup.prev != null)
{
nodeGroup.prev.next = nodeGroup.next;
nodeGroup.next.prev = nodeGroup.prev;
}
else
{
first = nodeGroup.next;
nodeGroup.next.prev = null;
}
nodeGroup.next = null;
nodeGroup.prev = last;
last.next = nodeGroup;
last = nodeGroup;
}
dragPart = bestHit;
dragGroup = nodeGroup;
return true;
}
return false;
}
/**
* another version only for part, don't used
*/
public boolean selectPart__(Point point)
{
Rectangle target = new Rectangle();
PuzzlePartList.PuzzlePart node = null, prevNode = null, bestHit = null, bestHitPrev = null;
for(int i = 0; i < pz_array.length; i++)
{
node = pz_array[i];
target.setFrame(node.locationIn, node.boundsIn.getSize());
if(target.contains(point))
{
bestHitPrev = prevNode;
bestHit = node;
}
}
if(bestHit != null)
{
node = bestHit;
if(node != last)
{
if(bestHitPrev != null)
{
bestHitPrev.next = node.next;
node.next = null;
last.next = node;
last = node;
}
else
{
first = node.next;
node.next = null;
last.next = node;
last = node;
}
}
dragPart = node;
return true;
}
return false;
}
/**
* deselect the selected part if one selected
*/
public void deselectPart()
{
dragPart = null;
dragGroup = null;
}
/**
* ask the model for the part that has changed and should be repainted
*
* @param repaintRect reference to the Rectangle, that get the repaint rectangle
*/
public void setRedrawRect(Rectangle repaintRect)
{
if(dragGroup == null)
repaintRect.setRect(0, 0, 0, 0);
else
repaintRect.setRect(dragGroup.locationOut.x - (dragGroup.boundsOut.x - dragGroup.shapeBounds.x),
dragGroup.locationOut.y - (dragGroup.boundsOut.y - dragGroup.shapeBounds.y),
dragGroup.shapeBounds.width,
dragGroup.shapeBounds.height);
//System.out.println(repaintRect);
//System.out.println(dragGroup.locationIn.x + ":" + dragGroup.locationOut.x + ":" + dragGroup.boundsOut.x + ":" + dragGroup.shapeBounds.x);
}
/**
* move the selected part
*
* @param dx new x position
* @param dy new y position
*/
public void moveLocation(int dx, int dy)
{
moveLocationGroup(dragGroup, dx, dy);
}
/**
* move the selected group
*
* @param group group to move
* @param dx new x position
* @param dy new y position
*/
protected void moveLocationGroup(PuzzlePartList.PuzzlePart group, int dx, int dy)
{
PuzzlePartList.PuzzlePart node = group;
// move all parts of group
while(node != null)
{
node.locationIn.setLocation(node.locationIn.x + dx,
node.locationIn.y + dy);
node.updateLocationOut();
node = node.nextInGroup;
}
}
/**
* if the piece is releasing, test if it pass to another part and if true create a new part
*/
public void updatePart()
{
PuzzlePartList.PuzzlePart node = dragGroup;
// for all parts of group
while(node != null)
{
if(((node.lock & PuzzlePartList.PuzzlePart.WEST) != PuzzlePartList.PuzzlePart.WEST) && node.west != null)
{
// check if pass
if((node.locationIn.x >= (node.west.locationIn.x + node.west.boundsIn.width - 5) &&
node.locationIn.x <= (node.west.locationIn.x + node.west.boundsIn.width + 5)) &&
(node.locationIn.y >= (node.west.locationIn.y - 5) &&
node.locationIn.y <= (node.west.locationIn.y + 5)))
{
// move to pass exactly
moveLocationGroup(dragGroup, -(node.locationIn.x - (node.west.locationIn.x + node.west.boundsIn.width)),
-(node.locationIn.y - node.west.locationIn.y));
// this pieces a locked
node.lock |= PuzzlePartList.PuzzlePart.WEST;
node.west.lock |= PuzzlePartList.PuzzlePart.EAST;
// update the list and shape of group
updateGroup(dragGroup, node, node.west);
}
}
if(((node.lock & PuzzlePartList.PuzzlePart.EAST) != PuzzlePartList.PuzzlePart.EAST) && node.east != null)
{
if((node.locationIn.x + node.boundsIn.width >= (node.east.locationIn.x - 5) &&
node.locationIn.x + node.boundsIn.width <= (node.east.locationIn.x + 5)) &&
(node.locationIn.y >= (node.east.locationIn.y - 5) &&
node.locationIn.y <= (node.east.locationIn.y + 5)))
{
moveLocationGroup(dragGroup, -(node.locationIn.x - (node.east.locationIn.x - node.boundsIn.width)),
-(node.locationIn.y - node.east.locationIn.y));
node.lock |= PuzzlePartList.PuzzlePart.EAST;
node.east.lock |= PuzzlePartList.PuzzlePart.WEST;
updateGroup(dragGroup, node, node.east);
}
}
if(((node.lock & PuzzlePartList.PuzzlePart.NORTH) != PuzzlePartList.PuzzlePart.NORTH) && node.north != null)
{
if((node.locationIn.y >= (node.north.locationIn.y + node.north.boundsIn.height - 5) &&
node.locationIn.y <= (node.north.locationIn.y + node.north.boundsIn.height + 5)) &&
(node.locationIn.x >= (node.north.locationIn.x - 5) &&
node.locationIn.x <= (node.north.locationIn.x + 5)))
{
moveLocationGroup(dragGroup, -(node.locationIn.x - node.north.locationIn.x),
-(node.locationIn.y - (node.north.locationIn.y + node.north.boundsIn.height)));
node.lock |= PuzzlePartList.PuzzlePart.NORTH;
node.north.lock |= PuzzlePartList.PuzzlePart.SOUTH;
updateGroup(dragGroup, node, node.north);
}
}
if(((node.lock & PuzzlePartList.PuzzlePart.SOUTH) != PuzzlePartList.PuzzlePart.SOUTH) && node.south != null)
{
if((node.locationIn.y + node.boundsIn.height >= (node.south.locationIn.y - 5) &&
node.locationIn.y + node.boundsIn.height <= (node.south.locationIn.y + 5)) &&
(node.locationIn.x >= (node.south.locationIn.x - 5) &&
node.locationIn.x <= (node.south.locationIn.x + 5)))
{
moveLocationGroup(dragGroup, -(node.locationIn.x - node.south.locationIn.x),
-(node.locationIn.y - (node.south.locationIn.y - node.boundsIn.height)));
node.lock |= PuzzlePartList.PuzzlePart.SOUTH;
node.south.lock |= PuzzlePartList.PuzzlePart.NORTH;
updateGroup(dragGroup, node, node.south);
}
}
// next in group
node = node.nextInGroup;
}
}
/**
* update the list and shape of group
*
* @param dragGroup group to change
* @param node node of dragGroup that pass
* @param node2 node of another group that pass
*/
protected void updateGroup(PuzzlePartList.PuzzlePart dragGroup, PuzzlePartList.PuzzlePart node, PuzzlePartList.PuzzlePart node2)
{
// last node of dragGroup
PuzzlePartList.PuzzlePart lastNodeOfGroup = null;
// first node of another group
PuzzlePartList.PuzzlePart firstNodeOfOtherGroup = null;
// get the first node of another group
firstNodeOfOtherGroup = node2;
while(firstNodeOfOtherGroup.prevInGroup != null) firstNodeOfOtherGroup = firstNodeOfOtherGroup.prevInGroup;
// if the same group
if(dragGroup == firstNodeOfOtherGroup) return;
// get the last node of dragGroup
lastNodeOfGroup = dragGroup;
while(lastNodeOfGroup.nextInGroup != null) lastNodeOfGroup = lastNodeOfGroup.nextInGroup;
// update list
lastNodeOfGroup.nextInGroup = firstNodeOfOtherGroup;
firstNodeOfOtherGroup.prevInGroup = lastNodeOfGroup;
if(firstNodeOfOtherGroup.prev != null)
firstNodeOfOtherGroup.prev.next = firstNodeOfOtherGroup.next;
else
first = firstNodeOfOtherGroup.next;
if(firstNodeOfOtherGroup.next != null)
firstNodeOfOtherGroup.next.prev = firstNodeOfOtherGroup.prev;
else
last = firstNodeOfOtherGroup.prev;
// not more needed, this part is in the group
firstNodeOfOtherGroup.prev = firstNodeOfOtherGroup.next = null;
// update the geometricaly shape
dragGroup.generalPath.append(firstNodeOfOtherGroup.generalPath, false);
dragGroup.shapeBounds = new Rectangle(dragGroup.generalPath.getBounds());
// update the image rect
dragGroup.boundsImage.add(firstNodeOfOtherGroup.boundsImage);
dragGroup.puzzlePaint.setViewRect(dragGroup.boundsImage);
// for solved count
// dragGroup.partsInGroup += firstNodeOfOtherGroup.partsInGroup;
if(puzzleCount == 0) puzzleCount += 1;
puzzleCount += 1;
}
/**
* class for one piece
*/
public static class PuzzlePart
{
/**
* for locking if two pieces pass together
*/
public static final int WEST = 0x01;
/**
* for locking if two pieces pass together
*/
public static final int EAST = 0x02;
/**
* for locking if two pieces pass together
*/
public static final int NORTH = 0x04;
/**
* for locking if two pieces pass together
*/
public static final int SOUTH = 0x08;
/**
* location of inner bounds
*/
public Point locationIn = new Point();
/**
* location of outer bounds
*/
public Point locationOut = new Point();
/**
* inner bounds
*/
public Rectangle boundsIn = new Rectangle();
/**
* outer bounds
*/
public Rectangle boundsOut = new Rectangle();
/**
* image bounds
*/
public Rectangle boundsImage = new Rectangle();
/**
* geometricaly shape
*/
public GeneralPath generalPath = null;
/**
* bounds of geometricaly shape
*/
public Rectangle shapeBounds = new Rectangle();
/**
* paint for this piece
*/
public PuzzlePaint puzzlePaint = null;
/**
* next for the group (horizontal linking)
*/
public PuzzlePart next = null;
/**
* prev for the group (horizontal linking)
*/
public PuzzlePart prev = null;
/**
* next in group (vertical linking)
*/
public PuzzlePart nextInGroup = null;
/**
* prev in group (vertical linking)
*/
public PuzzlePart prevInGroup = null;
/**
* reference to the neighbourhood
*/
public PuzzlePart north = null;
/**
* reference to the neighbourhood
*/
public PuzzlePart south = null;
/**
* reference to the neighbourhood
*/
public PuzzlePart west = null;
/**
* reference to the neighbourhood
*/
public PuzzlePart east = null;
/**
* if locked to WEST, EAST, NORTH, SOUTH or not
*/
public int lock = 0;
/* *
* for solved parts in group
*/
// public int partsInGroup = 1;
/**
* simply constructor
*
* @param bimage reference to the image
* @param lx location x of piece
* @param ly location y of piece
* @param plx pixel location x of image
* @param ply pixel location y of image
* @param width width of piece and image part
* @param height height of piece and image part
*/
public PuzzlePart(BufferedImage bimage, int lx, int ly, int pix, int piy, int width, int height)
{
locationIn.setLocation(lx, ly);
boundsImage.setRect(pix, piy, width, height);
boundsIn.setRect(pix, piy, width, height);
puzzlePaint = new PuzzlePaint(bimage, boundsImage);
}
/**
* update the outer location from inner
*/
public void updateLocationOut()
{
locationOut.setLocation(locationIn.x - (boundsIn.x - boundsOut.x), locationIn.y - (boundsIn.y - boundsOut.y));
}
/**
* create a description of this part for debugging
*
* @return a string representation of this piece
*/
public String toString()
{
return "PuzzlePart[location: " + locationIn.x + ", " + locationIn.y +
"; rect: " + boundsIn.x + ", " + boundsIn.y + ", " + boundsIn.width + ", " + boundsIn.height +
"]";
}
}
}
|
PuzzlePartList |
|