/*
* 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.Collider;
import ea.internal.collision.ColliderGroup;
import ea.internal.gra.Listung;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Vector;
/**
* Ein Knoten ist eine Sammlung vielen Raum-Objekten, die hierdurch einheitlich bewegt, und
* einheitlich behandelt werden koennen.
*
* @author Michael Andonie, Niklas Keller <me@kelunik.com>
*/
public class Knoten extends Raum implements Listung {
/**
* Die Liste aller Raum-Objekte, die dieser Knoten fasst.
*/
private Vector<Raum> list;
/**
* Konstruktor für Objekte der Klasse Knoten
*/
public Knoten () {
list = new Vector<>();
}
/**
* Entfernt alle Raum-Objekte von diesem Knoten, die an diesem Knoten gelagert sind.<br /> <br
* /> <b>ACHTUNG</b><br /> Sollte <i>Physik</i> benutzt werden:<br /> Diese Methode macht alle
* abgemeldeten <code>Raum</code>-Objekt fuer die Physik neutral!!!<br /> Sollte dies NICHT
* gewuenscht sein, gibt es hierfuer die Methode <code>leerenOhnePhysikAbmelden()</code>.
*
* @see #leerenOhnePhysikAbmelden()
*/
public void leeren () {
for (int i = list.size() - 1; i >= 0; i--) {
list.get(i).neutralMachen();
list.get(i).loeschen();
}
list.clear();
}
/**
* Loescht alle Raum-Objekte, die an diesem Knoten gelagert sind, ohne sie jedoch von ihrer
* Physik her zu beeinflussen.
*/
public void leerenOhnePhysikAbmelden () {
list.clear();
}
/**
* Entfernt ein Raum-Objekt von diesem Knoten.<br /> War es mehrfach angesteckt, so werden alle
* Verbindungen geloescht, war es niemals angemeldet, so passiert <b>gar nichts</b>.<br /> <br
* /> <b>Achtung!!</b><br /> Sollte <i>Physik</i> benutzt werden:<br /> Diese Methode macht alle
* abgemeldeten <code>Raum</code>-Objekt fuer die Physik neutral!!!<br /> Sollte dies NICHT
* gewuenscht sein, gibt es hierfuer die Methode <code>entfernenOhnePhysikAbmelden()</code>.
*
* @param m
* Das von diesem Knoten zu entfernende Raum-Objekt
*
* @see #entfernenOhnePhysikAbmelden(Raum)
*/
public void entfernen (Raum m) {
if (list.contains(m)) {
m.neutralMachen();
m.loeschen();
}
// noinspection StatementWithEmptyBody
while (list.remove(m)) ;
}
/**
* Entfernt ein Raum-Objekt von diesem Knoten, <b>ohne seine Physik zu beeinflussen</b>.<br />
* War es mehrfach angesteckt, so werden alle Verbindungen geloescht, war es niemals angemeldet,
* so passiert <b>gar nichts</b>.
*
* @param m
* Das von diesem Knoten zu entfernende Raum-Objekt
*/
public void entfernenOhnePhysikAbmelden (Raum m) {
list.remove(m);
}
/**
* Prueft, ob ein bestimmtes Raum-Objekt in diesem Knoten gelagert ist.<br /> <br />
* <b>ACHTUNG</b><br /> Diese Methode prueft nicht eventuelle Unterknoten, ob diese vielleiht
* das Raum-Objekt beinhalten, sondern nur den eigenen Inhalt!
*
* @param m
* Das Raum-Objekt, das auf Vorkommen in diesem Knoten ueberprueft werden soll
*
* @return <code>true</code>, wenn das Raum-Objekt <b>ein- oder auch mehrmals</b> an diesem
* Knoten liegt
*/
public boolean besitzt (Raum m) {
return list.contains(m);
}
/**
* Kombinationsmethode. Hiermit kann man so viele Raum-Objekte gleichzeitig an den Knoten
* anmelden, wie man will.<br /> <b>Beispiel:</b><br /> <br /> <code> //Der Knoten, um alle
* Objekte zu sammeln<br /> Knoten knoten = new Knoten();<br /> <br /> //Lauter gebastelte
* Raum-Objekte<br /> Raum r1<br /> Raum r2;<br /> Raum r3;<br /> Raum r4;<br /> Raum r5<br />
* Raum r6;<br /> Raum r7;<br /> Raum r8;<br /> Raum r9<br /> Raum r10;<br /> Raum r11;<br />
* Raum r12;<br /> <br /> //Eine Methode, um alle anzumelden:<br /> knoten.add(r1, r2, r3, r4,
* r5, r6, r7, r8, r9, r10, r11, r12);<br /> </code><br /> Das Ergebnis: 11 Zeilen Programmcode
* gespart.
*/
public void add (Raum... m) {
for (Raum n : m) {
add(n);
}
}
/**
* Fuegt ein Raum-Objekt diesem Knoten hinzu.<br /> Das zugefuegte Objekt wird ab dann in alle
* Methoden des Knotens (<code>verschieben(), dimension()</code> etc.) mit eingebunden.
*
* @param m
* Das hinzuzufuegende Raum-Objekt
*/
public void add (Raum m) {
// reverse to keep backwardscompability
Collections.reverse(list);
list.add(m);
Collections.reverse(list);
Collections.sort(list);
}
/**
* Gibt alle Elemente des Knotens in Form eines <code>Raum</code>-Objekt-Arays aus.
*
* @return Alle Elemente als vollstaendig gefuelltes <code>Raum</code>-Objekt-Aray.
*/
public Raum[] alleElemente () {
return list.toArray(new Raum[list.size()]);
}
/**
* Bewegt jedes angelegte Objekt für sich allein (Physik-Modus)!<br /> Das bedeutet, dass das
* Blockiertwerden eines einzelnen <code>Raum</code>-Objektes an diesem Knoten <b>nicht</b>
* automatisch alle anderen Objekte blockiert.
*
* @param v
* Der die Verschiebung beschreibende Vektor.
*
* @return Nur dann <code>true</code>, wenn bei allen anderen Objekten die Rueckgabe auch
* <code>true</code> ist. Sonst ist die Rueckgabe <code>false</code>.
*/
@Override
public boolean bewegen (Vektor v) {
boolean ret = true;
for (int i = list.size() - 1; i >= 0; i--) {
if (!list.get(i).bewegen(v)) {
ret = false;
}
}
return ret;
}
/**
* Zeichnet den Knoten.<br /> Das heisst, der Zeichnen-Befehl wird an die Unterobjekte
* weitergetragen.<br /> Diese Methode ist nur intern von Bedeutung
*
* @param g
* Das Grafik-Objekt
* @param r
* Das Rechteck, dass die Kameraposition definiert
*/
@Override
public void zeichnen (Graphics2D g, BoundingRechteck r) {
try {
for (int i = list.size() - 1; i >= 0; i--) {
list.get(i).zeichnenBasic(g, r);
}
} catch (ArrayIndexOutOfBoundsException e) {
// Wahrscheinlich wurde die Liste geleert.
}
}
/**
* Die dimension()-Methode.<br /> Gibt ein <code>BoundingRechteck</code> aus, das alle
* Komponente dieses Knotens bedeckt.
*
* @return Das BoundingRechteck, das alle Komponente dieses Knotens bedeckt.<br /> Ist ein
* BoundingRechteck mit den Werten (0|0|0|0), wenn dieses Knoten keine Konkreten Raum-Objekte
* gesammelt hat.
*/
@Override
public BoundingRechteck dimension () {
BoundingRechteck ret = null;
try {
for (int i = list.size() - 1; i >= 0; i--) {
if (ret == null) {
ret = list.get(i).dimension();
} else {
ret = ret.summe(list.get(i).dimension());
}
}
} catch (ArrayIndexOutOfBoundsException e) {
// Wahrscheinlich wurde die Liste geleert.
}
if (ret == null) {
return new BoundingRechteck(0, 0, 0, 0);
} else {
return ret;
}
}
/**
* Verschiebt diesen Knoten.<br /> Das heisst, dass saemtliche anliegenden Raum-Objekte
* gleichermassen Verschoben werden.
*
* @param v
* Der Vektor, der die Verschiebung angibt.
*/
@Override
public void verschieben (Vektor v) {
for (int i = list.size() - 1; i >= 0; i--) {
list.get(i).verschieben(v);
}
}
/**
* {@inheritDoc} Collider ist eine Gruppierung der Collider aller <code>Raum</code>-Objekte, die
* an diesem Knoten angehängt sind.
*/
@Override
public Collider erzeugeCollider () {
ColliderGroup group = new ColliderGroup();
for (Raum r : list) {
group.addCollider(r.erzeugeCollider());
}
return group;
}
/**
* Berechnet exakter alle rechteckigen Flächen, auf denen dieses Objekt liegt.<br /> Diese
* Methode wird von komplexeren Gebilden, wie geometrischen oder Listen ueberschrieben.
*
* @return Alle Rechtecksflächen, auf denen dieses Objekt liegt. Ist standardisiert ein Array
* der Größe 1 mit der <code>dimension()</code> als Inhalt.
*/
@Override
public BoundingRechteck[] flaechen () {
ArrayList<BoundingRechteck> data = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {
data.addAll(Arrays.asList(list.get(i).flaechen()));
}
return data.toArray(new BoundingRechteck[data.size()]);
}
/**
* Setzt die Durchsichtigkeit für jedes angemeldete Objekt.
*
* @param opacity {@inheritDoc}
*/
@Override
public void setOpacity (float opacity) {
try {
for (int i = list.size() - 1; i >= 0; i--) {
list.get(i).setOpacity(opacity);
}
} catch (ArrayIndexOutOfBoundsException e) {
// Wahrscheinlich wurde die Liste geleert.
}
}
}