/* Copyright 2010 Christian Matt
*
* This file is part of PonkOut.
*
* PonkOut is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PonkOut is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PonkOut. If not, see <http://www.gnu.org/licenses/>.
*/
package ponkOut.logic;
import java.util.LinkedList;
import java.util.List;
import org.lwjgl.util.vector.Vector2f;
import ponkOut.logic.Block.CornerPlace;
/**
* Used for collision detection. Contains a list of all blocks which share a
* face and the two end points.
*/
public class BlockFace {
private LinkedList<Block> blocks;
private Block.FacePlace facePlace;
/** position of left or top end point */
private Vector2f firstCorner;
/** position of right or bottom end point */
private Vector2f secondCorner;
/**
* creates a new face containing only one block
*/
public BlockFace(Block block, Block.FacePlace facePlace) {
blocks = new LinkedList<Block>();
blocks.add(block);
this.facePlace = facePlace;
firstCorner = getFirstCorner(block);
secondCorner = getSecondCorner(block);
block.setFace(this);
}
/**
* @param block
* an arbitrary block
* @return position of the first corner of the face with the same facePlace
* as this the block induces
*/
private Vector2f getFirstCorner(Block block) {
switch (facePlace) {
case LEFT:
return block.getCornerPos(CornerPlace.TOP_LEFT);
case RIGHT:
return block.getCornerPos(CornerPlace.TOP_RIGHT);
case TOP:
return block.getCornerPos(CornerPlace.TOP_LEFT);
case BOTTOM:
return block.getCornerPos(CornerPlace.BOTTOM_LEFT);
default:
throw new IllegalArgumentException("face does not have a valid value");
}
}
/**
* @param block
* an arbitrary block
* @return position of the second corner of the face with the same facePlace
* as this the block induces
*/
private Vector2f getSecondCorner(Block block) {
switch (facePlace) {
case LEFT:
return block.getCornerPos(CornerPlace.BOTTOM_LEFT);
case RIGHT:
return block.getCornerPos(CornerPlace.BOTTOM_RIGHT);
case TOP:
return block.getCornerPos(CornerPlace.TOP_RIGHT);
case BOTTOM:
return block.getCornerPos(CornerPlace.BOTTOM_RIGHT);
default:
throw new IllegalArgumentException("face does not have a valid value");
}
}
/**
* @param block
* this block is added to the front of this block's list
*/
public void addFront(Block block) {
blocks.add(0, block);
firstCorner = getFirstCorner(block);
block.setFace(this);
}
/**
* @param block
* this block is added to the end of this block's list
*/
public void addBack(Block block) {
blocks.add(block);
secondCorner = getSecondCorner(block);
block.setFace(this);
}
/**
* @param block
* all blocks in this face are added to the front of this face's
* list
*/
public void addFront(BlockFace face) {
for (int i = face.blocks.size() - 1; i >= 0; --i) {
Block block = face.blocks.get(i);
blocks.add(0, block);
block.setFace(this);
}
firstCorner = face.firstCorner;
}
/**
* @param block
* all blocks in face are added to the end of this face's list
*/
public void addBack(BlockFace face) {
for (int i = 0; i < face.blocks.size(); ++i) {
Block block = face.blocks.get(i);
blocks.add(block);
block.setFace(this);
}
secondCorner = face.secondCorner;
}
/**
* @param block
* block to remove
* @param createdFace
* will be set to the newly created or to null if no face was
* created
* @return true if this was the last block in this face, false if there are
* still blocks in this face
*/
/**
* @param block
* block to remove
* @param faces
* List to all faces of the same facePlace as this. Faces may be
* removed or added.
*/
public void remove(Block block, List<BlockFace> faces) {
BlockFace createdFace = null;
int index = blocks.indexOf(block);
if (index < 0)
throw new IllegalArgumentException(block + " is not part of this face.");
Vector2f blockFirstCorner = getFirstCorner(block);
Vector2f blockSecondCorner = getSecondCorner(block);
// adjust corner of block to remove if at one end of the face
if (blocks.size() == 1) {
faces.remove(this);
} else if (index == 0) {
firstCorner = blockSecondCorner;
} else if (index == blocks.size() - 1) {
secondCorner = blockFirstCorner;
} else {
// split the face into two parts
secondCorner = blockFirstCorner;
createdFace = new BlockFace(blocks.get(index + 1), facePlace);
blocks.remove(index + 1);
while (blocks.size() > index + 1) {
createdFace.addBack(blocks.get(index + 1));
blocks.remove(index + 1);
}
}
if (createdFace != null)
faces.add(createdFace);
block.removeFace(facePlace);
blocks.remove(index);
}
public Block.FacePlace getFacePlace() {
return facePlace;
}
public Vector2f getFirstCorner() {
return firstCorner;
}
public Vector2f getSecondCorner() {
return secondCorner;
}
/**
* Sets new corner position and removes all blocks which are outside the new
* corners.
*
* @param firstCorner
* New position of the first corner. Must not be beyond second
* corner.
*/
public void setFirstCorner(Vector2f firstCorner) {
switch (facePlace) {
case LEFT:
case RIGHT:
while (blocks.getFirst().getCornerPos(CornerPlace.BOTTOM_RIGHT).y >= firstCorner.y) {
blocks.getFirst().removeFace(facePlace);
blocks.removeFirst();
}
break;
case TOP:
case BOTTOM:
while (blocks.getFirst().getCornerPos(CornerPlace.BOTTOM_RIGHT).x <= firstCorner.x) {
blocks.getFirst().removeFace(facePlace);
blocks.removeFirst();
}
break;
}
this.firstCorner = new Vector2f(firstCorner.x, firstCorner.y);
}
/**
* Sets new corner position and removes all blocks which are outside the new
* corners.
*
* @param secondCorner
* New position of the second corner. Must not be beyond first
* corner.
*/
public void setSecondCorner(Vector2f secondCorner) {
switch (facePlace) {
case LEFT:
case RIGHT:
while (blocks.getLast().getCornerPos(CornerPlace.TOP_LEFT).y <= secondCorner.y) {
blocks.getLast().removeFace(facePlace);
blocks.removeLast();
}
break;
case TOP:
case BOTTOM:
while (blocks.getLast().getCornerPos(CornerPlace.TOP_LEFT).x >= secondCorner.x) {
blocks.getLast().removeFace(facePlace);
blocks.removeLast();
}
break;
}
this.secondCorner = new Vector2f(secondCorner.x, secondCorner.y);
}
public List<Block> getBlocks() {
return blocks;
}
/**
* @param position
* the position of the block
* @return block nearest to position
*/
public Block getBlockAt(Vector2f position) {
Block block = blocks.get(0);
switch (facePlace) {
case LEFT:
case RIGHT:
// go down until upper corner of block is below position
for (Block b : blocks) {
if (b.getCornerPos(CornerPlace.TOP_LEFT).y >= position.y)
block = b;
else
break;
}
break;
case TOP:
case BOTTOM:
// go right until left corner of block is to the right of position
for (Block b : blocks) {
if (b.getCornerPos(CornerPlace.TOP_LEFT).x <= position.x)
block = b;
else
break;
}
break;
}
return block;
}
}