package de.fau.cs.mad.fly.res;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import de.fau.cs.mad.fly.features.ICollisionListener;
import de.fau.cs.mad.fly.features.IFeatureLoad;
import de.fau.cs.mad.fly.sound.AudioManager;
import de.fau.cs.mad.fly.game.CollisionDetector;
import de.fau.cs.mad.fly.game.GameController;
import de.fau.cs.mad.fly.game.GameObject;
/**
* Manages the logic of the gates like storing the gate list and handling the
* gate passing.
*
* @author Tobi
*
*/
public class GateCircuit implements IFeatureLoad, ICollisionListener {
/**
* Comparator for the gate goals.
*/
private Comparator<GateGoal> goalComparator = new Comparator<GateGoal>() {
@Override
public int compare(GateGoal first, GateGoal second) {
if (first.getGateId() < second.getGateId()) {
return -1;
} else if (first.getGateId() > second.getGateId()) {
return 1;
}
return 0;
}
};
/**
* The gate that has been passed recently, at the beginning the dummy gate.
*/
private GateGoal virtualGate;
/**
* The starting gate of the gate circuit.
*/
private GateGoal startingGate;
/**
* Maps the id to the corresponding gate.
*/
private Map<Integer, GateGoal> gates = new HashMap<Integer, GateGoal>();
/**
* The list of all the gates of the gate circuit.
*/
private List<GateGoal> allGateGoals = new ArrayList<GateGoal>();
/**
* The list of all the gates of the gate circuit.
*/
private List<GateDisplay> allGateDisplays = new ArrayList<GateDisplay>();
/**
* The list of the gate circuit listeners that want to be notified if a gate
* is passed or the gate circuit is finished.
*/
private List<GateCircuitListener> gateCircuitListeners = new ArrayList<GateCircuitListener>();
/**
* True if the last gate was reached, false otherwise.
*/
private boolean reachedLastGate = false;
/**
* The level where the gate circuit is located.
*/
protected Level level = null;
/**
* Creates a new gate circuit.
*
* @param startingGate
* The starting gate of the gate circuit.
*/
public GateCircuit(GateGoal startingGate) {
this.virtualGate = startingGate;
this.startingGate = startingGate;
}
/**
* Adds an gate circuit listener to the gate circuit.
*
* @param listener
*/
public void addListener(GateCircuitListener listener) {
gateCircuitListeners.add(listener);
}
/**
* Returns the number of gates in the gate circuit.
*
* @return size of the gate circuit.
*/
public int getGatesNumber() {
return allGateGoals().size();
}
/**
* Returns a gate goal by a given id.
*
* @param id
* The id of the gate.
* @return the gate with the given id.
*/
public GateGoal getGateGoalById(int id) {
return gates.get(id);
}
/**
* Adds a gate to the gate circuit.
*
* @param gate
* The gate goal to add.
*/
public void addGate(GateGoal gate) {
gates.put(gate.getGateId(), gate);
allGateGoals.add(gate);
allGateDisplays.add(gate.getDisplay());
}
/**
* Removes a gate from the gate circuit.
*
* @param gate
* The gate goal to remove.
*/
public void removeGate(GateGoal gate) {
gates.remove(gate);
allGateGoals.remove(gate);
allGateDisplays.remove(gate.getDisplay());
}
/**
* Fills the Map that maps id to the corresponding gate and the list of all
* gates. Sorts the list by id.
*
* @param gates
* The map with all the gates.
*/
public void setGates(Map<Integer, GateGoal> gates) {
this.gates = gates;
allGateGoals.clear();
allGateDisplays.clear();
allGateGoals.addAll(gates.values());
Collections.sort(allGateGoals, goalComparator);
for (GateGoal g : allGateGoals) {
if (g.getDisplay() != null) {
allGateDisplays.add(g.getDisplay());
}
}
}
/**
* Returns if the last gate is already reached.
*
* @return true if the last gate is reached, false otherwise.
*/
public boolean isReachedLastGate() {
return reachedLastGate;
}
/**
* Setter to tell if the last gate was reached.
*
* @param reachedLastGate
*/
protected void setReachedLastGate(boolean reachedLastGate) {
this.reachedLastGate = reachedLastGate;
}
/**
* Checks if the currently passed gate is one of the current active gates.
*
* @param gate
* The gate to check.
*/
public void gatePassed(GateGoal gate) {
int numberOfSuccessorGates = virtualGate.successors.length;
for (int i = 0; i < numberOfSuccessorGates; i++) {
if (gate.getGateId() == virtualGate.successors[i]) {
gate.passedTimes++;
activeGatePassed(gate);
i = numberOfSuccessorGates;
}
}
}
private int gateCount = 0;
/**
* Calls the gate circuit listeners for a passed gate and finishes the
* circuit if it was the last gate and it has no successors.
*
* @param gate
* The gate that was passed.
*/
public void activeGatePassed(GateGoal gate) {
boolean finished = gate.successors.length == 0;
for (GateCircuitListener s : gateCircuitListeners)
s.onGatePassed(gate);
if ( finished ) {
GameController.getInstance().getAudioManager().play(AudioManager.Sounds.GATE_PASSED);
reachedLastGate = true;
circuitFinished();
} else if ( !gate.equals(virtualGate) ) {
gateCount++;
GameController.getInstance().getAudioManager().play(AudioManager.Sounds.GATE_PASSED);
}
virtualGate = gate;
}
/**
* Sets the VirtualGate and marks all its successors
* @param gate
*/
public void setVirtualGate(GateGoal gate) {
virtualGate = gate;
int len = gate.successors.length;
for (int i = 0; i < len; i++) {
getGateGoalById(gate.successors[i]).mark();
}
}
/**
* Calls the gate circuit listeners for the finished gate circuit.
*/
protected void circuitFinished() {
for (GateCircuitListener s : gateCircuitListeners) {
s.onFinished();
}
}
/**
* Setter for the starting gate.
*
* @param startingGate
* The starting gate.
*/
public void setStartGate(GateGoal startingGate) {
this.startingGate = startingGate;
}
/**
* Getter for the currently active gates.
*
* @return currently active gates.
*/
public int[] currentGates() {
return virtualGate.successors;
}
/**
* Getter for all the gate goals of the gate circuit.
*
* @return list of all the gates goals.
*/
public List<GateGoal> allGateGoals() {
return allGateGoals;
}
/**
* Getter for all the gate displays of the gate circuit.
*
* @return list of all the gates displays.
*/
public List<GateDisplay> allGateDisplays() {
return allGateDisplays;
}
/**
* Creates the rigid bodies with convenient parameters for the gate models
* and the gate goals in the level.
*/
public void createGateRigidBodies() {
CollisionDetector collisionDetector = CollisionDetector.getInstance();
Gdx.app.log("GateCircuit.createGateRigidBodies", "Setting up collision for level gates.");
for (GateGoal g : allGateGoals()) {
g.createShapeAndRigidBody(collisionDetector);
}
for (GateDisplay d : allGateDisplays()) {
d.createShapeAndRigidBody(collisionDetector);
}
}
/**
* Moves the gates.
*
* @param The
* delta since the last call.
*/
public void moveGates(float delta) {
GateDisplay display;
final int numberOfDisplays = allGateDisplays.size();
for (int i = 0; i < numberOfDisplays; i++) {
display = allGateDisplays.get(i);
display.move(delta);
display.getGoal().move(delta);
}
}
/**
* Renders the gates.
*
* @param batch
* The model batch for the rendering.
* @param environment
* The environment for the rendering.
* @param camera
* The camera for the rendering.
*/
public void render(ModelBatch batch, Environment environment, PerspectiveCamera camera) {
GateDisplay display;
final int numberOfDisplays = allGateDisplays.size();
for (int i = 0; i < numberOfDisplays; i++) {
display = allGateDisplays.get(i);
display.render(batch, environment, camera);
}
}
/**
* Resets the gate circuit.
* <p>
* Clears the gate circuit listeners and sets the virtual gate to the
* starting gate.
*/
public void reset() {
gateCircuitListeners.clear();
virtualGate = startingGate;
}
@Override
public void load(GameController game) {
activeGatePassed(virtualGate);
}
@Override
public void onCollision(GameObject g1, GameObject g2) {
if (!(g2 instanceof GateGoal)) {
return;
}
GateGoal gate = (GateGoal) g2;
gatePassed(gate);
}
}