/* * 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; } }