/* * 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.gra.Zeichenebene; import ea.internal.util.Logger; import java.awt.*; /** * Die Kamera "blickt" auf die Zeichenebene, das was sie sieht beschreibt den Teil der Zeichenebene; * das, was im Fenster dargestellt wird.<br /> Sie kann ein Objekt fokussieren und ihm so folgen. * Hierbei besteht auch die Moeglichkeit, diesen Fokus in Grenzen zu halten. Und zwar durch die * Fokus-Bounds. Diese 4 Grenzwerte koennen individuell verstellt und aktiviert werden. auch kann * man den von der Kamera darzustellenden Bereich durch eine einzige Methode definieren, in dem man * den Bereich als BoundingRechteck beschreibt.<br /> <br /> <br /> <br /> <code> BoundingRechteck * grenzen = new BoundingRechteck(0, 0, 1500, 1000);<br /> meineCam.boundsSetzen(grenzen);<br /> * </code> <br /> <br /> <br /> Hierdurch wird automatisch der gesamte Fokusapparat (auf den Bereich * zwischen den Punkten (0|0) und (1500|1000) ) eingestellt. Bei spezielleren Fokuswuenschen laesst * sich dies ebenfalls arrangieren durch die einzelnen Methoden, mit denen alle vier Bounds (N, S, * O, W) einzeln verstellt und (de)aktiviert werden koennen.<br /> <b>!!Achtung!!</b><br /> Bei den * Fokuseinstellungen sollte immer ein Bereich gewaehlt werden, der die Groesse des Anzeigefensters * (oder Vollbildes) bei weitem uebersteigt.<br /> Allgemein wirken diese Bounds auch ohne * aktivierten Fokus. jedoch ist dies meist weniger sinnvoll. * * @author Michael Andonie */ public class Kamera { /** * Die Zeichenebene, auf die sie "blickt" */ private Zeichenebene ebene; /** * Die aktuelle Bemessung der Kameraperspektive */ private BoundingRechteck bild; /** * Die Bounds der Kamera (sofern vorhanden) */ private BoundingRechteck bounds; /** * Der eventuelle Fokuspunkt der Kamera. */ private Raum fokus = null; /** * Der Fokus-Verzug */ private Vektor verzug = Vektor.NULLVEKTOR; /** * Gibt an, ob es Bounds gibt. */ private boolean hatBounds = false; /** * Konstruktor fuer Objekte der Klasse Kamera * * @param sizeX Die X-Laenge des Fensters * @param sizeY Die Y-Laenge des Fensters */ public Kamera(int sizeX, int sizeY, Zeichenebene z) { ebene = z; bild = new BoundingRechteck(0, 0, sizeX, sizeY); } /** * Setze einen Fokus der Kamera auf ein Objekt.<br /> Dieses Objekt ist ab dann im 'Zentrum' der * Kamera.<br /> Die Art des Fokus (vorne, hinten, oben, unten, mittig etc...) kann ueber die * Methode <b>setzeFokusArt()</b> geaendert werden.<br /> Soll das Fokusverhalten beendet * werden, muss die paramterlose Methode <b>loescheFokus()</b> ausgefuehrt werden; dann bleibt * die Kamera bis auf weiteres in der letzten Position.<br /> Diese Methode wrappt lediglich * <code>setzeFokus(Raum)</code>, wurde daher zur verhinderung des Orientierungsverlustes * geschrieben. * * @param r Der Fokuspunkt. * @see #setzeFokus(Raum) */ public void fokusSetzen(Raum r) { this.setzeFokus(r); } /** * Setze einen Fokus der Kamera auf ein Objekt.<br /> Dieses Objekt ist ab dann im 'Zentrum' der * Kamera.<br /> Die Art des Fokus (vorne, hinten, oben, unten, mittig etc...) kann ueber die * Methode <b>setzeFokusArt()</b> geaendert werden.<br /> Soll das Fokusverhalten beendet * werden, muss die paramterlose Methode <b>loescheFokus()</b> ausgefuehrt werden; dann bleibt * die Kamera bis auf weiteres in der letzten Position. * * @param r Der Fokuspunkt. */ public void setzeFokus(Raum r) { fokus = r; } /** * Setzt einen Fokus-Verzug. Der Standartwert hierfuer ist (0|0).<br /> Der Fokusverzug ist ein * Vektor, um den das Bild, das <b>den Fokus exakt im Zentrum hat</b>, verschoben wird.<br /> * Das heisst, dass eine FIgur im Fokus um 100 Pixel tiefer als im Absoluten Bildzentrum liegt, * wenn der Fokusverzug mit folgender Methode gesetzt wurde:<br /> <br /> <code> /*Irgendwo in * der spielsteuernden Klasse* /<br /> cam.fokusVerzugSetzen(new Vektor(0, -100));<br /> <br * /></code> * * @param v Der Vektor, um den ab sofort die Kamera vom Zentrum des Fokus verschoben wird. */ public void fokusVerzugSetzen(Vektor v) { verzug = v; } /** * Mit dieser Methode kann man direkt saemtliche Kamera-Bounds-Einstellungen machen.<br /> Ein * Bounding-Rechteck gibt die Begrenzung an, die die Kameraperspektive, <b>solange die Bounds * nicht deaktiviert werden</b> (ueber die Methode <code>hatBoundsSetzen</code> moeglich), * niemals uebertreten wird. * * @param r Das BoundingRechteck, das die Begrenzung des Raumes angibt * @see #hatBoundsSetzen(boolean) */ public void boundsSetzen(BoundingRechteck r) { if (r == null) { Logger.error("Der Eingabewert fuer den Fokusbereich war null!"); return; } hatBoundsSetzen(true); bounds = r; } /** * Setzt, ob das Fokusverhalten durch Bounds begrenzt wird. * * @param b Ob die gesetzten Minimum- und Maximum-Werte auch aktiviert werden sollen. * @see #boundsSetzen(BoundingRechteck) */ public void hatBoundsSetzen(boolean b) { hatBounds = b; } /** * Loescht den Fokus.<br /> Die Kamera bleibt in ihrer letzten Position zurueck bis entweder ein * neuer Fokus gesetzt wird oder sie einfach nur verschoben wird.<br /> Diese Methode macht das * selbe wie <code>loescheFokus</code>, und ist wegen einer einheitlichen Schreibweise * eingeführt. * * @see #loescheFokus() */ public void fokusLoeschen() { loescheFokus(); } /** * Loescht den Fokus.<br /> Die Kamera bleibt in ihrer letzten Position zurueck. */ public void loescheFokus() { fokus = null; } /** * Verschiebt die Kamera um einen bestimmten Wert in X- und Y-Richtung.<br /> Alternative * Methode fuer diejenigen, denen ein Vektor zu umstaendlich ist. * * @param x Die Verschiebung in X-Richtung * @param y Die Verschiebung in Y-Richtung * @see #verschieben(Vektor) */ public void verschieben(int x, int y) { this.verschieben(new Vektor(x, y)); } /** * Verschiebt die Kamera um einen bestimmten Wert in X- und Y-Richtung. * * @param v Der die Bewegung beschreibende Vektor. * @see #verschieben(int, int) */ public void verschieben(Vektor v) { bild = bild.verschobeneInstanz(v); } /** * Setzt das Zentrum der Kamera. Von nun an ist der Punkt mit den eingegebenen Koordinaten im * Zentrum des Bildes. * * @param x Die X-Koordinate des Zentrums des Bildes * @param y Die Y-Koordinate des Zentrums des Bildes * @see #zentrumSetzen(Punkt) */ public void zentrumSetzen(int x, int y) { this.zentrumSetzen(new Punkt(x, y)); } /** * Setzt das Zentrum der Kamera. Von nun an ist der Eingegebene Punkt im Zentrum des Bildes. * * @param zentrum Das neue Zentrum der Kamera * @see #zentrumSetzen(int, int) */ public void zentrumSetzen(Punkt zentrum) { bild = bild.mittenAngleichInstanz(zentrum); } /** * Setzt die Position der <i>linken oberen Ecke</i> der Kameraperspektive. * * @param p Der Punkt der linken oberen Ecke der Kameraperspektive * @see #positionSetzen(float, float) */ public void positionSetzen(Punkt p) { positionSetzen(p.x, p.y); } /** * Setzt die Position der <i>linken oberen Ecke</i> der Kameraperspektive. * * @param x Die <i>X-Koordinate der linken oberen Ecke</i> der Kameraperspektive * @param y Die <i>Y-Koordinate der linken oberen Ecke</i> der Kameraperspektive * @see #positionSetzen(Punkt) */ public void positionSetzen(float x, float y) { bild = bild.anPosition(x, y); } /** * @return Der Knoten, an dem jedes Raum-Objekt liegen muss, um gezeichnet zu werden. */ public Knoten wurzel() { return ebene.basis(); } /** * Die aktuelle Position der Kamera wird zurueckgegeben. * * @return Das aktuelle BoundingRechteck, dass die aktuelle Fensterdarstellung beschreibt. */ public BoundingRechteck position() { return bild; } /** * @return Der Verzug in Richtung X, den die Kamera bis jetzt vom Urspruenglichen Standort (0, * 0) hat. */ public int getX() { return (int) bild.x; } /** * @return Der Verzug in Richtung Y, den die Kamera bis jetzt vom Urspruenglichen Standort (0, * 0) hat. */ public int getY() { return (int) bild.y; } /** * Zeichnet alle Objekte neu, die sich auf der Zeichenebene und im Blickfeld der Kamera * befinden. */ public void zeichne(Graphics2D g) { if (hatFokus()) { // Nachjustieren bild = bild.mittenAngleichInstanz(fokus.dimension()); bild = bild.verschobeneInstanz(verzug); } if (hatBounds) { bild = bild.in(bounds); } ebene.basis().zeichnen(g, bild); if (EngineAlpha.isDebug()) { //Debug Grid int tx = (int) bild.x; int ty = (int) bild.y; int gridSize = 50; g.translate(-tx, -ty); g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 10)); g.setColor(new Color(255, 255, 255, 100)); for (int x = tx / gridSize * gridSize; x < tx + bild.breite; x += gridSize) { g.drawLine(x, ty, x, ty + (int) bild.hoehe); g.drawString("" + x, x + 10, ty + 20); } for (int y = ty / gridSize * gridSize; y < ty + bild.hoehe; y += gridSize) { g.drawLine(tx, y, tx + (int) bild.breite, y); g.drawString("" + y, tx + 10, y + 20); } g.translate(tx, ty); //Show Colliders Raum debugBoxes = ebene.basis().aktuellerCollider().visualize(ebene.basis().position(), new Farbe(255,255,255,20)); debugBoxes.zeichnen(g, bild); } } /** * @return Ob die Kamera steif ist, oder sich mit einem Fokuspunkt mitbewegt. */ public boolean hatFokus() { return (fokus != null); } }