EventManager.java
package io.github.unisim.event;
import com.badlogic.gdx.math.MathUtils;
import io.github.unisim.Difficulty;
import io.github.unisim.GameLogic;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BooleanSupplier;
public class EventManager {
private final BooleanSupplier canStartEvent;
private final List<Class<? extends GameEvent>> enabledEvents;
private GameEvent currentEvent;
private float nextEventProbability;
private float checkEventTimer;
private final GameLogic gameLogic;
public EventManager(BooleanSupplier canStartEvent, GameLogic gameLogic, Difficulty difficulty) {
this.canStartEvent = canStartEvent;
this.gameLogic = gameLogic;
enabledEvents = new ArrayList<>();
enabledEvents.addAll(List.of(BusyWeekEvent.class, DonationEvent.class));
// Don't add negative events on easy difficulty.
if (difficulty != Difficulty.EASY) {
enabledEvents.addAll(List.of(RainEvent.class, RosesEvent.class));
}
// Don't add random discount even on hard difficulty.
if (difficulty != Difficulty.HARD) {
enabledEvents.add(DiscountEvent.class);
}
}
/**
* Forcibly starts a new instance of the given event.
*
* @param eventClass the event to start
*/
public void startNewEvent(Class<? extends GameEvent> eventClass) {
try {
var eventConstructor = eventClass.getConstructor();
currentEvent = eventConstructor.newInstance();
gameLogic.pause();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Forcibly starts a new event.
*/
public void startNewEvent() {
startNewEvent(enabledEvents.get(ThreadLocalRandom.current().nextInt(enabledEvents.size())));
}
/**
* Updates the current active event if there is one, otherwise may randomly start a new event.
*
* @param deltaTime the delta time between the last call of update
*/
public void update(float deltaTime) {
if (currentEvent != null) {
currentEvent.update(deltaTime);
if (currentEvent.isFinished()) {
currentEvent = null;
}
return;
}
if (!canStartEvent.getAsBoolean()) {
return;
}
// No event is currently active, so generate a random number every 2 seconds to see if we should start a new
// event. Bias the random number slightly to prevent events from happening to close to each other.
nextEventProbability += deltaTime * 0.01f;
checkEventTimer += deltaTime;
if (checkEventTimer > 2.0f) {
checkEventTimer = 0.0f;
if (Math.min(MathUtils.random() + 0.1f, 1.0f) < nextEventProbability) {
nextEventProbability = 0.0f;
startNewEvent();
}
}
}
/**
* @return whether there's an event currently active
*/
public boolean isEventActive() {
return currentEvent != null;
}
/**
* @return the active event if any; null otherwise
*/
public GameEvent getCurrentEvent() {
return currentEvent;
}
}