/* * 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.internal.phy; import ea.*; import ea.internal.util.Logger; /** * Ein Gravitator sorgt fuer das Verhalten eines Aktiv-Raum-Objektes in der Physik. * * @author Michael Andonie */ public class Gravitator extends PhysikClient { /** * Die Physik */ private final Physik physik = Physik.getPhysik(); /** * Eine imaginaere Pseudo-Beschleunigung fuer die Schwerkraft. */ private int schwerkraft = 4; /** * Der Trend der aktuellen Y-Verschiebung */ private int yTrend = 0; /** * Der Zaehöer des Y-Trends. */ private int zaehler = 1; /** * Gibt an, ob das Objekt in der naechsten TICK-Runde springen soll. */ private boolean sprungStart = false; /** * Ob das Ziel-Objekt im letzten Schritt "gefallen" oder gesprungen ist. */ private boolean zuletztGefallen = false; /** * Ob das Ziel-Raum-Objekt von Schwerkraft beeinflusst wird */ private boolean hatSchwerkraft = true; /** * Das FallReagierbar-Interface, das auf zu tiefes Fallen reagieren soll. */ private FallReagierbar fListener = FallDummy.getDummy(); /** * Das StehReagierbar-Interface, das auf stehen reagieren soll. */ private StehReagierbar sListener = StehDummy.getDummy(); /** * Die kritische Tiefe, ab der der Listener regelmaessig informiert wird. */ private int kritischeTiefe; private float remainderX=0, remainderY=0; /** * Konstruktor. * * @param ziel * Ziel des Gravitators: Dieses Objekt wird von ihm überwacht */ public Gravitator (Raum ziel) { super(ziel); physik.aktivAnmelden(this); } /** * Methode zur Weitergabe eines Rechenschrittes * * @param runde * Die Runde (1 - 10) */ public void tick (int runde) { ziel.verschieben(physik.entblocken(ziel.dimension())); if (ziel.dimension().y > kritischeTiefe) { fListener.fallReagieren(); } if (!(runde == 1)) { return; } if (!hatSchwerkraft) { return; } boolean steht = steht(); if (!steht) { //FALL-ZAEHLEN if (zaehler % schwerkraft == 0) { if (yTrend < 10) { zaehler = 1; yTrend++; } } else { zaehler++; } } else if (!sprungStart) { if (zuletztGefallen) { sListener.stehReagieren(); } yTrend = 0; zuletztGefallen = false; zaehler = 1; } else { sprungStart = false; zuletztGefallen = false; } bewegen(new Vektor(0, yTrend)); } /** * Bewegt das Raum-Objekt mithilfe des Gravitators. * * @param v * Die Bewegung beschrieben durch einen Vektor. * * @return <code>true</code>, sollte die Bewegung vollfuehrt worden sein, ohne, dass man passiv * geblockt wurde. Wurde man in der vollen Ausfuehrung der Bewegung gehindert, ist die Rueckgabe * <code>false</code>. */ @Override public boolean bewegen (Vektor v) { ziel.verschieben(physik.entblocken(ziel.dimension())); return (xVersch(v.x) & yVersch(v.y)); } /** * Diese Methode wird immer dann aufgerufen, wenn ein Client nicht weiter benoetigt wird, und er * alle seine Funktionen beenden soll, um die von ihm belegten Ressourcen freizugeben. */ @Override public void aufloesen () { physik.aktivAbmelden(this); } /** * Laesst das anliegende Raum-Objekt springen. Dies ist nur dann möglich, wenn das anliegende * Raum-Objekt "steht". Also, wenn es auf einemm Passiv-Objekt steht. * * @param kraft * Die Sprungkraft. */ @Override public boolean sprung (int kraft) { if (!hatSchwerkraft) { Logger.error("Achtung! Ein Raum-Objekt, fuer das KEINE Schwerkraft gilt, kann nicht springen!"); return false; } if (steht()) { yTrend = -kraft; sprungStart = true; return true; } return false; } /** * Setzt, ob das Ziel-Objekt von der Schwerkraft beeinflusst wird und somit fallen, aber auch * springen kann. * * @param aktiv * Ist dieser Wert <code>true</code>, so wird das Ziel-Objekt von Schwerkraft beeinflusst. Ist * er <code>false</code>, dann nicht. */ @Override public void schwerkraftAktivSetzen (boolean aktiv) { hatSchwerkraft = aktiv; } /** * Diese Methode setzt die kritische Tiefe eines Aktiv-Objektes. Ab dieser wird das * entsprechende <code>FallReagierbar</code>-Inteface, <b>das angemeldet wurde</b>, ueber den * Fall informiert. * * @param tiefe * Die Tiefe, ab der das anliegende <code>FallReagierbar</code>-Interface informiert werden * soll. Als Y-Koordinate. * * @see #fallReagierbarAnmelden(FallReagierbar, int) */ @Override public void kritischeTiefeSetzen (int tiefe) { kritischeTiefe = tiefe; } /** * In dieser Methode wird der <code>FallReagierbar</code>-Listener angemeldet.<br /> Dieser wird * ab sofort <i>immer wieder</i> informiert, solange das Ziel-<code>Raum</code>-Objekt unterhalb * der Toleranzgrenze liegt. * * @param f * Das <code>FallReagierbar</code>-Objekt, das ab sofort im Grenzfall informiert wird. * @param tiefe * Die kritische Tiefe, ab der das Interface informiert wird. * * @see #kritischeTiefeSetzen(int tiefe) */ @Override public void fallReagierbarAnmelden (FallReagierbar f, int tiefe) { fListener = f; kritischeTiefe = tiefe; } /** * In dieser Methode wird der <code>StehReagierbar</code>-Listener angemeldet.<br /> Dieser wird * ab sofort immer dann <i>einmalig</i> informiert, wenn das Ziel-<code>Raum</code>-Objekt nach * einem Sprung/Fall wieder auf einem Passiv-Objekt steht. * * @param s * Das <code>StehReagierbar</code>-Objekt, das ab sofort immer einmalig informiert wird, wenn * das Ziel-Objekt zum Stehen kommt. */ public void stehReagierbarAnmelden (StehReagierbar s) { sListener = s; } /** * Testet, ob das hieran anliegende Ziel-Objekt steht. * * @return <code>true</code>, wenn das Ziel-Objekt auf einem Passiv-Objekt steht und somit nicht * faellt oder steigt, sonst <code>false</code>.<br /> <b>Bewegung nach Rechts/Links wird hier * nicht beruecksichtigt.</b> */ @Override public boolean steht () { BoundingRechteck test = ziel.dimension().verschobeneInstanz(new Vektor(0, 1)); return physik.inPassivem(test); } /** * Setzt die Schwerkraft fuer dieses 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() */ @Override public void schwerkraftSetzen (int schwerkraft) { this.schwerkraft = schwerkraft; } /** * {@inheritDoc} */ @Override public void impulsHinzunehmen (Vektor impuls) { Logger.error("Aktivobjekte unterstützen leider keine Impulsrechnung. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public void geschwindigkeitHinzunehmen (Vektor geschwindigkeit) { Logger.error("Aktivobjekte unterstützen leider keine Geschwindigkeit. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public float getLuftwiderstandskoeffizient () { Logger.error("Aktivobjekte unterstützen leider keinen Luftwiderstand. Dafür gibt es die Newton-Körper!"); return 0; } /** * {@inheritDoc} */ @Override public boolean istBeeinflussbar () { Logger.error("Aktivobjekte unterstützen leider keinen Beeinflussbarkeit. Dafür gibt es die Newton-Körper!"); return false; } /** * {@inheritDoc} */ @Override public float getMasse () { Logger.error("Aktivobjekte unterstützen leider keine Masse. Dafür gibt es die Newton-Körper!"); return 0; } /** * {@inheritDoc} */ @Override public Vektor getForce () { Logger.error("Aktivobjekte unterstützen leider keine Kraftrechnung. Dafür gibt es die Newton-Körper!"); return null; } /** * {@inheritDoc} */ @Override public void luftwiderstandskoeffizientSetzen (float luftwiderstandskoeffizient) { Logger.error("Aktivobjekte unterstützen leider keinen Luftwiderstand. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public void beeinflussbarSetzen (boolean beeinflussbar) { Logger.error("Aktivobjekte unterstützen leider keinen Beeinflussbarkeit. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public void masseSetzen (float masse) { Logger.error("Aktivobjekte unterstützen leider keine Masse. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public void kraftSetzen (Vektor kraft) { Logger.error("Aktivobjekte unterstützen leider keine Kraftrechnung. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public void geschwindigkeitSetzen (Vektor geschwindigkeit) { Logger.error("Aktivobjekte unterstützen leider keine Geschwindigkeit. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public void einfluesseZuruecksetzen () { Logger.error("Aktivobjekte unterstützen leider keine Einflüsse. Dafür gibt es die Newton-Körper!"); } /** * {@inheritDoc} */ @Override public void kraftAnwenden (Vektor kraft, float t_kraftuebertrag) { Logger.error("Aktivobjekte unterstützen leider keine Kraftrechnung. Dafür gibt es die Newton-Körper!"); } /** * Vollfuehrt portionsweises (in Pixelschritten) Verschieben auf der X-Richtung. * * @param dX * Die x-Änderung (Delta-X) * * @return <code>true</code>, wenn die Bewegung in X-Richtung ohne Passiv-Block moeglich war, * sonst <code>false</code>. */ public boolean xVersch (float dX) { float z; int max; dX += remainderX; if (dX > 0) { z = 1; max = (int) dX; } else if (dX < 0) { z = -1; max = - (int)dX; } else { remainderX = dX; return true; } Vektor v = new Vektor(z, 0); for (int i = 0; i < max; i++) { BoundingRechteck test = ziel.dimension().verschobeneInstanz(v); if (physik.inPassivem(test)) { return false; } ziel.verschieben(v); dX = dX-z; } remainderX = dX; return true; } /** * Vollfuehrt portionsweises (in Pixelschritten) Verschieben auf der Y-Richtung unter * beruecksichtung von SChwerkrafteigenschaften. * * @param dY * Die y-Änderung (Delta-Y) * * @return <code>true</code>, wenn die Bewegung in Y-Richtung ohne Passiv-Block moeglich war, * sonst <code>false</code>. */ public boolean yVersch (float dY) { float z; int max; dY += remainderX; if (dY > 0) { z = 1; max = (int) dY; } else if (dY < 0) { z = -1; max = - (int)dY; } else { remainderY = dY; return true; } Vektor v = new Vektor(0, z); for (int i = 0; i < max; i++) { BoundingRechteck test = ziel.dimension().verschobeneInstanz(v); if (physik.inPassivem(test)) { yTrend = 0; if (z > 0) { sListener.stehReagieren(); } zuletztGefallen = false; return false; } zuletztGefallen = true; ziel.verschieben(v); dY = dY-z; } remainderY = dY; return true; } }