package entities;
import gamestates.InGame;
import interfaces.Collidable;
import interfaces.Updatable;
import java.awt.Image;
import java.util.ArrayList;
import core.Renderer;
import core.Sprite;
import core.Tilemap;
/**
* Abstrakte Oberklasse für die dynamische Weltobjekte, die sich über der Tilemap befinden
*
* @author Sven Lennartz
*
*/
public abstract class Entity extends Sprite implements Updatable, Runnable {
// Zustände der Entity
public boolean collidesX, collidesY, grounded, jumping, moving, step, dead, active;
// Zähler für die Sprungdauer
private int jumpCounter;
// Zähler für die animation
private final int animationTime = 8;
private int animationCounter = animationTime;
// Variable zum zum berechnen der Framerate
private long cycleTime;
/**
* Array, welches die Images enthält, die ein Sprite benötigt.
* Also für Tiles nur eines,
* für z.B. den Spieler alle Bilder der Lauf-Animation etc
*/
private Image[] images;
/**
* Konstruktor, muss von jeder Art Entity aufgerufen werden
* und leitet die Parameter an die Sprite-Klasse weiter
*
* @param images Grafiken die der jeweilige Untertyp benötigt
* @param hitboxWidth Breite des Kollisionsbereichs
* @param hitboxHeight Höhe des Kollisionsbereichs
*
* @see Sprite
*/
public Entity(Image[] images, int hitboxWidth, int hitboxHeight, boolean blocked) {
super(images[0], hitboxWidth, hitboxHeight, blocked);
this.images = images;
} //ende Konstruktor
/**
* Der Thread-Durchlauf
*/
public void run() {
while(!dead) {
// Startzeit des Loops setzen
cycleTime = System.currentTimeMillis();
if (active) {
update();
checkCollision();
}
// Maximaldauer auf die Startzeit addieren und Differenz mit der aktuellen Zeit berechnen
cycleTime = cycleTime + 20;
long diff = cycleTime - System.currentTimeMillis();
// Differenz > 0 warten
try {
Thread.sleep(Math.max(0, diff));
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
} //ende run()
/* (non-Javadoc)
* @see core.Updatable#update()
*/
public void update() {
animate();
updateLocation();
// Sprunglogik
if (jumping)
if (jumpCounter > 0) {
getHitbox().newY -= 4;
--jumpCounter;
}
else {
jumping = false;
}
// Pseudo Gravitation
if (!(jumping || grounded))
getHitbox().newY += 8;
} //ende update()
/**
* Bewegung der Entities
*/
private void updateLocation() {
// Gestürzt
if (getHitbox().y > Renderer.getInstance().getHeight())
die();
if (collidesX)
getHitbox().newX = getHitbox().x;
else
getHitbox().x = getHitbox().newX;
if (collidesY)
getHitbox().newY = getHitbox().y;
else
getHitbox().y = getHitbox().newY;
}
/**
* Animation während Bewegung
*/
private void animate() {
if (jumping) {
setCurrentImage(images[1]);
animationCounter = animationTime;
step = false;
}
else if(grounded && moving) {
--animationCounter;
if (animationCounter == 0) {
if(images.length > 1 && !step) {
setCurrentImage(images[1]);
step = true;
}
else {
setCurrentImage(images[0]);
step = false;
}
animationCounter = animationTime;
}
}
else {
setCurrentImage(images[0]);
animationCounter = animationTime;
step = false;
}
moving = false;
}
/**
* Setzt diese Entity auf ein (Boden-)Objekt fest
*
* @param other Das Objekt auf das man gesetzt wird
*/
public void ground(Collidable other) {
getHitbox().y = other.getHitbox().y - getHitbox().height;
grounded = true;
}
/**
* Methode für die Sterbelogik
*/
public void jump(int jumpCounter) {
this.jumpCounter = jumpCounter * 2;
jumping = true;
}
/**
* Methode für die Sterbelogik
*/
public abstract void die();
/**
* Alle benötigten Kollisionsabfragen
*/
private void checkCollision() {
collidesX = false;
collidesY = false;
grounded = false;
Tilemap tm = Tilemap.getInstance();
// Kollision des Akteurs mit der Tilemap
// Tile links oben
int x = getHitbox().newX;
int y = getHitbox().newY;
Collidable tile = tm.getTilefromCoord(x, y);
synchronized (tile) {
tile.getHitbox().setLocation(x - x % tm.getTilesizeX(), y - y % tm.getTilesizeY());
if (tile.isBlocked()) {
tile.handleCollisionWith(this);
}
}
// Tile rechts oben
x = getHitbox().newX + getHitbox().width - 1;
y = getHitbox().newY;
tile = tm.getTilefromCoord(x, y);
synchronized (tile) {
tile.getHitbox().setLocation(x - x % tm.getTilesizeX(), y - y % tm.getTilesizeY());
if (tile.isBlocked()) {
tile.handleCollisionWith(this);
}
}
// Tile links
x = getHitbox().newX;
y = getHitbox().newY + getHitbox().height / 2;
tile = tm.getTilefromCoord(x, y);
synchronized (tile) {
tile.getHitbox().setLocation(x - x % tm.getTilesizeX(), y - y % tm.getTilesizeY());
if (tile.isBlocked()) {
tile.handleCollisionWith(this);
}
}
// Tile rechts
x = getHitbox().newX + getHitbox().width - 1;
y = getHitbox().newY + getHitbox().height / 2;
tile = tm.getTilefromCoord(x, y);
synchronized (tile) {
tile.getHitbox().setLocation(x - x % tm.getTilesizeX(), y - y % tm.getTilesizeY());
if (tile.isBlocked()) {
tile.handleCollisionWith(this);
}
}
// Tile links unten
x = getHitbox().newX;
y = getHitbox().newY + getHitbox().height;
tile = tm.getTilefromCoord(x, y);
synchronized (tile) {
tile.getHitbox().setLocation(x - x % tm.getTilesizeX(), y - y % tm.getTilesizeY());
if (tile.isBlocked()) {
tile.handleCollisionWith(this);
}
}
// Tile rechts unten
x = getHitbox().newX + getHitbox().width - 1;
y = getHitbox().newY + getHitbox().height;
tile = tm.getTilefromCoord(x, y);
synchronized (tile) {
tile.getHitbox().setLocation(x - x % tm.getTilesizeX(), y - y % tm.getTilesizeY());
if (tile.isBlocked()) {
tile.handleCollisionWith(this);
}
}
ArrayList<Entity> updatelist = InGame.getInstance().getUpdateList();
ArrayList<Entity> localupdatelist = new ArrayList<Entity>();
synchronized (updatelist) {
localupdatelist.addAll(updatelist);
}
// Wenn zwei Akteure kollidieren wird die Kollisionsbehandlung beider ausgeführt
for (Entity other : localupdatelist) {
if (other != this && isCollidingWith(other, true)) {
other.handleCollisionWith(this);
}
}
}
}