Skip to content

Game Control

Kamil Więczaszek edited this page Jun 13, 2023 · 30 revisions

Game state logic

Game state is the part of the game timeline, with specific duration expressed in time units. It is represented by GameState object. Game states are used to split the game into smaller parts to make game more controllable.

Every game state has several properties specified by arguments while invoking a constructor:

  • name - name of the state, mainly for display
  • duration - this is the number of periods the state lasts; -1 for infinite
  • period - length of each period expressed in milliseconds; 1 if not specified
  • reverseTimer - deterimnes if the game state timer shall count up from 0 or count down to 0

State declared infinite will last until the shouldEnd() method returns true.

Lets declare an example state called WAITING_FOR_PLAYERS:

public static final GameState WAITING_FOR_PLAYERS = new GameState("waiting", -1, 1, false) {
    @Override
    public void onInit() {
        
    }

    @Override
    public void tick() {
        
    }

    @Override
    public void onEnd() {
        
    }
}

Note: This object is declared as final field of an anonymous subclass of GameState. It is recommended to do so, in case there is a need for special functionality.


As can be seen, declaration above contains empty overrides of some methods provided by GameState class, although they aren't abstract thus their declaration is optional. Those are predefined handler methods that are called on specific action:

  • onInit() is called when the state is initialized
  • tick() is called every time the time counter increases
  • onEnd() is called when the state is terminated
  • shouldEnd() is called when tick() method and determines if the state should be terminated; returns false by default

Game state timer

GameStateTimer class is one of the key class for creating a game engine. It is a special timer that operates on GameState objects and gives ability to split the one game timeline into separate parts (game states) that differ from each other by the name, duration and happening events. That allows the user to precisely define what and when should happen in the game and control the timeline.

The timer has two counting types, which are chosen accordingly to the current state:

  • normal counting - the timer counts from 0 to current state duration
  • counting back - the timer counts back from current state duration back to 0

Game state timer can be created using its constructor. Its object can also be fetched from the GameManager object using getGameStateTimer() method.

GameStateTimer gsTimer;
// Object creation
gsTimer = new GameStateTimer(this);
// Fetch from GameManager object
gsTimer = gameManager.getGameStateTimer();

Note: Despite no restriction of having multiple game state timers, it is recommended to have only one declared per game - for consistency and to avoid ambiguity.

Manual control

Major purpose of GameStateTimer is to count and switch between particular game states with no need to declare any additional statements and care for multithreading. This can be done whether manually or automatically using GstSchedule object.

Manual control happens by using dedicated methods:

  • initialize() - initializes specified GameState object
  • terminate() - terminates the current game state and runs next from schedule if specified
  • pause() - pauses the timer if running
  • resume() - resumes the timer if paused
  • prompt() - if running, instantly executes common timer cycle iteration: checks for ending the state and calls tick() method for current state but does not count up a time

Note: If timer runs no state (ex. if it was terminated) it stores the GameState.EMPTY state which simply does nothing and can be only interfeared by initializing new state.

Scheduling

As mentioned before, timer can be applied a schedule, which determines exact order of game states that are about to be started. Intervals between the states can be replaced with objects of Await class which is the state with no functionality but particular duration expressed in milliseconds.

Using schedules:

// Declaring schedule
GstSchedule schedule = gsTimer.getSchedule();

// Adding schedule items
schedule.addState(MY_STATE);
schedule.addState(new Await(2000));
schedule.addState(MY_OTHER_STATE);

// Declaring new GameStateTimer with associated schedule
GameStateTimer timer = new GameStateTimer(schedule, this);

Conditional listeners

ConditionalListener adds a condition gate for the listener. The event will only be passed down to the handled listener if the condition is met. Both condition and listener are passed down to constructor in arguments. Declaration doesn't register the listener - this has to be done by calling register() method.

Declaring custom listener with static condition method:

import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerPickupItemEvent;

public class PlayerPickupItemListener implements Listener {

    @EventHandler
    public void onPlayerPickupItem(PlayerPickupItemEvent event) {
        System.out.println(event.getPlayer().getDisplayName() + " picked up a stack of items");
    }

    public static boolean condition(Event event) {
        if(event instanceof PlayerPickupItemEvent) {
            return ((PlayerPickupItemEvent) event).getItem().getItemStack().getAmount() == 64;
        }
        return false;
    }
}

Creating associated ConditionalListener object:

ConditionalListener conditionalListener = new ConditionalListener(new PlayerPickupItemListener(), PlayerPickupItemListener::condition);
conditionalListener.register(this); // PlayerPickupItemListener listener registration using this plugin

If the ConditionalListener object reference is unnecessary, the code above can be shortened to one line:

new ConditionalListener(new PlayerPickupItemListener(), PlayerPickupItemListener::condition).register();

Technical info

  • Java version: 8
  • Build: Maven
  • Minecraft version: 1.8.8+
  • License: Apache 2.0

⚠️ Repository in development state. ⚠️

Clone this wiki locally