package aitgame.tilegame;
import java.awt.Point;
import java.util.Iterator;
import java.util.LinkedList;
import aitgame.graphics.Sprite;
import aitgame.tilegame.sprites.Creature;
/**
* CollisionManager manages all the collisions in the game. It detects
* collisions on walls, other objects and it handels what other objects
* the player has connecton with.
*
* @author Ait-game team
*/
public class CollisionManager {
private TileMap map;
private Point pointCache = new Point();
private TileMapRenderer renderer;
private double oldX = 0, oldY = 0;
/**
* This is the start of the collision and is called of detecting collision
* and it sees to that the objects updates to the right position.
*/
public void handleColisionsAndMoves(LinkedList<Sprite> collisionAndUpdate,
LinkedList<Sprite> iOnlyCollision, LinkedList<Sprite> itemSprites, long elapsedTime,
TileMap map, TileMapRenderer renderer) {
this.map = map;
this.renderer = renderer;
Iterator<Sprite> iCollisionAndUpdate = collisionAndUpdate.iterator();
while (iCollisionAndUpdate.hasNext()) {
Creature person = (Creature) iCollisionAndUpdate.next();
if(!checkPeopleCollision(person, elapsedTime, collisionAndUpdate.iterator(),
iOnlyCollision.iterator())){
checkTileCollision(person, elapsedTime);
}
person.update(elapsedTime);
//Looks for people and objects that can be contacted.
person.removeContacts();
checkContactCollision(person, elapsedTime, collisionAndUpdate.iterator(),
iOnlyCollision.iterator(), itemSprites.iterator());
}
}
/*
* Checks the collision to tile so the moving objects doesn't go through the walls
* and other tiles that is not made for walking on.
*/
private void checkTileCollision(Creature person, long elapsedTime) {
//check xCollision
Point tile = checkTileCollisionX(person, elapsedTime);
if(tile == null){
person.updatePositionX(elapsedTime);
}else{
person.updatePositionX(elapsedTime, tile);
}
//check yCollision
tile = checkTileCollisionY(person, elapsedTime);
if(tile == null){
person.updatePositionY(elapsedTime);
}else{
person.updatePositionY(elapsedTime, tile);
}
}
/**
* Check the collision on tiles i X-axis
*/
private Point checkTileCollisionX(Creature person, long elapsedTime) {
float newX = person.getNewX(elapsedTime);
Point tile = getTileCollision(person, newX, person.getCollisionY());
//If no collision found
if (tile == null) {
return null;
}
return tile;
}
/**
* Checks the collision on tiles i Y-axis
*/
private Point checkTileCollisionY(Creature person, long elapsedTime) {
float newY = person.getNewY(elapsedTime);
Point tile = getTileCollision(person, person.getCollisionX(), newY);
//If no collision found
if (tile == null) {
return null;
}
return tile;
}
/**
* Checks collision on peoples and other objects that can move.
*/
private boolean checkPeopleCollision(Creature person, long elapsedTime,
Iterator<Sprite> iCollisionAndUpdate, Iterator<Sprite> iOnlyCollision) {
Creature creature;
boolean collision = false;
//check for collision in CollisionAndUpdate-list.
while (iCollisionAndUpdate.hasNext()) {
creature = (Creature) iCollisionAndUpdate.next();
}
//check for collision in iOnlyCollision-list.
while (iOnlyCollision.hasNext()) {
creature = (Creature) iOnlyCollision.next();
collision = collision(person, creature, elapsedTime);
}
if(collision){
return collision;
}
return false;
}
/**
* A mathematical test to see if two objects is colliding.
*/
private boolean collision(Creature c1, Creature c2, long elapsedTime){
double x1 = c1.getNewX(elapsedTime);
double y1 = c1.getNewY(elapsedTime);
double x2 = c2.getCollisionX(), y2 = c2.getCollisionY();
double r1 = 30, r2 = 30;
double dx = x1 - x2;
double dy = y1 - y2;
double d = Math.sqrt(dx * dx + dy * dy);
if (d <= r1 + r2) {
double PositionChangeX1 = (r1+r2)/d*dx;
double PositionChangeY1 = (r1+r2)/d*dy;
x1 = x2 + PositionChangeX1;
y1 = y2 + PositionChangeY1;
// update locations
if (!Double.isNaN(x1)){
c1.setCollisionX((float) x1);
}
if (!Double.isNaN(y1)){
c1.setCollisionY((float) y1);
}
return true;
}else{
return false;
}
}
/**
* Checks to see if objects has contact with each other.
*/
private void checkContactCollision(Creature person, long elapsedTime, Iterator<Sprite> iCollisionAndUpdate,
Iterator<Sprite> iOnlyCollision, Iterator<Sprite> itemSprites) {
Creature creature;
//check for collision in CollisionAndUpdate-list.
while (iCollisionAndUpdate.hasNext()) {
creature = (Creature) iCollisionAndUpdate.next();
}
//check for collision in iOnlyCollision-list.
while (iOnlyCollision.hasNext()) {
creature = (Creature) iOnlyCollision.next();
isContactCollision(person, creature, elapsedTime);
}
//check for collision in itemSprites-list.
while (itemSprites.hasNext()) {
creature = (Creature) iOnlyCollision.next();
}
}
/**
* Mathematical test to see if the objects has a contection.
*/
private boolean isContactCollision(Creature person, Creature creature, long elapsedTime) {
double x1 = person.getNewX(elapsedTime);
double y1 = person.getNewY(elapsedTime);
double x2 = creature.getCollisionX(), y2 = creature.getCollisionY();
double r1 = 150, r2 = 150;
double dx = x1 - x2;
double dy = y1 - y2;
double d = Math.sqrt(dx * dx + dy * dy);
if(d <= r1 + r2){
person.addContact(creature);
}
return false;
}
/**
* Returns the tile that the sprite has collided with.
*/
public Point getTileCollision(Creature sprite, float newX, float newY){
float fromX = Math.min(sprite.getCollisionX(), newX);
float fromY = Math.min(sprite.getCollisionY(), newY);
float toX = Math.max(sprite.getCollisionX(), newX);
float toY = Math.max(sprite.getCollisionY(), newY);
// get the tile locations
int fromTileX = TileMapRenderer.pixelsToTiles(fromX);
int fromTileY = TileMapRenderer.pixelsToTiles(fromY);
int toTileX = TileMapRenderer.pixelsToTiles(toX + sprite.getCollisionWidth() - 1);
int toTileY = TileMapRenderer.pixelsToTiles(toY + sprite.getCollisionHeight() - 1);
// check each tile for a collision
for (int x=fromTileX; x<=toTileX; x++) {
for (int y=fromTileY; y<=toTileY; y++) {
if (x < 0 || x >= map.getWidth() || map.getTile(x, y) != null){
// collision found, return the tile
pointCache.setLocation(x, y);
return pointCache;
}
}
}
// no collision found
return null;
}
}