/*
* Engine Alpha ist eine anfängerorientierte 2D-Gaming Engine.
*
* Copyright (c) 2011 - 2014 Michael Andonie and contributors.
*
* This program 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
* any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ea;
import ea.internal.collision.BoxCollider;
import ea.internal.collision.Collider;
import ea.internal.collision.NullCollider;
import ea.internal.gui.Fenster;
import ea.internal.phy.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.Serializable;
import java.util.Locale;
/**
* Raum bezeichnet alles, was sich auf der Zeichenebene befindet.<br /> Dies ist die absolute
* Superklasse aller grafischen Objekte. Umgekehrt kann somit jedes grafische Objekt die folgenden
* Methoden nutzen.
*
* @author Michael Andonie, Niklas Keller
*/
public abstract class Raum implements Serializable, Comparable<Raum> {
/**
* Ein einfacher Farbzyklus, der fuer die Leucht-Animationen genommen wird
*/
public static final Color[] farbzyklus = {Color.white, Color.blue, Color.red, Color.yellow, Color.magenta, Color.cyan, Color.green, Color.orange,};
/**
* Die Serialisierungs-Konstante dieser Klasse. <b>In keiner Weise fuer die Programmierung mit
* der Engine bedeutsam!</b>
*/
private static final long serialVersionUID = 98L;
/**
* Der Leuchtmacher fuer alle Raum-Objekte
*/
private static final LeuchtMacher macher = new LeuchtMacher();
/**
* Der Animations-Manager, über den alle Animationen laufen.<br /> Wird zum Löschen aller
* Referenzen auf dieses Objekt verwendet.
*/
private static final AnimationsManager animationsManager = AnimationsManager.getAnimationsManager();
/**
* Ob die Kollisionstests Roh oder fein ablaufen sollen.
*/
protected static boolean roh = false;
/**
* Die absolute Position des Raum-Objekts. Die Interpretation dieses Parameters hängt von den
* sich <b>ableitenden</b> Klassen ab. Er kann komplett irrelevant sein (Knoten), oder - im
* Regelfall - die linke obere Ecke des Objektes bezeichnen. Default
*/
protected Punkt position = Punkt.ZENTRUM;
/**
* Gibt an, ob das Objekt zur Zeit ueberhaupt sichtbar sein soll.<br /> Ist dies nicht der Fall,
* so wird die Zeichenroutine direkt uebergangen.
*/
private boolean sichtbar = true;
/**
* Gibt an, ob dieses Objekt mit Verzug ungleich von 0 gezeichnet wuerde. In diesem Fall wird es
* als statisch betrachtet. Ob dies tatsaechlich der Fall ist, ist irrelevant.
*/
private boolean statisch = false;
/**
* Der Physik-Client, der die Physik dieses Raum-Objekts regelt.
*/
private PhysikClient phClient = new NullClient(this);
/**
* Der aktuelle Collider dieses Raum-Objekts.
*/
private Collider collider = NullCollider.getInstance();
/**
* Z-Index des Raumes, je höher, desto weiter oben wird der Raum gezeichnet
*/
private int zIndex = 1;
/**
* Drehung des Objekts in Grad
*/
private double drehung;
/**
* Opacity = Durchsichtigkeit des Raumes
* <p/>
* <ul><li><code>0.0f</code> entspricht einem komplett durchsichtigen Bild.</li>
* <li><code>1.0f</code> entspricht einem undurchsichtigem Bild.</li></ul>
*/
private float opacity = 1;
/**
* Composite des Grafik-Objekts. Zwischenspeicherung des letzten Zustands
*/
private Composite composite;
/**
* Transofrm des Grafik-Objekts. Zwischenspeicherung des letzten Zustands
*/
private AffineTransform transform;
/**
* Setzt, ob sämtliche Kollisionstests in der Engine Alpha grob oder fein sein sollen.
*
* @param heavy
* Ist dieser Wert <code>true</code>, werden intern Kollisionstests genauer, aber
* rechenintensiver. Ist er <code>false</code>, werden diese Kollisionstests schneller, aber
* ungenauer.
*
* @see Game#rechenintensiveArbeitSetzen(boolean)
*/
public static void heavyComputingSetzen (boolean heavy) {
roh = heavy;
}
/**
* Diese Methode ordnet einem String ein Color-Objekt zu.<br /> Hierdurch ist in den Klassen
* außerhalb der Engine keine awt-Klasse nötig.
*
* @param t
* Der Name der Farbe.<br /> Ein Katalog mit allen moeglichen Namen findet sich im
* <b>Handbuch</b>
*
* @return Das Farbobjekt zum String; ist Color.black bei unzuordnembaren String
*/
public static Color zuFarbeKonvertieren (String t) {
Color c;
switch (t.toLowerCase(Locale.GERMAN)) {
case "gelb":
c = Color.yellow;
break;
case "weiss":
case "weiß":
c = Color.white;
break;
case "orange":
c = Color.orange;
break;
case "grau":
c = Color.gray;
break;
case "gruen":
case "grün":
c = Color.green;
break;
case "blau":
c = Color.blue;
break;
case "rot":
c = Color.red;
break;
case "pink":
c = Color.pink;
break;
case "magenta":
case "lila":
c = Color.magenta;
break;
case "cyan":
case "tuerkis":
case "türkis":
c = Color.cyan;
break;
case "dunkelgrau":
c = Color.darkGray;
break;
case "hellgrau":
c = Color.lightGray;
break;
case "braun":
c = new Color(110,68,14);
break;
default:
c = Color.black;
break;
}
return DateiManager.ausListe(c);
}
/**
* Erstellt eine Halbdurchsichtige Farbe mit den selben RGB-Werten, wie die eingegebene.<br />
* Diese Methode wird intern verwendet.
*
* @param c
* Die Farbe, deren im Alphawert gesenkte Instanz erstellt werden soll.
*/
public static final Color halbesAlpha (Color c) {
return DateiManager.ausListe(new Color(c.getRed(), c.getGreen(), c.getBlue(), 178));
}
/**
* Interne Testmethode, die ein mathematisch simples Konzept hat.<br /> Es gibt kein Problem,
* wenn die Zahlen das selbe Vorzeichen haben oder wenn eine der beiden Zahlen gleich 0 ist.
*
* @return <code>true</code>, falls diese Zahlenkonstellation ein Problem ist, sonst
* <code>false</code>.
*/
protected static boolean problem (int z1, int z2) {
if (z1 == 0 || z2 == 0) {
return false;
}
return (z1 < 0 ^ z2 < 0);
}
/**
* Setzt den Z-Index dieses Raumes. Je größer, desto weiter vorne wird ein Raum gezeichnet.
* <b>Diese Methode muss ausgeführt werden, bevor der Raum zu einem Knoten hinzugefügt
* wird.</b>
*
* @param z
* zu setzender Index
*/
public void zIndex (int z) {
zIndex = z;
}
/**
* Macht dieses <code>Raum</code>-Objekt fuer die Physik zu einem <i>Neutralen</i> Objekt, also
* einem Objekt das per se nicht an der Physik teilnimmt.
*/
public void neutralMachen () {
phClient.aufloesen();
phClient = new NullClient(this);
}
/**
* Macht dieses Objekt zu einem Passiv-Objekt. <br /> Ab dem Aufruf dieser Methode verhaelt es
* sich als Boden-/Wand- bzw. Deckenelement und haelt Aktiv-Objekte auf.
*/
public void passivMachen () {
phClient.aufloesen();
phClient = new Passivator(this);
}
/**
* Macht dieses Objekt zu einem Aktiv-Objekt.<br /> Ab dem Aufruf dieser Methode laesst es sich
* von Passiv-Objekten aufhalten und wird - solange dies nicht ueber den Methodenaufruf
* <code>schwerkraftAktivSetzen(false)</code> deaktiviert wird - von einer kuenstlichen
* Schwerkraft angezogen.
*
* @see #schwerkraftAktivSetzen(boolean)
*/
public void aktivMachen () {
phClient.aufloesen();
phClient = new Gravitator(this);
}
/**
* TODO: Dokumentation
*/
public void newtonschMachen () {
phClient.aufloesen();
phClient = new MechanikClient(this);
}
/**
* Laesst das <code>Raum</code>-Objekt einen Sprung von variabler Kraft machen. Dies
* funktioniert jedoch nur dann, wenn das Objekt auch ein <i>Aktiv-Objekt</i> ist. Ansonsten ist
* wird hier eine Fehlermeldung ausgegeben.
*
* @param kraft
* Die Kraft dieses Sprunges. Je hoeher dieser Wert, desto hoeher der Sprung.
*
* @return <code>true</code>, wenn das <code>Raum</code>-Objekt erfolgreich springen konnte.
* <code>false</code>, wenn das <code>Raum</code>-Objekt <b>nicht</b> springen konnte.<br />
* Zweiteres ist automatisch immer dann der Fall, wenn<br /> - das <code>Raum</code>-Objekt
* <b>kein Aktiv-Objekt mit aktivierter Schwerkraft (Standard)</b> ist oder <br /> - das
* <code>Raum</code>-Objekt als Aktiv-Objekt <b>nicht auf einem Passiv-Objekt</b> steht.
*/
public boolean sprung (int kraft) {
return phClient.sprung(kraft);
}
/**
* Setzt, ob dieses <code>Raum</code>-Objekt von Schwerkraft beeinflusst wird. Macht nur dann
* Sinn, wenn das Objekt, an dem diese Methode ausgefuehrt wird, ein Aktiv-Objekt ist.
*
* @param aktiv
* <code>true</code>, wenn Schwerkraft aktiv sein soll, sonst <code>false</code>.
*
* @see #aktivMachen()
*/
public void schwerkraftAktivSetzen (boolean aktiv) {
phClient.schwerkraftAktivSetzen(aktiv);
}
/**
* Setzt die Schwerkraft fuer dieses spezielle Objekt.<br /> <b>Achtung:</b> Standardwert: 4<br
* /> Groesserer Wert = langsamer Fallen<br /> Kleinerer Wert = schneller Fallen <br />
* Negativer Wert : Moege Gott uns allen gnaedig sein...
*
* @param schwerkraft
* Der Wert fuer die Schwerkraft der Physik.<br /> <b>Wichtig:</b> Dies repraesentiert
* <i>keinen</i> Wert fuer die (Erd-) Beschleunigungszahl "g" aus der Physik. Schon allein
* deshalb, weil die Zahl umgekehrt wirkt (s. oben).
*
* @see ea.Raum#aktivMachen()
*/
public void schwerkraftSetzen (int schwerkraft) {
this.phClient.schwerkraftSetzen(schwerkraft);
}
/**
* Meldet einen <code>FallReagierbar</code>-Listener an.
* <p/>
* Dieser wird ab sofort immer dann informiert, wenn dieses <code>Raum</code>-Objekt unter eine
* bestimmte Höhe faellt. Diese wird als <b>kritische Tiefe</b> bezeichnet. Der Listener wird ab
* diesem Zeitpunkt <i>dauerhaft aufgerufen, solange das Objekt unterhalb dieser Toleranzgrenze
* ist</i>. Deshalb sollte in der implementierten Reaktionsmethode des
* <code>FallReagierbar</code>-Interfaces die Höhe so neu gesetzt werden, dass das
* <code>Raum</code>-Objekt nicht mehr unterhalb der <b>kritischen Tiefe</b> ist.
* <p/>
* <b>ACHTUNG!</b>
* <p/>
* Jedes <code>Raum</code>-Objekt hat <b>HÖCHSTENS</b> einen <code>FallReagierbar</code>-Listener.
* Das bedeutet, dass es <b>nicht möglich ist, dass mehrere <code>FallReagierbar</code>-Listener
* über ein Objekt informiert werden</b>.
* <p/>
* Die <b>kritische Tiefe</b> jedoch lässt sich problemlos immer wieder neu setzen, über die
* Methode <code>kritischeTiefeSetzen(int tiefe)</code>.
* <p/>
* Diese Methode mach natürlich nur Sinn, wenn sie an einem <i>Aktiv-Objekt</i> ausgeführt wird.
* Andernfalls gibt es eine Fehlermeldung!
*
* @param f
* Das anzumeldende <code>FallReagierbar</code>
* @param kritischeTiefe
* Die Tiefe ab der der Listener <i>dauerhaft</i> durch den Aufruf seiner Reaktionsmethode
* informiert wird, solange das <code>Raum</code>-Objekt hierunter ist.
*
* @see FallReagierbar
* @see #kritischeTiefeSetzen(int)
*/
public void fallReagierbarAnmelden (FallReagierbar f, int kritischeTiefe) {
phClient.fallReagierbarAnmelden(f, kritischeTiefe);
}
/**
* Setzt die <b>kritische Tiefe</b> neu. Ab dieser Tiefe wird der <code>FallReagierbar</code>-Listener
* dieses <code>Raum</code>-Objektes aufgerufen - dauerhaft so lange, bis das
* <code>Raum</code>-Objekt <b>nicht mehr unterhalb dieser Tiefe ist</b>.
*
* @param tiefe
* Die neue kritische Tiefe. Die Tiefe ab der der Listener <i>dauerhaft</i> durch den Aufruf
* seiner Reaktionsmethode informiert wird, solange das <code>Raum</code>-Objekt hierunter
* ist.
*
* @see FallReagierbar
* @see #fallReagierbarAnmelden(FallReagierbar, int)
*/
public void kritischeTiefeSetzen (int tiefe) {
phClient.kritischeTiefeSetzen(tiefe);
}
/**
* Diese Methode meldet einen <code>StehReagierbar</code>-Listener neu an.<br /> Dieser wird
* nach der Anmeldung immer dann <i>einmalig</i> durch den Aufruf seiner
* <code>stehReagieren()</code>-Methode informiert, wenn dieses <code>Raum</code>-Objekt nach
* dem Fall/Sprung wieder auf einem Passiv-Objekt zu stehen kommt.<br /> <br />
* <b>ACHTUNG!</b><br /> Ein <code>Raum</code>-Objekt kann <b>hoechstens einen
* <code>StehReagierbar</code>-Listener besitzen</b>!<br /> <br /> Diese Methode mach natuerlich
* nur Sinn, wenn sie an einem <i>Aktiv-Objekt</i> ausgefuehrt wird. Andernfalls gibt es eine
* Fehlermeldung!
*
* @param s
* Der <code>StehReagierbar</code>-Listener, der ab sofort bei jedem neuen zum Stehen kommen
* dieses <code>Raum</code>-Objekts informiert wird.
*
* @see ea.StehReagierbar
*/
public void stehReagierbarAnmelden (StehReagierbar s) {
phClient.stehReagierbarAnmelden(s);
}
/**
* Prueft, ob dieses Objekt als <i>Aktiv-Objekt</i> steht.<br /> Diese Methode steht nicht in
* direktem Zusammenhang mit dem Interface <code>StehReagierbar</code>, denn durch diese Methode
* laesst sich zu jedem beliebigen Zeitpunkt erfragen, ob das <code>Raum</code>-Objekt steht,
* nicht jedoch - wie durch <code>StehReagierbar</code> - am genauen Zeitpunkt des zum Stehen
* kommens hierauf reagieren.<br /> <br /> Diese Methode macht natuerlich nur dann sinn, wenn
* sie an einem <i>Aktiv-Objekt</i> ausgefuehrt wird. Andernfalls gibt es eine Fehlermeldung!
*
* @return <code>true</code>, wenn dieses <code>Raum</code>-Objekt als <i>Aktiv-Objekt</i> auf
* einem Passiv-Objekt steht. Steht dieses <code>Raum</code>-Objekt als <i>Aktiv-Objekt</i>
* nicht auf einem Passiv-Objekt, oder ist dieses <code>Raum</code>-Objekt kein
* <i>Aktiv-Objekt</i>, so ist die Rueckgabe <code>false</code>.
*/
public boolean steht () {
return phClient.steht();
}
/**
* <b>Bewegt</b> dieses <code>Raum</code>-Objekt. Der Unterschied zum <b>Verschieben</b> ist
* folgender:<br /> Ist dieses Objekt in der Physik beteiligt, so ist dies eine Bewegung
* innerhalb der Physik und kein Stumpfes Verschieben.<br /> Ist dieses Objekt fuer die Physik
* neutral ist dies genauso wie <code>verschieben</code>.
*
* @param v
* Die Bewegung beschreibender Vektor
*
* @return <code>true</code>, wenn sich dieses <code>Raum</code>-Objekt ohne Probleme bewegen
* liess. Konnte es wegen der Physik (Aktiv-Objekt von Passiv-Objekt geblockt) <b>nicht
* vollstaendig verschoben werden</b>, so wird <code>false</code> zurueckgegeben.<br /> Die
* Rueckgabe ist bei Passiv-Objekten und neutralen Objekten immer <code>true</code>, da diese
* Problemlos verschoben werden können.
*
* @see #bewegen(float, float)
* @see #verschieben(Vektor)
* @see #verschieben(float, float)
*/
public boolean bewegen (Vektor v) {
synchronized (this) {
return phClient.bewegen(v);
}
}
/**
* <b>Bewegt</b> dieses <code>Raum</code>-Objekt. Der Unterschied zum <b>Verschieben</b> ist
* folgender:<br /> Ist dieses Objekt in der Physik beteiligt, so ist dies eine Bewegung
* innerhalb der Physik und kein Stumpfes Verschieben.<br /> Ist dieses Objekt fuer die Physik
* neutral ist dies genauso wie <code>verschieben</code>.
*
* @param dX
* Der X-Anteil der Verschiebung (Delta-X)
* @param dY
* Der Y-Anteil der Verschiebung (Delta-Y)
*
* @see #bewegen(Vektor)
* @see #verschieben(Vektor)
* @see #verschieben(float, float)
*/
public void bewegen (float dX, float dY) {
phClient.bewegen(new Vektor(dX, dY));
}
/**
* Setzt die Meter pro Pixel für die Zeichenebene. Dies ist das <i>dynamische Bindeglied</i>
* zwischen der <b>physikalisch möglichst korrekten Berechnung innerhalb der Engine</b> sowie
* der <b>freien Wählbarkeit der Zeichenebene</b>.
*
* @param mpp
* Die Anzahl an Metern, die auf einen Pixel fallen.<br/> Beispiele:<br /> <ul>
* <li><code>10(.0f)</code> => Auf einen Pixel fallen <b>10</b> Meter. => Ein Meter = 0,1
* Pixel</li> <li><code>0.1f</code> => Auf einen Pixel fallen <b>0,1</b> Meter. => Ein Meter =
* 10 Pixel</li> </ul>
*
* @see #newtonschMachen()
*/
public void setzeMeterProPixel (float mpp) {
ea.internal.phy.MechanikClient.setzeMeterProPixel(mpp);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Wirkt einen Impuls auf das <code>Raum</code>-Objekt aus. Dieser ändert - abhängig von seiner
* Richtung, Intensität sowie von der <i>Mass</i> des </code>Raum</code>-Objekts eine
* Geschwindigkeitsänderung.
*
* @param impuls
* Der Impuls, der diesem <code>Raum</code>-Objekt zugeführt werden soll.<br />
* <b>WICHTIG:</b> Die Einheiten für physikalische Größen innerhalb der Engine entsprechen
* denen aus der klassischen Mechanik. Die Einheit für Impuls ist [kg * (m / s)]
*
* @see #masseSetzen(float)
* @see #konstanteKraftSetzen(Vektor)
* @see #setzeMeterProPixel(float)
* @see #newtonschMachen()
*/
public void impulsHinzunehmen (Vektor impuls) {
phClient.impulsHinzunehmen(impuls);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Addiert <b>hart</b> (also ohne Rücksicht auf das Gewicht des Objekts) eine neue Geschwindigkeit
* auf die aktuelle Geschwindigkeit dieses <code>Raum</code>-Objektes. Die neue Geschwidig
*
* @param geschwindigkeit
* die Geschwindigkeit, die zu der aktuellen Geschwindigkeit von diesem <code>Raum</code>-Objekt.
* hinzuaddiert werden soll. Die neue Geschwindigkeit ist damit <code>v1 + v2</code>. <br />
* <b>WICHTIG:</b> Die Einheiten für physikalische Größen innerhalb der Engine entsprechen
* denen aus der klassischen Mechanik. Die Einheit für Geschwindigkeit ist [m / s]
*
* @see #masseSetzen(float)
* @see #konstanteKraftSetzen(Vektor)
* @see #setzeMeterProPixel(float)
* @see #luftwiderstandskoeffizientSetzen(float)
* @see #newtonschMachen()
*/
public void geschwindigkeitHinzunehmen (Vektor geschwindigkeit) {
phClient.geschwindigkeitHinzunehmen(geschwindigkeit);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Gibt den Luftwiderstandskoeffizienten dieses <code>Raum-Objektes</code> aus.
*
* @see #luftwiderstandskoeffizientSetzen(float)
* @see #newtonschMachen()
*/
public float luftwiderstandskoeffizient () {
return phClient.getLuftwiderstandskoeffizient();
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Gibt aus, ob dieses <code>Raum</code>-Objekt beeinflussbar, also durch Impulse beweglich ist.
* Was das heisst, kannst Du in der Setter-Methode nachlesen.
*
* @return <code>true</code>, falls dieses <code>Raum</code>-Objekt beeinflussbar ist, sonst
* <code>false</code>.
*
* @see #beeinflussbarSetzen(boolean)
* @see #newtonschMachen()
*/
public boolean istBeeinflussbar () {
return phClient.istBeeinflussbar();
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Gibt aus die Masse dieses <code>Raum</code>-Objektes aus. Diese ist relevant
* Impulsrechnungen, z.B. wenn 2 Objekte kollidieren.
*
* @return die Masse dieses <code>Raum</code>-Objektes in korrekter Einheit. <b>WICHTIG:</b> Die
* Einheiten für physikalische Größen innerhalb der Engine entsprechen denen aus der klassischen
* Mechanik. Die Einheit für Masse ist [kg]
*
* @see #masseSetzen(float)
* @see #newtonschMachen()
*/
public float getMasse () {
return phClient.getMasse();
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Gibt aus die Kraft aus, die auf dieses <code>Raum</code>-Objekt dauerhaft wirkt. So lässt
* sich z.B. eine dynamische Schwerkraft realisieren.
*
* @return die Kraft, die auf dieses <code>Raum</code>-Objektes konstant wirkt. <b>WICHTIG:</b>
* Die Einheiten für physikalische Größen innerhalb der Engine entsprechen denen aus der
* klassischen Mechanik. Die Einheit für Kraft ist [N] = [kg * (m / s^2)]
*
* @see #beeinflussbarSetzen(boolean)
* @see #newtonschMachen()
*/
public Vektor getForce () {
return phClient.getForce();
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Setzt den Luftwiderstandskoeffizienten für dieses <code>Raum</code>-Objekt. Je größer dieser
* Wert ist, desto stärker ist der Luftwiderstand auf das <code>Raum-Objekt</code>.<br /> Der
* Luftwiderstand <b>nicht</b> über die vollständige Luftwiderstandsformel (u.a. mit
* Querschnittsfläche des Körpers) berechnet. Der Luftwiderstand berechnet sich
* <b>ausschließlich aus der Geschwindigkeit und dieses Luftwiderstandskoeffizienten</b>:<br />
* <code> (F_w = luftwiderstandskoeffizient * v^2)</code>
*
* @param luftwiderstandskoeffizient
* Der Luftwiderstandskoeffizient, der für dieses <code>Raum</code>-Objekt gelten soll. Ist
* dieser Wert <code>0</code>, so wirkt kein Luftwiderstand auf das Objekt.
*
* @see #luftwiderstandskoeffizient()
* @see #newtonschMachen()
*/
public void luftwiderstandskoeffizientSetzen (float luftwiderstandskoeffizient) {
phClient.luftwiderstandskoeffizientSetzen(luftwiderstandskoeffizient);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Setzt, ob dieses <code>Raum</code>-Objekt <i>beeinflussbar</i> sein soll für Impulse von
* anderen Objekten, die mit diesem Kollidieren. Ist es <b>nicht beeinflussbar</b>, so prallen
* (beeinflussbare) Objekte einfach an ihm ab. Typische unbeeinflussbare Objekte sind:<br />
* <ul> <li>Böden</li><li>Wände</li><li>Decken</li><li>bewegliche Plattformen</li> </ul><br />
* Ist ein <code>Raum</code>-Objekt <b>beeinflussbar</b>, so kann es an anderen Objekten
* abprallen bzw. von ihnen blockiert werden. Es kann sie nicht verschieben. Typische
* beeinflussbare Objekte sind: <br /> <ul> <li>Spielfiguren</li> </ul><br />
* <p/>
* Diese Eigenschaft kann beliebig oft durchgewechselt werden.
*
* @param beeinflussbar
* ist dieser Wert <code>true</code>, so ist dieses Objekt ab sofort <i>beeinflussbar</i>.
* Sonst ist es ab sofort <i>nicht beeinflussbar</i>.
*
* @see #istBeeinflussbar()
* @see #newtonschMachen()
*/
public void beeinflussbarSetzen (boolean beeinflussbar) {
phClient.beeinflussbarSetzen(beeinflussbar);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Setzt die Masse für dieses <code>Raum</code>-Objekt. Es hat ab sofort diese Masse. Diese hat
* Auswirkungen auf Impulsrechnung und die Dynamik dieses Objekts..
*
* @param masse
* die Mass, die dieses <code>Raum</code>-Objekt ab sofort haben soll. <b>WICHTIG:</b> Die
* Einheiten für physikalische Größen innerhalb der Engine entsprechen denen aus der
* klassischen Mechanik. Die Einheit für Masse ist [kg]
*
* @see #getMasse()
* @see #newtonschMachen()
*/
public void masseSetzen (float masse) {
phClient.masseSetzen(masse);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Setzt die Kraft, die auf dieses <code>Raum</code>-Objekt dauerhaft wirken soll. So lässt sich
* z.B. eine dynamische Schwerkraft realisieren:<br /> Die Schwerkraft, wäre eine Kraft, die
* dauerhaft nach unten wirkt, also zum Beispiel: <br /><code> Kreis ball = ...<br /> [...] <br
* /> ball.kraftSetzen(new Vektor(0,9.81)); // Setze eine Schwerkraft mit 9,81 kg * m/s^2
* </code>
*
* @param kraft
* die Kraft, die auf dieses <code>Raum</code>-Objekt konstant wirken soll. <b>WICHTIG:</b>
* Die Einheiten für physikalische Größen innerhalb der Engine entsprechen denen aus der
* klassischen Mechanik. Die Einheit für Kraft ist [N] = [kg * (m / s^2)]
*
* @see #getForce()
* @see #newtonschMachen()
*/
public void konstanteKraftSetzen (Vektor kraft) {
phClient.kraftSetzen(kraft);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Setzt die Geschwindigkeit, die dieses <code>Raum</code>-Objekt haben soll.
*
* @param geschwindigkeit
* die Geschwindikeit, die auf dieses <code>Raum</code>-Objekt mit sofortiger Wirkung annehmen
* soll. <b>WICHTIG:</b> Die Einheiten für physikalische Größen innerhalb der Engine
* entsprechen denen aus der klassischen Mechanik. Die Einheit für Geschwindigkeit ist [m /
* s]
*
* @see #newtonschMachen()
*/
public void geschwindigkeitSetzen (Vektor geschwindigkeit) {
phClient.geschwindigkeitSetzen(geschwindigkeit);
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Setzt alle Einflüsse auf dieses <code>Raum</code>-Objekt zurück. Dies bedeutet: * die auf
* dieses Objekt einwirkende, konstante Kraft wird 0. * die Geschwindigkeit dieses Objekts wird
* 0.
*
* @see #newtonschMachen()
*/
public void einfluesseZuruecksetzen () {
phClient.einfluesseZuruecksetzen();
}
/**
* <b>Physik-Methode</b> - funktioniert nur bei <i>Newton'schen Raum-Objekten</i>
* <p/>
* Setzt einen neuen <i>Impuls</i> auf dieses <code>Raum</code>-Objekt, indem eine bestimmte
* <i>Kraft</i> für eine bestimmte <i>Zeit</i> auf dieses Objekt wirkt.
* <p/>
* Es gilt für <b>ausreichend kleines <code>t</code></b>: <code>p = F * t</code>
* <p/>
* Dies ist die grundlegende Berechnung für den Impuls.
*
* @param kraft
* Eine Kraft, die (modellhaft) auf dieses <code>Raum</code>-Objekt wirken soll.
* <b>WICHTIG:</b> Die Einheiten für physikalische Größen innerhalb der Engine entsprechen
* denen aus der klassischen Mechanik. Die Einheit für Kraft ist <code>[N] = [kg * (m /
* s^2)]</code>
* @param t_kraftuebertrag
* Die Zeit, über die die obige Kraft auf dieses <code>Raum</code>-Objekt wirken soll.
* <b>WICHTIG:</b> Die Einheiten für physikalische Größen innerhalb der Engine entsprechen
* denen aus der klassischen Mechanik. Die Einheit für Zeit ist [s]
*
* @see #newtonschMachen()
*/
public void kraftAnwenden (Vektor kraft, float t_kraftuebertrag) {
phClient.kraftAnwenden(kraft, t_kraftuebertrag);
}
/**
* Setzt die Sichtbarkeit des Objektes.
*
* @param sichtbar
* Ob das Objekt sichtbar sein soll oder nicht.<br /> Ist dieser Wert <code>false</code>, so
* wird es nicht im Fenster gezeichnet.<br /> <b>Aber:</b> Es existiert weiterhin ohne
* Einschraenkungen. <b>Allerdings</b> gilt ein Treffer mit einem unsichtbaren Raum-Objekt in
* der Klasse <code>Physik</code> nicht als Kollision. Unsichtbare Raum-Objekte werden somit
* bei Trefferkollisionen ausgelassen.
*
* @see #sichtbar()
* @see Physik
*/
public final void sichtbarSetzen (boolean sichtbar) {
this.sichtbar = sichtbar;
}
/**
* Gibt an, ob das Raum-Objekt sichtbar ist.
*
* @return Ist <code>true</code>, wenn das Raum-Objekt zur Zeit sichtbar ist.
*
* @see #sichtbarSetzen(boolean)
*/
public final boolean sichtbar () {
return this.sichtbar;
}
/**
* Meldet ein Leuchtend-Objekt an dem vorgesehenen LeuchtErsteller Objekt an.<br /> Diese
* Methode ist dafür vorgesehen, dass sie <b>nur im Konstruktor der dieses Interface
* implementierenden Instanz aufgerufen wird</b>, und zwar mit dem <code>this</code>-Pointer,
* sprich:<br /> :<code>super.leuchterAnmelden(this);</code>
* <p/>
* Prinzipiell sollte diese Methode nur innerhalb der Engine aufgerufen werden
*
* @param l
* Der anzumeldende Leuchter
*/
protected final void leuchterAnmelden (Leuchtend l) {
macher.add(l);
}
/**
* Meldet ein Leuchtend-Objekt am vorgesehenen LeuchtMacher-Objekt ab.<br /> Prinzipiell sollte
* diese Methode nur innerhalb der Engine aufgerufen werden
*
* @param l
* Der abzumeldende Leuchter
*/
protected final void leuchterAbmelden (Leuchtend l) {
macher.entfernen(l);
}
/**
* Die Basiszeichenmethode.<br /> Sie schließt eine Fallabfrage zur Sichtbarkeit ein. Diese
* Methode wird bei den einzelnen Gliedern eines Knotens aufgerufen.
*
* @param g
* Das zeichnende Graphics-Objekt
* @param r
* Das BoundingRechteck, dass die Kameraperspektive Repraesentiert.<br /> Hierbei soll
* zunaechst getestet werden, ob das Objekt innerhalb der Kamera liegt, und erst dann
* gezeichnet werden.
*
* @see #zeichnen(Graphics2D, BoundingRechteck)
*/
public final void zeichnenBasic (Graphics2D g, BoundingRechteck r) {
statisch = (r.x == 0) && (r.y == 0);
if (sichtbar) {
zeichnen(g, r);
}
}
/**
* Zeichnet das Objekt.
*
* @param g
* Das zeichnende Graphics-Objekt
* @param r
* Das BoundingRechteck, dass die Kameraperspektive Repraesentiert.<br /> Hierbei soll
* zunaechst getestet werden, ob das Objekt innerhalb der Kamera liegt, und erst dann
* gezeichnet werden.
*/
public abstract void zeichnen (Graphics2D g, BoundingRechteck r);
/**
* Setzt die Position des Objektes gänzlich neu auf der Zeichenebene. Das Setzen ist technisch
* gesehen eine Verschiebung von der aktuellen Position an die neue. <br /><br />
* <b>Achtung!</b><br /> Bei <b>allen</b> Objekten ist die eingegebene Position die linke, obere
* Ecke des Rechtecks, das die Figur optimal umfasst. Das heißt, dass dies bei Kreisen z.B.
* <b>nicht</b> der Mittelpunkt ist! Hierfür gibt es die Sondermethode
* <code>mittelpunktSetzen(int x, int y)</code>.
*
* @param x
* neue <code>x</code>-Koordinate
* @param y
* neue <code>y</code>-Koordinate
*
* @see #positionSetzen(Punkt)
* @see #mittelpunktSetzen(int, int)
* @see #setX(float)
* @see #setY(float)
*/
public void positionSetzen (float x, float y) {
this.positionSetzen(new Punkt(x, y));
}
/**
* Setzt die Position des Objektes gänzlich neu auf der Zeichenebene. Das Setzen ist technisch
* gesehen eine Verschiebung von der aktuellen Position an die neue. <br /><br />
* <b>Achtung!</b><br /> Bei <b>allen</b> Objekten ist die eingegebene Position die linke, obere
* Ecke des Rechtecks, das die Figur optimal umfasst. Das heißt, dass dies bei Kreisen z.B.
* <b>nicht</b> der Mittelpunkt ist! Hierfür gibt es die Sondermethode
* <code>mittelpunktSetzen(int x, int y)</code>.
*
* @param p
* Der neue Zielpunkt
*
* @see #positionSetzen(float, float)
* @see #mittelpunktSetzen(int, int)
* @see #setX(float)
* @see #setY(float)
*/
public void positionSetzen (Punkt p) {
BoundingRechteck r = dimension();
verschieben(new Vektor(p.x - r.x, p.y - r.y));
}
/**
* Methode zum Beschreiben der rechteckigen Fläche, die dieses Objekt einnimmt.<br /> Diese
* Methode wird zentral für die Trefferkollisionen innerhalb der Engine benutzt und gehört zu
* den wichtigsten Methoden der Klasse und der Engine.
*
* @return Ein BoundingRechteck mit minimal nötigen Umfang, um das Objekt <b>voll
* einzuschliessen</b>.
*/
public abstract BoundingRechteck dimension ();
/**
* Verschiebt das Objekt ohne Bedingungen auf der Zeichenebene. Dies ist die <b>zentrale</b>
* Methode zum
*
* @param v
* Der Vektor, der die Verschiebung des Objekts angibt.
*
* @see Vektor
* @see #verschieben(float, float)
* @see #bewegen(Vektor)
* @see #bewegen(float, float)
*/
public void verschieben (Vektor v) {
position = position.verschobeneInstanz(v);
}
/**
* Verschiebt die Raum-Figur so, dass ihr Mittelpunkt die eingegebenen Koordinaten hat.
* <p/>
* Diese Methode arbeitet nach dem Mittelpunkt des das Objekt abdeckenden BoundingRechtecks
* durch den Aufruf der Methode <code>zentrum()</code>. Daher ist diese Methode in der Anwendung
* auf ein Knoten-Objekt nicht unbedingt sinnvoll.
*
* @param x
* Die <code>x</code>-Koordinate des neuen Mittelpunktes des Objektes
* @param y
* Die <code>y</code>-Koordinate des neuen Mittelpunktes des Objektes
*
* @see #mittelpunktSetzen(Punkt)
* @see #verschieben(Vektor)
* @see #positionSetzen(float, float)
* @see #zentrum()
*/
public void mittelpunktSetzen (int x, int y) {
this.mittelpunktSetzen(new Punkt(x, y));
}
/**
* Verschiebt die Raum-Figur so, dass ihr Mittelpunkt die eingegebenen Koordinaten hat.<br />
* Diese Methode Arbeitet nach dem Mittelpunkt des das Objekt abdeckenden BoundingRechtecks
* durch den Aufruf der Methode <code>zentrum()</code>. Daher ist diese Methode im Anwand auf
* ein Knoten-Objekt nicht unbedingt sinnvoll.<br /> Macht dasselbe wie
* <code>mittelPunktSetzen(p.x, p.y)</code>.
*
* @param p
* Der neue Mittelpunkt des Raum-Objekts
*
* @see #mittelpunktSetzen(int, int)
* @see #verschieben(Vektor)
* @see #positionSetzen(float, float)
* @see #zentrum()
*/
public void mittelpunktSetzen (Punkt p) {
this.verschieben(this.zentrum().nach(p));
} /**
* Gibt die x-Koordinate der linken oberen Ecke zurück. Sollte das Raumobjekt nicht rechteckig
* sein, so wird die Position der linken oberen Ecke des umschließenden Rechtecks genommen.
* <p/>
* TODO: Deprecate positionX() in favor of this new method?
*
* @return <code>x</code>-Koordinate
*
* @see #getY()
* @see #position()
*/
public float getX () {
return position.x;
}
/**
* Berechnet das Zentrum des Raum-Objekts als Punkt auf der Zeichenebene.
* <p/>
* Das Zentrum wird über die Methode <code>dimension()</code> berechnet, und zwar über die
* Methode des resultierenden BoundingRechtecks:<br /> <code>dimension().zentrum()</code>
*
* @return Zentrum dieses Raumobjekts
*/
public Punkt zentrum () {
return this.dimension().zentrum();
}
/**
* Gibt die Breite des Objekts zurück. Entspricht einem Aufruf von {@code
* raum.dimension().breite}.
*
* @return Breite des Objekts
*
* @see #dimension()
*/
public float getBreite () {
return dimension().breite;
} /**
* Setzt die x-Koordinate der Position des Objektes gänzlich neu auf der Zeichenebene. Das
* Setzen ist technisch gesehen eine Verschiebung von der aktuellen Position an die neue. <br
* /><br /> <b>Achtung!</b><br /> Bei <b>allen</b> Objekten ist die eingegebene Position die
* linke, obere Ecke des Rechtecks, das die Figur optimal umfasst. Das heißt, dass dies bei
* Kreisen z.B. <b>nicht</b> der Mittelpunkt ist! Hierfür gibt es die Sondermethode
* <code>mittelpunktSetzen(int x, int y)</code>.
*
* @param x
* neue <code>x</code>-Koordinate
*
* @see #positionSetzen(float, float)
* @see #mittelpunktSetzen(int, int)
* @see #setY(float)
*/
public void setX (float x) {
this.verschieben(x - getX(), 0);
}
/**
* Gibt die Höhe des Objekts zurück. Entspricht einem Aufruf von {@code
* raum.dimension().hoehe}.
*
* @return Höhe des Objekts
*
* @see #dimension()
*/
public float getHoehe () {
return dimension().hoehe;
}
/**
* Einfache Methode, die die X-Koordinate der linken oberen Ecke des das
* <code>Raum</code>-Objekt exakt umrandenden <code>BoundingRechteck</code>'s auf der
* Zeichenebene zurueckgibt.
*
* @return Die die X-Koordinate der linken oberen Ecke auf der Zeichenebene
*/
public int positionX () {
return (int) this.dimension().x;
} /**
* Gibt die y-Koordinate der linken oberen Ecke zurück. Sollte das Raumobjekt nicht rechteckig
* sein, so wird die Position der linken oberen Ecke des umschließenden Rechtecks genommen.
* <p/>
* TODO: Deprecate positionX() in favor of this new method?
*
* @return <code>y</code>-Koordinate
*
* @see #getX()
* @see #position()
*/
public float getY () {
return position.y;
}
/**
* Einfache Methode, die die Y-Koordinate der linken oberen Ecke des das
* <code>Raum</code>-Objekt exakt umrandenden <code>BoundingRechteck</code>'s auf der
* Zeichenebene zurueckgibt.
*
* @return Die die Y-Koordinate der linken oberen Ecke auf der Zeichenebene
*/
public int positionY () {
return (int) this.dimension().y;
}
/**
* Test, ob ein anderes Raum-Objekt von diesem geschnitten wird.
*
* @param r
* Das Objekt, das auf Kollision mit diesem getestet werden soll.
*
* @return TRUE, wenn sich beide Objekte schneiden.
*/
public final boolean schneidet (Raum r) {
if(this instanceof Knoten) {
Knoten k = (Knoten) this;
for(Raum m : k.alleElemente()) {
if(r.schneidet(m))
return true;
}
} else if (r instanceof Knoten) {
Knoten k = (Knoten) r;
for(Raum m : k.alleElemente()) {
if(this.schneidet(m))
return true;
}
} else if (this instanceof Kreis) {
if(r instanceof Kreis) {
float x = r.mittelPunkt().abstand(this.mittelPunkt());
return x <= ((Kreis)this).radius() + ((Kreis)r).radius();
} else {
return this.dimension().schneidetBasic(r.dimension());
}
} else {
return this.dimension().schneidetBasic(r.dimension());
}
return false;
} /**
* Setzt die y-Koordinate der Position des Objektes gänzlich neu auf der Zeichenebene. Das
* Setzen ist technisch gesehen eine Verschiebung von der aktuellen Position an die neue. <br
* /><br /> <b>Achtung!</b><br /> Bei <b>allen</b> Objekten ist die eingegebene Position die
* linke, obere Ecke des Rechtecks, das die Figur optimal umfasst. Das heißt, dass dies bei
* Kreisen z.B. <b>nicht</b> der Mittelpunkt ist! Hierfür gibt es die Sondermethode
* <code>mittelpunktSetzen(int x, int y)</code>.
*
* @param y
* neue <code>y</code>-Koordinate
*
* @see #positionSetzen(float, float)
* @see #mittelpunktSetzen(int, int)
* @see #setX(float)
*/
public void setY (float y) {
this.verschieben(0, y - getY());
}
/**
* Gibt den <i>aktuellen Collider</i> dieses <code>Raum</code>-Objekts zurück.
*
* @return der aktuelle Collider dieses <code>Raum</code>-Objekts, der für die Collision
* Detection verwendet wird.
*
* @see #colliderSetzen(Collider)
* @see #schneidet(Raum)
*/
public final Collider aktuellerCollider () {
if (collider.istNullCollider()) {
return collider = erzeugeCollider();
}
return collider;
}
/**
* Erzeugt einen neuen Collider für dieses Objekt. Diese Methode approximiert für das Objekt der
* jeweils implementierenden <code>Raum</code>-Klasse einen möglichst "guten" Collider; also
* einen solchen, der das tatsächliche Objekt möglichst genau umfängt, aber auch möglichst wenig
* Rechenarbeit beansprucht.
*
* @return Ein möglichst optimaler Collider für dieses Raum-Objekt.
*
* @see #colliderSetzen(Collider)
*/
public abstract Collider erzeugeCollider ();
/**
* Dreht die Zeichenfläche um den Mittelpunkt des Raumes um die gegebenen Grad, bevor mit dem
* Zeichenn begonnen wird.<br /> <b><i>Diese Methode sollte nicht außerhalb der Engine verwendet
* werden.</i></b>
*
* @see #drehung
* @see #gibDrehung()
* @see #zeichnen(Graphics2D, BoundingRechteck)
* @see #afterRender(Graphics2D, BoundingRechteck)
*/
@NoExternalUse
public final void beforeRender (Graphics2D g, BoundingRechteck r) {
transform = g.getTransform();
Punkt middle = mittelPunkt().verschobeneInstanz(new Vektor(-r.x, -r.y));
if (drehung != 0) {
g.rotate(Math.toRadians(drehung), middle.x, middle.y);
}
if (opacity != 1) {
composite = g.getComposite();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, opacity));
} else {
composite = null;
}
}
/**
* Methode zum schnellen Herausfinden des Mittelpunktes des Raum-Objektes.
*
* @return Die Koordinaten des Mittelpunktes des Objektes
*
* @see #dimension()
* @see #position()
*/
public Punkt mittelPunkt () {
BoundingRechteck b = this.dimension();
return new Punkt(b.x + (b.breite / 2), b.y + (b.hoehe / 2));
}
/**
* Dreht die Zeichenfläche wieder zurück in den Ausgangszustand. <b><i>Diese Methode sollte
* nicht außerhalb der Engine verwendet werden.</i></b>
*
* @see #drehung
* @see #gibDrehung()
* @see #zeichnen(Graphics2D, BoundingRechteck)
* @see #beforeRender(Graphics2D, BoundingRechteck)
*/
@NoExternalUse
public final void afterRender (Graphics2D g, BoundingRechteck r) {
if (composite != null) {
g.setComposite(composite);
}
g.setTransform(transform);
}
/**
* Prueft, ob ein bestimmter Punkt innerhalb des Raum-Objekts liegt.
*
* @param p
* Der Punkt, der auf Inhalt im Objekt getestet werden soll.
*
* @return TRUE, wenn der Punkt innerhalb des Objekts liegt.
*/
public final boolean beinhaltet (Punkt p) {
if (statisch) {
BoundingRechteck b = Fenster.instanz().getCam().position();
p = p.verschobeneInstanz(new Vektor(-b.x, -b.y));
}
BoundingRechteck[] dim = flaechen();
for (BoundingRechteck r : dim) {
if (r.istIn(p)) {
return true;
}
}
return false;
}
/**
* Berechnet exakter alle Rechteckigen Flaechen, auf denen dieses Objekt liegt.<br /> Diese
* Methode wird von komplexeren Gebilden, wie geometrischen oder Listen ueberschrieben.
*
* @return Alle Rechtecksflaechen, auf denen dieses Objekt liegt. Ist standartisiert ein Array
* der Groesse 1 mit der <code>dimension()</code> als Inhalt.
*
* @see Knoten
*/
public BoundingRechteck[] flaechen () {
return new BoundingRechteck[] {this.dimension()};
}
/**
* Erzeugt einen Collider auf <i>Lazy</i> Art: Es wird das durch die
* <code>dimension()</code>-Methode berechnete <code>BoundingRechteck</code> benutzt, um einen
* simplen <i>Box-Collider</i> zu erstellen.
*/
protected Collider erzeugeLazyCollider () {
return BoxCollider.fromBoundingRechteck(Vektor.NULLVEKTOR, this.dimension());
} /**
* Verschiebt das Objekt.<br /> Hierbei wird nichts anderes gemacht, als <code>verschieben(new
* Vektor(dX, dY))</code> auszufuehren. Insofern ist diese Methode dafuer gut, sich nicht mit
* der Klasse Vektor auseinandersetzen zu muessen.
*
* @param dX
* Die Verschiebung in Richtung X
* @param dY
* Die Verschiebung in Richtung Y
*
* @see #verschieben(Vektor)
* @see #bewegen(Vektor)
* @see #bewegen(float, float)
*/
public void verschieben (float dX, float dY) {
this.verschieben(new Vektor(dX, dY));
}
/**
* Setzt einen neuen Collider für dieses <code>Raum</code>-Objekt. Nach Aufruf dieser Methode
* ist der <i>standardisierte</i> Collider, der intern automatisch gesetzt wird (jedoch meist
* nicht optimal ist), außer Kraft und nur noch der hier übergebene Collider ist für die
* <i>Collision Detection</i> relevant.
*
* @param collider
* Der neue Collider, der für die Schnitt-Überprüfung verwendet wird.
*
* @see #schneidet(Raum)
* @see #boundsUebernehmen(Raum)
*/
public void colliderSetzen (Collider collider) {
this.collider = collider;
}
/**
* Übernimmt für die Collision Detection die Bounds eines anderen <code>Raum</code>-Objektes.
*
* @param boundHilfe
* Ein weiteres Raum-Objekt, dessen prinzipiellen Bounds übernommen werden sollen.<br /> <br
* /><b>WICHTIG!</b> Die Entfernung des als Parameter übergebenen <code>Raum</code>-Objektes
* vom <i>Ursprung</i> der Zeichenebene aus entspricht dem <i>Offset</i> des Colliders
* <b>relativ zu diesem <code>Raum</code>-Objekt</b>.
*
* @see #colliderSetzen(Collider)
*/
public void boundsUebernehmen (Raum boundHilfe) {
Collider c = boundHilfe.aktuellerCollider();
c.offsetSetzen(boundHilfe.position().alsVektor());
this.collider = c;
}
/**
* Gibt die Position der linken oberen Ecke zurück. Sollte das Raumobjekt nicht rechteckig sein,
* so wird die Position der linken oberen Ecke des umschließenden Rechtecks genommen. <br /><br
* />Mehr Informationen liefert die Methode {@link #dimension()}.
*
* @return Die Koordinaten des Punktes der linken, oberen Ecke in Form eines
* <code>Punkt</code>-Objektes
*
* @see #dimension()
*/
public Punkt position () {
return position;
}
/**
* Berechnet, ob dieses Raum-Objekt <b>exakt ueber einem zweiten steht</b>.<br /> Dies waere
* fuer die Engine ein Stehen auf diesem.
*
* @param m
* Das Raum-Objekt, fuer das getestet werden soll, ob dieses auf ihm steht,
*
* @return <code>true</code>, wenn dieses Objekt auf dem eingegeben steht, sonst
* <code>false</code>
*/
public boolean stehtAuf (Raum m) {
return this.dimension().stehtAuf(m.dimension());
}
/**
* Berechnet den Höhenunterschied zwischen dem Fuß des höheren und dem Kopf des tieferen
* Raum-Objekts.
*
* @param m
* Das Raum-Objekt, dessen Höhenunterschied zu diesem gefunden werden soll
*
* @return Der <b>absolute (also niemals negative)</b> Unterschied in der Höhe zwiscchen den
* beiden Objekten. <b>Überlagern sie sich, so ist der Rückgabewert 0</b>!
*/
public int hoehenUnterschied (Raum m) {
return (int) this.dimension().hoehenUnterschied(m.dimension());
}
/**
* Diese Methode loescht alle eventuell vorhandenen Referenzen innerhalb der Engine auf dieses
* Objekt, damit es problemlos geloescht werden kann.<br /> <b>Achtung:</b> zwar werden
* hierdurch alle Referenzen geloescht, die <b>nur innerhalb</b> der Engine liegen (dies
* betrifft vor allem Animationen etc), jedoch nicht die innerhalb eines
* <code>Knoten</code>-Objektes!!!!!!!!!<br /> Das heisst, wenn das Objekt an einem Knoten liegt
* (was <b>immer der Fall ist, wenn es auch gezeichnet wird (siehe die Wurzel des
* Fensters)</b>), muss es trotzdem selbst geloescht werden, <b>dies erledigt diese Methode
* nicht!!</b>.
*/
public void loeschen () {
animationsManager.animationBeendenVon(this);
}
/**
* Prüft, ob dieses Raum-Objekt in ener bestimmten festen Fläche ist.
*
* @param r
* Die kritische Fläche, auf deren schneiden mit diesem Raum-Objekt getestet werden soll.
*
* @return <code>true</code>, wenn dieses Raum-Objekt sich mit dem BoundingRechteck schneidet,
* sonst <code>false</code>.
*/
public boolean inFlaeche (BoundingRechteck r) {
BoundingRechteck[] fl = this.flaechen();
for (BoundingRechteck fr : fl) {
if (fr.schneidetBasic(r)) {
return true;
}
}
return false;
}
/**
* Gibt die aktuelle Drehung des Raumes in Grad zurück.
*
* @return Gibt die aktuelle Drehung des Raumes in Grad zurück.
*/
public double gibDrehung () {
return drehung;
}
/**
* Dreht ein Objekt auf die angegebene Gradzahl um den Mittelpunkt des Raumes.
*
* @param grad
* Grad, auf die gedreht werden soll.
*/
public void drehenAbsolut (double grad) {
this.drehung = grad;
}
/**
* Dreht ein Objekt um die angegebene Gradzahl um den Mittelpunkt des Raumes.
*
* @param grad
* Grad, um die gedreht werden soll.
*/
public void drehenRelativ (double grad) {
this.drehung -= grad;
}
/**
* Gibt die aktuelle Opacity des Raumes zurück.
*
* @return Gibt die aktuelle Opacity des Raumes zurück.
*/
@API
@SuppressWarnings ( "unused" )
public float getOpacity () {
return opacity;
}
/**
* Setzt die Opacity des Raumes.
* <p/>
* <ul><li><code>0.0f</code> entspricht einem komplett durchsichtigen Raum.</li>
* <li><code>1.0f</code> entspricht einem undurchsichtigem Raum.</li></ul>
*/
@API
@SuppressWarnings ( "unused" )
public void setOpacity (float opacity) {
this.opacity = opacity;
}
/**
* Hilfsmethode für die Sortierung der Räume nach dem Z-Index. <b><i>Diese Methode sollte nicht
* außerhalb der Engine verwendet werden.</i></b>
*
* @see #zIndex
* @see #zIndex(int)
*/
@Override
@NoExternalUse
public int compareTo (Raum r) {
if (zIndex < r.zIndex) {
return 1;
}
if (zIndex > r.zIndex) {
return -1;
}
return 0;
}
}