diff --git a/src/example/java/module-info.java b/src/example/java/module-info.java index f2211af2..e9673f29 100644 --- a/src/example/java/module-info.java +++ b/src/example/java/module-info.java @@ -1,7 +1,4 @@ -/** - * An example game made for The FastJ Game - * Library. - */ +/** Examples for The FastJ Game Library. */ module fastj.game { - requires fastj.library; // allows us to use fastj + requires fastj.library; } diff --git a/src/example/java/tech/fastj/example/engineconfig/Main.java b/src/example/java/tech/fastj/example/engineconfig/Main.java new file mode 100644 index 00000000..1ab6fb84 --- /dev/null +++ b/src/example/java/tech/fastj/example/engineconfig/Main.java @@ -0,0 +1,93 @@ +package tech.fastj.example.engineconfig; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.engine.HWAccel; +import tech.fastj.math.Point; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Display; +import tech.fastj.graphics.game.Polygon2D; +import tech.fastj.graphics.util.DrawUtil; + +import tech.fastj.systems.control.SimpleManager; + +public class Main extends SimpleManager { + @Override + public void init(Display display) { + /* As a small aside, this is a small inclusion in order to show how configuring FastJ + * affects rendering. + * The code is not the primary focus of the example -- this is just to give a visual. */ + Pointf[] squareMesh = DrawUtil.createBox(50f, 50f, 100f); + Polygon2D square = new Polygon2D(squareMesh); + drawableManager.addGameObject(square); + } + + @Override + public void update(Display display) { + // Empty -- this example does not make use of this method. + } + + public static void main(String[] args) { + FastJEngine.init("Hello, Configuration!", new Main()); + + + /* FastJEngine Configuration */ + + /* When using the other examples or FastJ in general, you may have noticed that the game + * engine defaults to a 1280*720 window. This is part of FastJEngine's default + * configuration. + * + * With that said, let's get started with the first two types of configuration: + * 1. configureViewerResolution + * 2. configureInternalResolution + * + * Note 1: Both of these configurations require use of a Point. A Point is similar to that + * of a Pointf, but it only allows integer values. + * Note 2: Configurations should always be done after initializing the game engine. + */ + + + /* "FastJEngine#configureViewerResolution" configures the viewer resolution -- the size of + * the window that the player plays in. + * By default, this is configured to 720p -- 1280*720. Of course, you can change this to + * any set of values you would like, as long as both values are at least 1. + * + * For this example, I've set it to 640*480. Feel free to mess around with the numbers! */ + FastJEngine.configureViewerResolution(new Point(640, 480)); + + /* "FastJEngine#configureInternalResolution" configures the internal resolution -- the size + * of the actual game canvas (where the game gets rendered). + * By default, this is also configured to 720p -- 1280*720. Like the viewer resolution, + * this can be set to any values that are at least 1. + * + * For this example, I've set this to 640*480. Feel free to mess around with the numbers! */ + FastJEngine.configureInternalResolution(new Point(640, 480)); + + + /* Now, we'll move onto configureHardwareAcceleration. + * By making use of java2d, FastJ supports a few hardware-accelerated graphics APIs: + * - OpenGL + * - Direct3D + * + * With that in mind, "FastJEngine#configureHardwareAcceleration" allows you to configure + * the type of hardware acceleration your game uses. This is set using the "HWAccel" enum. + * + * For this example, we're going to set the hardware acceleration to OpenGL. */ + FastJEngine.configureHardwareAcceleration(HWAccel.OpenGL); + + + /* Lastly, FPS and UPS configuration. + * + * - FPS: Frames Per Second (how many times the game renders to the screen in a second) + * - UPS: Updates Per Second (how many times the game updates in a second) + * + * FPS can be configured with "FastJEngine#setTargetFPS". + * UPS can be configured with "FastJEngine#setTargetUPS". + * + * FPS defaults to the refresh rate of your default monitor -- check your monitor's specifications to determine + * what this value is. On the other hand, UPS defaults to 60. */ + FastJEngine.setTargetFPS(60); + FastJEngine.setTargetUPS(30); + + FastJEngine.run(); + } +} diff --git a/src/example/java/tech/fastj/example/hellofastj/Main.java b/src/example/java/tech/fastj/example/hellofastj/Main.java index 304b10df..2ea3988a 100644 --- a/src/example/java/tech/fastj/example/hellofastj/Main.java +++ b/src/example/java/tech/fastj/example/hellofastj/Main.java @@ -9,13 +9,41 @@ public class Main extends SimpleManager { @Override public void init(Display display) { + // Empty -- this example does not make use of this method. } @Override public void update(Display display) { + // Empty -- this example does not make use of this method. } public static void main(String[] args) { + /* Hello, FastJ! */ + + /* Welcome, travelers. it seems you've wandered far enough off the beaten path to find this + * game engine. For that, I thank you for coming and I commend your efforts in finding us. + * My name is Andrew, and I'll be your guide through these examples. It's a pleasure to + * meet you! + * + * Introductions aside, FastJ's very simple to start off with. This entire source file is + * all you'd need in order to create an empty screen for FastJ. + * + * "FastJEngine#init" initializes the game engine with a name (String) and a logic manager. + * The name is fairly self-explanatory, and the logic manager is the class used to handle + * all of the things you'd expect a game application to have: + * + * - Loading the Game Logic (handled in the "init" method) + * - Receiving/Processing Input + * - Updating the Game (handled in the "update" method) + * - Rendering the Game + * - Resetting the Game + * + * Note: This example has the Main class (this source file) also be a SimpleManager, + * which is a type of LogicManager where you handle all the game loading and updating in + * the manager itself. + * As such, it's very easy to add an application entrypoint (the main method) here, + * allowing us to contain an entire game in one source file. */ + FastJEngine.init("Hello, FastJ!", new Main()); FastJEngine.run(); } diff --git a/src/example/java/tech/fastj/example/keyboard/Main.java b/src/example/java/tech/fastj/example/keyboard/Main.java new file mode 100644 index 00000000..5eb76d60 --- /dev/null +++ b/src/example/java/tech/fastj/example/keyboard/Main.java @@ -0,0 +1,133 @@ +package tech.fastj.example.keyboard; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.graphics.Display; + +import tech.fastj.systems.control.SimpleManager; +import tech.fastj.systems.input.keyboard.Keyboard; +import tech.fastj.systems.input.keyboard.KeyboardActionListener; +import tech.fastj.systems.input.keyboard.Keys; + +import java.awt.event.KeyEvent; + +public class Main extends SimpleManager { + + @Override + public void init(Display display) { + /* Keyboard */ + + /* Keyboard controls in FastJ can be achieved through a few different methods. + * - Creating a KeyboardActionListener to do actions when a key is pressed/released/etc + * - key listeners can be added to the manager at any time. With that said, most use cases would add the + * listener when the game is being loaded. + * - Polling the Keyboard class directly for key state + * - This tactic works best in methods called often -- such as the update method. + * + * For this example, we'll work with the KeyboardActionListener in the init method, and working with polling in + * the update method. */ + + + /* KeyboardActionListener */ + + /* The KeyboardActionListener class is designed to set up actions depending on keyboard actions from the player. + * It has 4 main methods: + * + * - onKeyDown: this method is called when a key is held down. + * - onKeyRecentlyPressed: this method is called when a key is first pressed. + * - onKeyReleased: this method is called when a key is released. + * - onKeyTyped: this method is called when a key is typed -- first pressed or held down. + * + * To demonstrate each method, I've chosen to log whenever any of the methods is called. Run the program to see + * this in action. */ + + inputManager.addKeyboardActionListener(new KeyboardActionListener() { + @Override + public void onKeyDown() { + FastJEngine.log("Key(s) held down"); + } + + @Override + public void onKeyRecentlyPressed(KeyEvent keyEvent) { + FastJEngine.log("Key " + keyEvent.getKeyChar() + " pressed."); + } + + @Override + public void onKeyReleased(KeyEvent keyEvent) { + FastJEngine.log("Key " + keyEvent.getKeyChar() + " released."); + } + + @Override + public void onKeyTyped(KeyEvent keyEvent) { + FastJEngine.log("Key " + keyEvent.getKeyChar() + " typed."); + } + }); + } + + @Override + public void update(Display display) { + /* Polling Keyboard for key state */ + + /* The Keyboard class has a plethora of methods for checking a key's state. + * + * - Keyboard#isKeyDown: check whether a key is held down. + * - Keyboard#isKeyRecentlyPressed: check whether a key was recently pressed. + * - Keyboard#isKeyRecentlyReleased: check whether a key was recently released. + * - Keyboard#getLastKeyPressed: get the string representation of the last key pressed. + * + * To demonstrate each of these, I've added if statements to check if the key "W" is held, pressed, released, or is the last key pressed. + * */ + + // Furthermore, the Keys class represents the possible keys on the keyboard. + // Make sure to use it when checking for a key's state. + if (Keyboard.isKeyDown(Keys.W)) { + FastJEngine.log("W key is held down"); + } + + if (Keyboard.isKeyRecentlyPressed(Keys.W)) { + FastJEngine.log("W key was pressed"); + } + + if (Keyboard.isKeyRecentlyReleased(Keys.W)) { + FastJEngine.log("W key was released"); + } + + if ("W".equals(Keyboard.getLastKeyPressed())) { + FastJEngine.log("Last key pressed was W"); + } + + /* Checking keys on the keyboard multiple times */ + + /* This system is fine, but is not by itself able to handle keys that exist on the keyboard multiple times, such + * as Shift or Control. + * To account for this, there are versions of the first three methods that take a second parameter that states + * where the key is on the keyboard. + * This extra parameter is the KeyLocation class, and it contains a few options: + * + * - KeyLocation#Standard: keys that only appear on the keyboard once. + * - KeyLocation#Left: keys that appear twice -- specifying the key on the left side of the keyboard. + * - KeyLocation#Right: keys that appear twice -- specifying the key on the right side of the keyboard. + * - KeyLocation#Numpad: keys that appear on the numpad. + * + * To demonstrate this, I've added checks for when: + * - the left shift key is held down + * - the right control key is recently pressed + * - the numpad 4 key is recently released */ + + if (Keyboard.isKeyDown(Keys.Shift, Keyboard.KeyLocation.Left)) { + FastJEngine.log("Left Shift key is held down"); + } + + if (Keyboard.isKeyRecentlyPressed(Keys.Shift, Keyboard.KeyLocation.Right)) { + FastJEngine.log("Right Control key was pressed"); + } + + if (Keyboard.isKeyRecentlyReleased(Keys.Numpad4, Keyboard.KeyLocation.Numpad)) { + FastJEngine.log("Numpad 4 key was released"); + } + } + + public static void main(String[] args) { + FastJEngine.init("Hello, Keyboard Controls!", new Main()); + FastJEngine.run(); + } +} diff --git a/src/example/java/tech/fastj/example/logging/Main.java b/src/example/java/tech/fastj/example/logging/Main.java new file mode 100644 index 00000000..c7f983b0 --- /dev/null +++ b/src/example/java/tech/fastj/example/logging/Main.java @@ -0,0 +1,34 @@ +package tech.fastj.example.logging; + +import tech.fastj.engine.FastJEngine; + +public class Main { + public static void main(String[] args) { + /* FastJ Logging */ + + /* FastJ's logging solution is not very robust just yet. It currently makes use of the + * standard out/err streams (System.out and System.err). While not performant, it is currently sufficient for the engine's usage. */ + + /* First up, "FastJEngine#log". This method prints out in this style: + * "INFO: " */ + + FastJEngine.log("Hello! This is an informational logging statement."); + + /* Next, "FastJEngine#warning". This method prints out in this style: + * "WARNING: " */ + + FastJEngine.warning("Be careful now! This is a warning."); + + /* Lastly, "FastJEngine#error". This method is special, because it not only prints out the + * error -- it crashes the engine with an exception as well. + * This method prints in this style: + * "ERROR: " + * "Exception " */ + + /* Under normal circumstances, this method also requires that you add an exception -- the + * exception that caused a need to call "FastJEngine#error". + * For the sake of demonstration, we will create an exception ourselves. */ + IllegalStateException exampleException = new IllegalStateException("This is an example exception."); + FastJEngine.error("Oh dear, looks like something went wrong. This is an error message.", exampleException); + } +} diff --git a/src/example/java/tech/fastj/example/model2d/Main.java b/src/example/java/tech/fastj/example/model2d/Main.java new file mode 100644 index 00000000..87964d70 --- /dev/null +++ b/src/example/java/tech/fastj/example/model2d/Main.java @@ -0,0 +1,53 @@ +package tech.fastj.example.model2d; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Display; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; +import tech.fastj.graphics.util.DrawUtil; + +import tech.fastj.systems.control.SimpleManager; + +public class Main extends SimpleManager { + + @Override + public void init(Display display) { + /* Model2D */ + + /* WARNING: If you're not familiar with FastJ, you'll need to read through the + * "polygon2d" example first. + * + * In order to create a Model2D, you'll need an array of Polygon2D objects. + * A Model2D is essentially a collection of Polygon2D objects, and it treats those objects + * as one game object. */ + + // We'll create two squares -- just like the ones from the "hellopolygon2d" example. + Pointf[] smallSquareMesh1 = DrawUtil.createBox(0f, 0f, 50f); + Polygon2D smallSquare1 = new Polygon2D(smallSquareMesh1); + + // To visualize the two squares as different, we'll change the second one up a bit. + Pointf[] smallSquareMesh2 = DrawUtil.createBox(50f, 50f, 25f); + Polygon2D smallSquare2 = new Polygon2D(smallSquareMesh2); + + // In order to create our Model2D, we need those squares in an array. + Polygon2D[] smallSquaresArray = {smallSquare1, smallSquare2}; + + // Now, we can create our Model2D object. + Model2D smallSquares = new Model2D(smallSquaresArray); + + /* Super simple! Now, this alone does not cause the model to render to the screen. In order + * for it to be rendered, you need to add it as a game object to the drawable manager. */ + drawableManager.addGameObject(smallSquares); + } + + @Override + public void update(Display display) { + // Empty -- this example does not make use of this method. + } + + public static void main(String[] args) { + FastJEngine.init("Hello, Model2D!", new Main()); + FastJEngine.run(); + } +} diff --git a/src/example/java/tech/fastj/example/modelreadwrite/Main.java b/src/example/java/tech/fastj/example/modelreadwrite/Main.java new file mode 100644 index 00000000..09c87f8b --- /dev/null +++ b/src/example/java/tech/fastj/example/modelreadwrite/Main.java @@ -0,0 +1,87 @@ +package tech.fastj.example.modelreadwrite; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; +import tech.fastj.graphics.util.DrawUtil; +import tech.fastj.graphics.util.PsdfUtil; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class Main { + public static void main(String[] args) { + /* Model Reading/Writing */ + + /* WARNING: If you're not familiar with FastJ, you'll need to read through the + * "model2d" example first. + * + * Creating models from pure code is convenient, but quite cumbersome to read through. Let's + * learn how to read and write them to a file format instead. */ + + // We'll start with the model code from the "model2d" example. + Pointf[] smallSquareMesh1 = DrawUtil.createBox(0f, 0f, 50f); + Polygon2D smallSquare1 = new Polygon2D(smallSquareMesh1); + + Pointf[] smallSquareMesh2 = DrawUtil.createBox(50f, 50f, 25f); + Polygon2D smallSquare2 = new Polygon2D(smallSquareMesh2); + + Polygon2D[] smallSquaresArray = {smallSquare1, smallSquare2}; + Model2D smallSquares = new Model2D(smallSquaresArray); + + + /* Now that that's out of the way, let's write this Model2D to a file. + * DrawUtil contains the function for writing Model2D objects to a file. With this, we'll + * write the file, and then print out the contents. + * + * Model2D objects can be written to the PSDF (Polygon Structural Data Format) format, + * which is a format written specifically for use with the FastJ engine. + * At a later point in time, the engine will support writing Model2D objects to more + * standard formats, but until then we'll be using the PSDF format. + */ + + + /* This is the path which we will be writing to. It resolves to + * "src/example/resources/modelreadwrite/smallSquares.psdf". */ + String smallSquaresFilePath = "src/example/resources/modelreadwrite/smallSquares.psdf"; + + // And now, we can call the model-writing method. + PsdfUtil.writePsdf(smallSquaresFilePath, smallSquares); + + + /* As a small aside, this gets the file and prints out its contents. + * The code is not the primary focus of the example -- this is just to give a visual. */ + try { + String smallSquaresFileContents = Files.readString(Path.of(smallSquaresFilePath)); + FastJEngine.log("Contents of smallSquares.psdf: \n" + smallSquaresFileContents); + } catch (IOException exception) { + exception.printStackTrace(); + } + + + /* Next up, we'll read the file back. + * Since we already have the string denoting the location of the file, we can reuse it. */ + Polygon2D[] smallSquaresArrayFromFile = PsdfUtil.loadPsdf(smallSquaresFilePath); + + // We can use this to create a new Model2D. + Model2D smallSquaresFromFile = new Model2D(smallSquaresArrayFromFile); + + /* Here, we check for equality between the original and the read file. + * As expected, the two contain the exact same contents. */ + FastJEngine.log("smallSquaresfromFile == smallSquares? " + smallSquaresFromFile.equals(smallSquares)); + + + /* Another small aside: this removes the file we created earlier in the program. + * This code is not the primary focus of the example -- it's just to clean up the work we did. */ + try { + boolean wasDeleted = Files.deleteIfExists(Path.of(smallSquaresFilePath)); + if (!wasDeleted) { + FastJEngine.warning("The file at \"" + smallSquaresFilePath + "\" was not deleted."); + } + } catch (IOException exception) { + exception.printStackTrace(); + } + } +} diff --git a/src/example/java/tech/fastj/example/polygon2d/Main.java b/src/example/java/tech/fastj/example/polygon2d/Main.java new file mode 100644 index 00000000..49869bcf --- /dev/null +++ b/src/example/java/tech/fastj/example/polygon2d/Main.java @@ -0,0 +1,92 @@ +package tech.fastj.example.polygon2d; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Display; +import tech.fastj.graphics.game.Polygon2D; +import tech.fastj.graphics.util.DrawUtil; + +import tech.fastj.systems.control.SimpleManager; + +import java.awt.Color; + +public class Main extends SimpleManager { + + @Override + public void init(Display display) { + /* Polygon2D */ + + /* In order to create a Polygon2D, you first need to create a mesh. + * A mesh is essentially an array of "Pointf"s (vectors) that form a shape when drawn in + * order. This mesh is the base upon which the Polygon2D can be constructed, and defines + * what sort of shape gets drawn to the screen. */ + + // You can create a mesh by hand... + Pointf[] smallSquareMeshByHand = { + new Pointf(0f, 0f), + new Pointf(0f, 50f), + new Pointf(50f, 50f), + new Pointf(50f, 0f) + }; + + // ...or by using one of the many "DrawUtil.create" methods. + Pointf[] smallSquareMeshFromDrawUtil = DrawUtil.createBox(0f, 0f, 50f); + + /* The two meshes above result in the exact same thing: a square at the point (0, 0) with a + * size of 50. */ + + + /* Now, we can create our Polygon2D. We'll use smallSquareMeshByHand for right now, but you + * should try switching from it to smallSquareMeshFromDrawUtil to see what happens! */ + Polygon2D smallSquare = new Polygon2D(smallSquareMeshByHand); + + /* Super simple! Now, this alone does not cause the square to render to the screen. In + * order for it to be rendered, you need to add it as a game object to the drawable + * manager. */ + drawableManager.addGameObject(smallSquare); + + /* If you comment out the line above, you'll see that the small square does not get + * rendered. */ + + + /* You can set the following properties of a Polygon2D: + * - Mesh (Pointf[]) + * - Paint (solid color, gradient) + * - PaintFilled (render the outline or fill) + * - Rotation + * - Scale + * - Translation + * + * To show this off, we'll create a larger square with the following property values: + * - Square mesh at (625, 25) with a size of 47.9 + * - Blue color + * - Outline + * - Rotation of 30 degrees + * - Scaled to 50% (0.5) + * - Translated by (20, 10) */ + Pointf[] largeSquareMesh = DrawUtil.createBox(625f, 25.5f, 47.9f); + Polygon2D largeSquare = new Polygon2D(largeSquareMesh) + .setPaint(Color.blue) + .setFilled(false); + + /* As you can see from the code above, many of the methods Polygon2D contains allow for + * method chaining. + * From the code below, you can see that other methods do not. */ + + largeSquare.rotate(30f); + largeSquare.scale(new Pointf(0.5f, 0.5f)); + largeSquare.translate(new Pointf(20f, 10f)); + + drawableManager.addGameObject(largeSquare); + } + + @Override + public void update(Display display) { + // Empty -- this example does not make use of this method. + } + + public static void main(String[] args) { + FastJEngine.init("Hello, Polygon2D!", new Main()); + FastJEngine.run(); + } +} diff --git a/src/example/java/tech/fastj/example/text2d/Main.java b/src/example/java/tech/fastj/example/text2d/Main.java new file mode 100644 index 00000000..cc4779e4 --- /dev/null +++ b/src/example/java/tech/fastj/example/text2d/Main.java @@ -0,0 +1,58 @@ +package tech.fastj.example.text2d; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Display; +import tech.fastj.graphics.game.Text2D; + +import tech.fastj.systems.control.SimpleManager; + +public class Main extends SimpleManager { + + @Override + public void init(Display display) { + /* Text2D */ + + /* In order to create a Text2D, you will need two things: + * 1. A message, or some text to display. + * 2. A location for the message to be rendered at. */ + + // The message is pretty simple -- just a String containing text. + String messageString = "Hello, FastJ Text2D!"; + + /* The location is fairly simple as well -- just a Pointf containing the x and y location. + * + * For the sake of clarification, a Pointf is a 2D vector containing x and y variables. + * In this case, "messageLocation" represents the point (0, 25) in the 2D coordinate space. + * + * Note: Text2D render differently from polygons. They are rendered such that the y + * location represents the bottom of the text shown. + * One good way to account for this is to add the size of the font to the y position. Since + * we did not create a custom font for the Text2D, we can use the size of the default font, + * "Text2D#DefaultFont#getSize()". */ + Pointf messageLocation = new Pointf(0f, 0f + Text2D.DefaultFont.getSize()); + + + // Now, we put it all together! + Text2D message = new Text2D(messageString, messageLocation); + + /* Super simple! Now, this alone does not cause the text to render to the screen. In order + * for it to be rendered, you need to add it as a game object to the drawable manager. */ + drawableManager.addGameObject(message); + + /* If you comment out the line above, you'll see that the text does not get rendered. */ + + + /* */ + } + + @Override + public void update(Display display) { + // Empty -- this example does not make use of this method. + } + + public static void main(String[] args) { + FastJEngine.init("Hello, Text2D!", new Main()); + FastJEngine.run(); + } +} diff --git a/src/main/java/tech/fastj/engine/FastJEngine.java b/src/main/java/tech/fastj/engine/FastJEngine.java index 494c5891..4469d69c 100644 --- a/src/main/java/tech/fastj/engine/FastJEngine.java +++ b/src/main/java/tech/fastj/engine/FastJEngine.java @@ -350,7 +350,7 @@ public static void closeGame() { * as possible, without waiting for the next game update/render to be finished. */ public static void forceCloseGame() { - if (display != null) { + if (display != null && display.isReady()) { display.close(); } exit(); diff --git a/src/main/java/tech/fastj/systems/behaviors/BehaviorHandler.java b/src/main/java/tech/fastj/systems/behaviors/BehaviorHandler.java index ad25326b..c81a1561 100644 --- a/src/main/java/tech/fastj/systems/behaviors/BehaviorHandler.java +++ b/src/main/java/tech/fastj/systems/behaviors/BehaviorHandler.java @@ -6,7 +6,7 @@ /** * Interface denoting that the implementing classes directly interface with the {@link BehaviorManager} class. - * + *

* FOR IMPLEMENTORS: In order for these methods to work you need to call {@link * BehaviorManager#addListenerList(BehaviorHandler)} upon construction. */ diff --git a/src/main/java/tech/fastj/systems/control/SimpleManager.java b/src/main/java/tech/fastj/systems/control/SimpleManager.java index 14dd0509..fe207f6a 100644 --- a/src/main/java/tech/fastj/systems/control/SimpleManager.java +++ b/src/main/java/tech/fastj/systems/control/SimpleManager.java @@ -44,11 +44,13 @@ public void render(Display display) { ); } + /** Processes all stored input events. */ @Override public void processInputEvents() { inputManager.processEvents(); } + /** Stores the specified input event to be processed later ({@link #processInputEvents()}). */ @Override public void receivedInputEvent(InputEvent inputEvent) { inputManager.receivedInputEvent(inputEvent); diff --git a/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java b/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java index 3456be1d..d7fcc585 100644 --- a/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java +++ b/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java @@ -226,9 +226,11 @@ public static boolean areKeysDown() { public static void stop() { reset(); + if (keyChecker != null) { keyChecker.shutdownNow(); } + keyChecker = null; } @Override diff --git a/src/main/java/tech/fastj/systems/tags/TagHandler.java b/src/main/java/tech/fastj/systems/tags/TagHandler.java index d9cd61bb..75e37437 100644 --- a/src/main/java/tech/fastj/systems/tags/TagHandler.java +++ b/src/main/java/tech/fastj/systems/tags/TagHandler.java @@ -8,7 +8,7 @@ /** * Interface denoting that the implementing classes directly interface with the {@link BehaviorManager} class. - * + *

* FOR IMPLEMENTORS: In order for these methods to work you need to call {@link * TagManager#addTaggableEntityList(TagHandler)} upon construction. */