package de.lessvoid.nifty.slick2d;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.render.batch.BatchRenderDevice;
import de.lessvoid.nifty.slick2d.input.ForwardingInputSystem;
import de.lessvoid.nifty.slick2d.input.SlickInputSystem;
import de.lessvoid.nifty.slick2d.input.SlickSlickInputSystem;
import de.lessvoid.nifty.slick2d.render.batch.SlickBatchRenderBackendFactory;
import de.lessvoid.nifty.slick2d.sound.SlickSoundDevice;
import de.lessvoid.nifty.slick2d.time.LWJGLTimeProvider;
import de.lessvoid.nifty.spi.render.RenderDevice;
import de.lessvoid.nifty.spi.sound.SoundDevice;
import de.lessvoid.nifty.spi.time.TimeProvider;
import org.newdawn.slick.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* This class implements a Slick Basic game with a NiftyGUI Overlay.
*
* @author Martin Karing <nitram@illarion.org>
*/
public abstract class NiftyOverlayBasicGame extends BasicGame implements NiftyInputForwarding, NiftyOrderControl {
/**
* The one and only Nifty GUI.
*/
@Nullable
private Nifty niftyGUI = null;
/**
* This variable provides the control over the forwarding implementations.
*/
@Nullable
private ForwardingInputSystem inputForwardingControl;
/**
* The render order that is used in this game.
*/
@Nonnull
private NiftyRenderOrder renderOrder;
/**
* The update order that is used in this game.
*/
@Nonnull
private NiftyUpdateOrder updateOrder;
/**
* The last reported screen height.
*/
private int lastHeight;
/**
* The last reported screen width.
*/
private int lastWidth;
/**
* Forward constructor to set the title of the game.
*
* @param title the title of the game
*/
protected NiftyOverlayBasicGame(@Nonnull final String title) {
super(title);
renderOrder = NiftyRenderOrder.NiftyOverlay;
updateOrder = NiftyUpdateOrder.NiftyLast;
}
@Override
public final void setRenderOrder(@Nonnull NiftyRenderOrder order) {
renderOrder = order;
}
@Override
public final void setUpdateOrder(@Nonnull NiftyUpdateOrder order) {
updateOrder = order;
}
@Nullable
@Override
public final ForwardingInputSystem getInputForwardingControl() {
return inputForwardingControl;
}
@Nonnull
@Override
public final NiftyRenderOrder getRenderOrder() {
return renderOrder;
}
@Nonnull
@Override
public final NiftyUpdateOrder getUpdateOrder() {
return updateOrder;
}
/**
* Initialize the game and the GUI.
*/
@Override
public final void init(@Nonnull final GameContainer container) throws SlickException {
initGameAndGUI(container);
if (niftyGUI == null) {
throw new IllegalArgumentException("NiftyGUI is not initialized!");
}
}
/**
* Initialize the game. This function is called during {@link #init(GameContainer)}. During this call its needed to
* initialize the Nifty GUI with own options by calling {@link #initNifty(GameContainer, RenderDevice,
* SoundDevice, SlickInputSystem, TimeProvider)} .
*
* @param container the game container that displays the game
*/
protected abstract void initGameAndGUI(@Nonnull GameContainer container);
@Override
public final boolean isInputForwardingSupported() {
return inputForwardingControl != null;
}
/**
* Render the game.
*/
@Override
public final void render(@Nonnull final GameContainer container, @Nonnull final Graphics g) throws SlickException {
if (niftyGUI == null) {
renderGame(container, g);
} else {
switch (renderOrder) {
case NiftyOverlay:
renderGame(container, g);
niftyGUI.render(false);
break;
case NiftyBackground:
niftyGUI.render(true);
renderGame(container, g);
break;
}
}
}
/**
* This function is supposed to be used to render the game. It is called during the call of the {@link
* #render(GameContainer, Graphics)} function.
*
* @param container the container that displays the game
* @param g the graphics instance that is used to draw the game
*/
protected abstract void renderGame(@Nonnull GameContainer container, @Nonnull Graphics g);
/**
* Update the game.
*/
@Override
public final void update(@Nonnull final GameContainer container, final int delta) throws SlickException {
if (niftyGUI == null) {
updateGame(container, delta);
} else {
final int currentHeight = container.getHeight();
final int currentWidth = container.getWidth();
if ((currentHeight != lastHeight) || (currentWidth != lastWidth)) {
lastHeight = currentHeight;
lastWidth = currentWidth;
niftyGUI.resolutionChanged();
}
switch (updateOrder) {
case NiftyLast:
updateGame(container, delta);
niftyGUI.update();
break;
case NiftyFirst:
niftyGUI.update();
updateGame(container, delta);
break;
}
}
}
/**
* This function is supposed to be used to update the state of the game. It called during the call of the {@link
* #update(GameContainer, int)} function.
*
* @param container the container that displays the game
* @param delta the time since the last update
* @throws SlickException in case anything goes wrong during the update
*/
protected abstract void updateGame(@Nonnull GameContainer container, int delta) throws SlickException;
/**
* Initialize the Nifty GUI for this game. This function will use the default {@link TimeProvider}. Also it will use
* the render and sound devices that are provided with this library. As for the input it will forward all input to
* the
* Slick {@link InputListener} that is implemented in this class.
*
* @param container the container used to display the game
* @throws IllegalStateException in case this function was called before
* @see SlickSoundDevice
* @see SlickSlickInputSystem
*/
protected final void initNifty(@Nonnull final GameContainer container) {
initNifty(container, new SlickSlickInputSystem(this));
}
/**
* Initialize the Nifty GUI for this game. This function will use the default {@link TimeProvider}. Also it will use
* the render and sound devices that are provided with this library.
*
* @param container the container used to display the game
* @param inputSystem the input system that is supposed to be used
* @throws IllegalStateException in case this function was called before
* @see SlickSoundDevice
*/
protected final void initNifty(@Nonnull final GameContainer container, @Nonnull final SlickInputSystem inputSystem) {
initNifty(container, new BatchRenderDevice(SlickBatchRenderBackendFactory.create(container)), new SlickSoundDevice(), inputSystem);
}
/**
* Initialize the Nifty GUI for this game. This function will use the default {@link TimeProvider}.
*
* @param container the container used to display the game
* @param renderDevice the render device that is supposed to be used to render the GUI
* @param soundDevice the sound device that is supposed to be used
* @param inputSystem the input system that is supposed to be used
* @throws IllegalStateException in case this function was called before
*/
protected final void initNifty(
@Nonnull final GameContainer container,
@Nonnull final RenderDevice renderDevice,
@Nonnull final SoundDevice soundDevice,
@Nonnull final SlickInputSystem inputSystem) {
initNifty(container, renderDevice, soundDevice, inputSystem, new LWJGLTimeProvider());
}
/**
* Initialize the Nifty GUI for this game.
*
* @param container the container used to display the game
* @param renderDevice the render device that is supposed to be used to render the GUI
* @param soundDevice the sound device that is supposed to be used
* @param inputSystem the input system that is supposed to be used
* @param timeProvider the time provider that is supposed to be used
* @throws IllegalStateException in case this function was called before
*/
protected final void initNifty(
@Nonnull @SuppressWarnings("TypeMayBeWeakened") final GameContainer container,
@Nonnull final RenderDevice renderDevice,
@Nonnull final SoundDevice soundDevice,
@Nonnull final SlickInputSystem inputSystem,
@Nonnull final TimeProvider timeProvider) {
if (niftyGUI != null) {
throw new IllegalStateException("The NiftyGUI was already initialized. Its illegal to do so twice.");
}
final Input input = container.getInput();
inputSystem.setInput(input);
niftyGUI = new Nifty(renderDevice, soundDevice, inputSystem, timeProvider);
if (inputSystem instanceof ForwardingInputSystem) {
inputForwardingControl = (ForwardingInputSystem) inputSystem;
}
/* Slick automatically adds the game as input listener. Undo this. */
input.removeListener(this);
input.removeListener(inputSystem);
input.addListener(inputSystem);
prepareNifty(niftyGUI);
}
/**
* This function should be used to prepare the actual GUI and the controllers of the Nifty GUI. It is called right
* after the Nifty GUI got initialized.
*
* @param nifty the Nifty GUI that got initialized
*/
protected abstract void prepareNifty(@Nonnull Nifty nifty);
/**
* Get the instance of the NiftyGUI that is used to render this screen.
*
* @return the instance of the NiftyGUI
*/
@Nullable
public final Nifty getNifty() {
return niftyGUI;
}
}