From 0a6398ea0ac1575775d197817c6c3219c7835203 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 23 May 2021 23:00:20 -0400 Subject: [PATCH 01/27] fixed issue with force closing FastJ when game engine has not been initialized `Keyboard.stop()` would try to call a method on `keyChecker`, but keyChecker had not been initialized yet. As such, it causes a null pointer. To fix this, I've changed `keyChecker` to a final variable called `KeyChecker`, similar to that of `Mouse#MouseExecutor`. --- .../lucasstarsz/fastj/systems/input/keyboard/Keyboard.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/lucasstarsz/fastj/systems/input/keyboard/Keyboard.java b/src/main/java/io/github/lucasstarsz/fastj/systems/input/keyboard/Keyboard.java index 55636060..e9560958 100644 --- a/src/main/java/io/github/lucasstarsz/fastj/systems/input/keyboard/Keyboard.java +++ b/src/main/java/io/github/lucasstarsz/fastj/systems/input/keyboard/Keyboard.java @@ -23,7 +23,7 @@ public class Keyboard implements KeyListener { private static final Map Keys = new HashMap<>(); private static String lastKeyPressed = ""; - private static ScheduledExecutorService keyChecker; + private static final ScheduledExecutorService KeyChecker = Executors.newSingleThreadScheduledExecutor(); private static final Map> KeyEventProcessor = Map.of( KeyEvent.KEY_PRESSED, (inputManager, keyEvent) -> { @@ -67,8 +67,7 @@ public class Keyboard implements KeyListener { /** Initializes the keyboard. */ public static void init() { - keyChecker = Executors.newSingleThreadScheduledExecutor(); - keyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); + KeyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); } /** Updates each key if it was recently pressed. */ @@ -226,7 +225,7 @@ public static boolean areKeysDown() { public static void stop() { reset(); - keyChecker.shutdownNow(); + KeyChecker.shutdownNow(); } @Override From c1e99e6092c1f1d75fe714da6d5e7dea228c536a Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 11:25:14 -0400 Subject: [PATCH 02/27] added commentary Also added some stray documentation to SimpleManager --- .../fastj/example/hellofastj/Main.java | 28 +++++++++++++++++++ .../fastj/systems/control/SimpleManager.java | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/example/java/io/github/lucasstarsz/fastj/example/hellofastj/Main.java b/src/example/java/io/github/lucasstarsz/fastj/example/hellofastj/Main.java index f6ba3242..8d30c981 100644 --- a/src/example/java/io/github/lucasstarsz/fastj/example/hellofastj/Main.java +++ b/src/example/java/io/github/lucasstarsz/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/main/java/io/github/lucasstarsz/fastj/systems/control/SimpleManager.java b/src/main/java/io/github/lucasstarsz/fastj/systems/control/SimpleManager.java index 675dd13b..c19f5d16 100644 --- a/src/main/java/io/github/lucasstarsz/fastj/systems/control/SimpleManager.java +++ b/src/main/java/io/github/lucasstarsz/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); From b21a591790a9886c66010ebe4603659158eafd43 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 12:54:04 -0400 Subject: [PATCH 03/27] small documentation fixes --- .../lucasstarsz/fastj/systems/behaviors/BehaviorHandler.java | 2 +- .../io/github/lucasstarsz/fastj/systems/tags/TagHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/lucasstarsz/fastj/systems/behaviors/BehaviorHandler.java b/src/main/java/io/github/lucasstarsz/fastj/systems/behaviors/BehaviorHandler.java index 1a59497e..c1709d94 100644 --- a/src/main/java/io/github/lucasstarsz/fastj/systems/behaviors/BehaviorHandler.java +++ b/src/main/java/io/github/lucasstarsz/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/io/github/lucasstarsz/fastj/systems/tags/TagHandler.java b/src/main/java/io/github/lucasstarsz/fastj/systems/tags/TagHandler.java index 5382917e..24359e1c 100644 --- a/src/main/java/io/github/lucasstarsz/fastj/systems/tags/TagHandler.java +++ b/src/main/java/io/github/lucasstarsz/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. */ From e612befbeca69f97ef605841f933078d7ba4ea4b Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 04/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- .../fastj/example/fastjengineconfig/Main.java | 80 ++++++++++++++++ .../fastj/example/logging/Main.java | 34 +++++++ .../fastj/example/model2d/Main.java | 52 +++++++++++ .../fastj/example/modelreadwrite/Main.java | 86 +++++++++++++++++ .../fastj/example/polygon2d/Main.java | 92 +++++++++++++++++++ .../fastj/example/text2d/Main.java | 58 ++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 src/example/java/io/github/lucasstarsz/fastj/example/fastjengineconfig/Main.java create mode 100644 src/example/java/io/github/lucasstarsz/fastj/example/logging/Main.java create mode 100644 src/example/java/io/github/lucasstarsz/fastj/example/model2d/Main.java create mode 100644 src/example/java/io/github/lucasstarsz/fastj/example/modelreadwrite/Main.java create mode 100644 src/example/java/io/github/lucasstarsz/fastj/example/polygon2d/Main.java create mode 100644 src/example/java/io/github/lucasstarsz/fastj/example/text2d/Main.java diff --git a/src/example/java/io/github/lucasstarsz/fastj/example/fastjengineconfig/Main.java b/src/example/java/io/github/lucasstarsz/fastj/example/fastjengineconfig/Main.java new file mode 100644 index 00000000..3f63f01a --- /dev/null +++ b/src/example/java/io/github/lucasstarsz/fastj/example/fastjengineconfig/Main.java @@ -0,0 +1,80 @@ +package io.github.lucasstarsz.fastj.example.fastjengineconfig; + +import io.github.lucasstarsz.fastj.engine.FastJEngine; +import io.github.lucasstarsz.fastj.engine.HWAccel; +import io.github.lucasstarsz.fastj.math.Point; +import io.github.lucasstarsz.fastj.math.Pointf; +import io.github.lucasstarsz.fastj.graphics.Display; +import io.github.lucasstarsz.fastj.graphics.DrawUtil; +import io.github.lucasstarsz.fastj.graphics.game.Polygon2D; + +import io.github.lucasstarsz.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); + + + FastJEngine.run(); + } +} diff --git a/src/example/java/io/github/lucasstarsz/fastj/example/logging/Main.java b/src/example/java/io/github/lucasstarsz/fastj/example/logging/Main.java new file mode 100644 index 00000000..7aab9e78 --- /dev/null +++ b/src/example/java/io/github/lucasstarsz/fastj/example/logging/Main.java @@ -0,0 +1,34 @@ +package io.github.lucasstarsz.fastj.example.logging; + +import io.github.lucasstarsz.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/io/github/lucasstarsz/fastj/example/model2d/Main.java b/src/example/java/io/github/lucasstarsz/fastj/example/model2d/Main.java new file mode 100644 index 00000000..e8a9dfbc --- /dev/null +++ b/src/example/java/io/github/lucasstarsz/fastj/example/model2d/Main.java @@ -0,0 +1,52 @@ +package io.github.lucasstarsz.fastj.example.model2d; + +import io.github.lucasstarsz.fastj.engine.FastJEngine; +import io.github.lucasstarsz.fastj.math.Pointf; +import io.github.lucasstarsz.fastj.graphics.Display; +import io.github.lucasstarsz.fastj.graphics.DrawUtil; +import io.github.lucasstarsz.fastj.graphics.game.Model2D; +import io.github.lucasstarsz.fastj.graphics.game.Polygon2D; + +import io.github.lucasstarsz.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/io/github/lucasstarsz/fastj/example/modelreadwrite/Main.java b/src/example/java/io/github/lucasstarsz/fastj/example/modelreadwrite/Main.java new file mode 100644 index 00000000..9947e92a --- /dev/null +++ b/src/example/java/io/github/lucasstarsz/fastj/example/modelreadwrite/Main.java @@ -0,0 +1,86 @@ +package io.github.lucasstarsz.fastj.example.modelreadwrite; + +import io.github.lucasstarsz.fastj.engine.FastJEngine; +import io.github.lucasstarsz.fastj.math.Pointf; +import io.github.lucasstarsz.fastj.graphics.DrawUtil; +import io.github.lucasstarsz.fastj.graphics.game.Model2D; +import io.github.lucasstarsz.fastj.graphics.game.Polygon2D; + +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. + DrawUtil.writeToPSDF(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 = DrawUtil.load2DModel(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/io/github/lucasstarsz/fastj/example/polygon2d/Main.java b/src/example/java/io/github/lucasstarsz/fastj/example/polygon2d/Main.java new file mode 100644 index 00000000..294127dc --- /dev/null +++ b/src/example/java/io/github/lucasstarsz/fastj/example/polygon2d/Main.java @@ -0,0 +1,92 @@ +package io.github.lucasstarsz.fastj.example.polygon2d; + +import io.github.lucasstarsz.fastj.engine.FastJEngine; +import io.github.lucasstarsz.fastj.math.Pointf; +import io.github.lucasstarsz.fastj.graphics.Display; +import io.github.lucasstarsz.fastj.graphics.DrawUtil; +import io.github.lucasstarsz.fastj.graphics.game.Polygon2D; + +import io.github.lucasstarsz.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[]) + * - Color + * - 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) + .setColor(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/io/github/lucasstarsz/fastj/example/text2d/Main.java b/src/example/java/io/github/lucasstarsz/fastj/example/text2d/Main.java new file mode 100644 index 00000000..3e3ea500 --- /dev/null +++ b/src/example/java/io/github/lucasstarsz/fastj/example/text2d/Main.java @@ -0,0 +1,58 @@ +package io.github.lucasstarsz.fastj.example.text2d; + +import io.github.lucasstarsz.fastj.engine.FastJEngine; +import io.github.lucasstarsz.fastj.math.Pointf; +import io.github.lucasstarsz.fastj.graphics.Display; +import io.github.lucasstarsz.fastj.graphics.game.Text2D; + +import io.github.lucasstarsz.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(); + } +} From 261138aa711cb177a537fed0638df3cbee62d2b1 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 23 May 2021 23:00:20 -0400 Subject: [PATCH 05/27] fixed issue with force closing FastJ when game engine has not been initialized `Keyboard.stop()` would try to call a method on `keyChecker`, but keyChecker had not been initialized yet. As such, it causes a null pointer. To fix this, I've changed `keyChecker` to a final variable called `KeyChecker`, similar to that of `Mouse#MouseExecutor`. --- .../java/tech/fastj/systems/input/keyboard/Keyboard.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 6c5c822c..daf08d7e 100644 --- a/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java +++ b/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java @@ -23,7 +23,7 @@ public class Keyboard implements KeyListener { private static final Map Keys = new HashMap<>(); private static String lastKeyPressed = ""; - private static ScheduledExecutorService keyChecker; + private static final ScheduledExecutorService KeyChecker = Executors.newSingleThreadScheduledExecutor(); private static final Map> KeyEventProcessor = Map.of( KeyEvent.KEY_PRESSED, (inputManager, keyEvent) -> { @@ -67,8 +67,7 @@ public class Keyboard implements KeyListener { /** Initializes the keyboard. */ public static void init() { - keyChecker = Executors.newSingleThreadScheduledExecutor(); - keyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); + KeyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); } /** Updates each key if it was recently pressed. */ @@ -226,7 +225,7 @@ public static boolean areKeysDown() { public static void stop() { reset(); - keyChecker.shutdownNow(); + KeyChecker.shutdownNow(); } @Override From d9a34c53fb72d764f4931672e67f9c630fc4c54f Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 11:25:14 -0400 Subject: [PATCH 06/27] added commentary Also added some stray documentation to SimpleManager --- .../tech/fastj/example/hellofastj/Main.java | 28 +++++++++++++++++++ .../fastj/systems/control/SimpleManager.java | 2 ++ 2 files changed, 30 insertions(+) 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/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); From 0d2c99a77667201a65471330bdc1af396f4fb5cd Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 12:54:04 -0400 Subject: [PATCH 07/27] small documentation fixes --- src/main/java/tech/fastj/systems/behaviors/BehaviorHandler.java | 2 +- src/main/java/tech/fastj/systems/tags/TagHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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. */ From 0ac5fa40fdc4f3812e34928434206282c27ce249 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 08/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- .../fastj/example/fastjengineconfig/Main.java | 80 ++++++++++++++++ .../java/tech/fastj/example/logging/Main.java | 34 +++++++ .../java/tech/fastj/example/model2d/Main.java | 52 +++++++++++ .../fastj/example/modelreadwrite/Main.java | 86 +++++++++++++++++ .../tech/fastj/example/polygon2d/Main.java | 92 +++++++++++++++++++ .../java/tech/fastj/example/text2d/Main.java | 58 ++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 src/example/java/tech/fastj/example/fastjengineconfig/Main.java create mode 100644 src/example/java/tech/fastj/example/logging/Main.java create mode 100644 src/example/java/tech/fastj/example/model2d/Main.java create mode 100644 src/example/java/tech/fastj/example/modelreadwrite/Main.java create mode 100644 src/example/java/tech/fastj/example/polygon2d/Main.java create mode 100644 src/example/java/tech/fastj/example/text2d/Main.java diff --git a/src/example/java/tech/fastj/example/fastjengineconfig/Main.java b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java new file mode 100644 index 00000000..93537406 --- /dev/null +++ b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java @@ -0,0 +1,80 @@ +package tech.fastj.example.fastjengineconfig; + +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.DrawUtil; +import tech.fastj.graphics.game.Polygon2D; + +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); + + + 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..68967b70 --- /dev/null +++ b/src/example/java/tech/fastj/example/model2d/Main.java @@ -0,0 +1,52 @@ +package tech.fastj.example.model2d; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Display; +import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; + +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..289a7a71 --- /dev/null +++ b/src/example/java/tech/fastj/example/modelreadwrite/Main.java @@ -0,0 +1,86 @@ +package tech.fastj.example.modelreadwrite; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; + +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. + DrawUtil.writeToPSDF(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 = DrawUtil.load2DModel(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..97199ebe --- /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.DrawUtil; +import tech.fastj.graphics.game.Polygon2D; + +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[]) + * - Color + * - 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) + .setColor(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(); + } +} From 6da0fa59adf98b67f56f4749d99569fe43056a96 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 23 May 2021 23:00:20 -0400 Subject: [PATCH 09/27] fixed issue with force closing FastJ when game engine has not been initialized `Keyboard.stop()` would try to call a method on `keyChecker`, but keyChecker had not been initialized yet. As such, it causes a null pointer. To fix this, I've changed `keyChecker` to a final variable `KeyChecker`, similar to that of `Mouse#MouseExecutor`. --- .../java/tech/fastj/systems/input/keyboard/Keyboard.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) 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..daf08d7e 100644 --- a/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java +++ b/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java @@ -23,7 +23,7 @@ public class Keyboard implements KeyListener { private static final Map Keys = new HashMap<>(); private static String lastKeyPressed = ""; - private static ScheduledExecutorService keyChecker; + private static final ScheduledExecutorService KeyChecker = Executors.newSingleThreadScheduledExecutor(); private static final Map> KeyEventProcessor = Map.of( KeyEvent.KEY_PRESSED, (inputManager, keyEvent) -> { @@ -67,8 +67,7 @@ public class Keyboard implements KeyListener { /** Initializes the keyboard. */ public static void init() { - keyChecker = Executors.newSingleThreadScheduledExecutor(); - keyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); + KeyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); } /** Updates each key if it was recently pressed. */ @@ -226,9 +225,7 @@ public static boolean areKeysDown() { public static void stop() { reset(); - if (keyChecker != null) { - keyChecker.shutdownNow(); - } + KeyChecker.shutdownNow(); } @Override From 719bcf47ba0a51e31c0adfaed2ebf56342d2bbd6 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 11:25:14 -0400 Subject: [PATCH 10/27] added commentary Also added some stray documentation to SimpleManager --- .../tech/fastj/example/hellofastj/Main.java | 28 +++++++++++++++++++ .../fastj/systems/control/SimpleManager.java | 2 ++ 2 files changed, 30 insertions(+) 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/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); From 25e6c04dbaf7da9e904a9eae91b8091754d19cbb Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 12:54:04 -0400 Subject: [PATCH 11/27] small documentation fixes --- src/main/java/tech/fastj/systems/behaviors/BehaviorHandler.java | 2 +- src/main/java/tech/fastj/systems/tags/TagHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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. */ From 7e326e6c132769577e12665f7d711dbb2b063608 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 12/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- .../fastj/example/fastjengineconfig/Main.java | 80 ++++++++++++++++ .../java/tech/fastj/example/logging/Main.java | 34 +++++++ .../java/tech/fastj/example/model2d/Main.java | 52 +++++++++++ .../fastj/example/modelreadwrite/Main.java | 86 +++++++++++++++++ .../tech/fastj/example/polygon2d/Main.java | 92 +++++++++++++++++++ .../java/tech/fastj/example/text2d/Main.java | 58 ++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 src/example/java/tech/fastj/example/fastjengineconfig/Main.java create mode 100644 src/example/java/tech/fastj/example/logging/Main.java create mode 100644 src/example/java/tech/fastj/example/model2d/Main.java create mode 100644 src/example/java/tech/fastj/example/modelreadwrite/Main.java create mode 100644 src/example/java/tech/fastj/example/polygon2d/Main.java create mode 100644 src/example/java/tech/fastj/example/text2d/Main.java diff --git a/src/example/java/tech/fastj/example/fastjengineconfig/Main.java b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java new file mode 100644 index 00000000..93537406 --- /dev/null +++ b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java @@ -0,0 +1,80 @@ +package tech.fastj.example.fastjengineconfig; + +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.DrawUtil; +import tech.fastj.graphics.game.Polygon2D; + +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); + + + 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..68967b70 --- /dev/null +++ b/src/example/java/tech/fastj/example/model2d/Main.java @@ -0,0 +1,52 @@ +package tech.fastj.example.model2d; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Display; +import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; + +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..289a7a71 --- /dev/null +++ b/src/example/java/tech/fastj/example/modelreadwrite/Main.java @@ -0,0 +1,86 @@ +package tech.fastj.example.modelreadwrite; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; + +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. + DrawUtil.writeToPSDF(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 = DrawUtil.load2DModel(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..97199ebe --- /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.DrawUtil; +import tech.fastj.graphics.game.Polygon2D; + +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[]) + * - Color + * - 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) + .setColor(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(); + } +} From bb874920388110901df29158c8e6625ce0527c31 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 13/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- src/example/java/tech/fastj/example/model2d/Main.java | 2 +- src/example/java/tech/fastj/example/polygon2d/Main.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/example/java/tech/fastj/example/model2d/Main.java b/src/example/java/tech/fastj/example/model2d/Main.java index 68967b70..149cefa1 100644 --- a/src/example/java/tech/fastj/example/model2d/Main.java +++ b/src/example/java/tech/fastj/example/model2d/Main.java @@ -3,7 +3,7 @@ import tech.fastj.engine.FastJEngine; import tech.fastj.math.Pointf; import tech.fastj.graphics.Display; -import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.util.DrawUtil; import tech.fastj.graphics.game.Model2D; import tech.fastj.graphics.game.Polygon2D; diff --git a/src/example/java/tech/fastj/example/polygon2d/Main.java b/src/example/java/tech/fastj/example/polygon2d/Main.java index 97199ebe..d326c612 100644 --- a/src/example/java/tech/fastj/example/polygon2d/Main.java +++ b/src/example/java/tech/fastj/example/polygon2d/Main.java @@ -3,7 +3,7 @@ import tech.fastj.engine.FastJEngine; import tech.fastj.math.Pointf; import tech.fastj.graphics.Display; -import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.util.DrawUtil; import tech.fastj.graphics.game.Polygon2D; import tech.fastj.systems.control.SimpleManager; @@ -51,7 +51,7 @@ public void init(Display display) { /* You can set the following properties of a Polygon2D: * - Mesh (Pointf[]) - * - Color + * - Paint (solid color, gradient) * - PaintFilled (render the outline or fill) * - Rotation * - Scale @@ -66,7 +66,7 @@ public void init(Display display) { * - Translated by (20, 10) */ Pointf[] largeSquareMesh = DrawUtil.createBox(625f, 25.5f, 47.9f); Polygon2D largeSquare = new Polygon2D(largeSquareMesh) - .setColor(Color.blue) + .setPaint(Color.blue) .setFilled(false); /* As you can see from the code above, many of the methods Polygon2D contains allow for From 65ff60df8bbac1fdcf5cbd0ab20bdc9d08c64e53 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 23 May 2021 23:00:20 -0400 Subject: [PATCH 14/27] fixed issue with force closing FastJ when game engine has not been initialized `Keyboard.stop()` would try to call a method on `keyChecker`, but keyChecker had not been initialized yet. As such, it causes a null pointer. To fix this, I've changed `keyChecker` to a final variable `KeyChecker`, similar to that of `Mouse#MouseExecutor`. --- .../java/tech/fastj/systems/input/keyboard/Keyboard.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) 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..daf08d7e 100644 --- a/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java +++ b/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java @@ -23,7 +23,7 @@ public class Keyboard implements KeyListener { private static final Map Keys = new HashMap<>(); private static String lastKeyPressed = ""; - private static ScheduledExecutorService keyChecker; + private static final ScheduledExecutorService KeyChecker = Executors.newSingleThreadScheduledExecutor(); private static final Map> KeyEventProcessor = Map.of( KeyEvent.KEY_PRESSED, (inputManager, keyEvent) -> { @@ -67,8 +67,7 @@ public class Keyboard implements KeyListener { /** Initializes the keyboard. */ public static void init() { - keyChecker = Executors.newSingleThreadScheduledExecutor(); - keyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); + KeyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); } /** Updates each key if it was recently pressed. */ @@ -226,9 +225,7 @@ public static boolean areKeysDown() { public static void stop() { reset(); - if (keyChecker != null) { - keyChecker.shutdownNow(); - } + KeyChecker.shutdownNow(); } @Override From 0aee606b15d59fb83343dbaf2f129b479c543a67 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 11:25:14 -0400 Subject: [PATCH 15/27] added commentary Also added some stray documentation to SimpleManager --- .../tech/fastj/example/hellofastj/Main.java | 28 +++++++++++++++++++ .../fastj/systems/control/SimpleManager.java | 2 ++ 2 files changed, 30 insertions(+) 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/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); From 71dbc373aae25b09e15b2e5ff83e9f3906b349f4 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Mon, 24 May 2021 12:54:04 -0400 Subject: [PATCH 16/27] small documentation fixes --- src/main/java/tech/fastj/systems/behaviors/BehaviorHandler.java | 2 +- src/main/java/tech/fastj/systems/tags/TagHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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. */ From 2475068969637aa6e154a8f84e01c190d421f623 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 17/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- .../fastj/example/fastjengineconfig/Main.java | 80 ++++++++++++++++ .../java/tech/fastj/example/logging/Main.java | 34 +++++++ .../java/tech/fastj/example/model2d/Main.java | 52 +++++++++++ .../fastj/example/modelreadwrite/Main.java | 86 +++++++++++++++++ .../tech/fastj/example/polygon2d/Main.java | 92 +++++++++++++++++++ .../java/tech/fastj/example/text2d/Main.java | 58 ++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 src/example/java/tech/fastj/example/fastjengineconfig/Main.java create mode 100644 src/example/java/tech/fastj/example/logging/Main.java create mode 100644 src/example/java/tech/fastj/example/model2d/Main.java create mode 100644 src/example/java/tech/fastj/example/modelreadwrite/Main.java create mode 100644 src/example/java/tech/fastj/example/polygon2d/Main.java create mode 100644 src/example/java/tech/fastj/example/text2d/Main.java diff --git a/src/example/java/tech/fastj/example/fastjengineconfig/Main.java b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java new file mode 100644 index 00000000..93537406 --- /dev/null +++ b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java @@ -0,0 +1,80 @@ +package tech.fastj.example.fastjengineconfig; + +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.DrawUtil; +import tech.fastj.graphics.game.Polygon2D; + +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); + + + 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..68967b70 --- /dev/null +++ b/src/example/java/tech/fastj/example/model2d/Main.java @@ -0,0 +1,52 @@ +package tech.fastj.example.model2d; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Display; +import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; + +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..289a7a71 --- /dev/null +++ b/src/example/java/tech/fastj/example/modelreadwrite/Main.java @@ -0,0 +1,86 @@ +package tech.fastj.example.modelreadwrite; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.game.Model2D; +import tech.fastj.graphics.game.Polygon2D; + +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. + DrawUtil.writeToPSDF(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 = DrawUtil.load2DModel(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..97199ebe --- /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.DrawUtil; +import tech.fastj.graphics.game.Polygon2D; + +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[]) + * - Color + * - 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) + .setColor(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(); + } +} From b3634ad5691c58bef5b5b5bd4a615e1b4c3a360b Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 18/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- src/example/java/tech/fastj/example/model2d/Main.java | 2 +- src/example/java/tech/fastj/example/polygon2d/Main.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/example/java/tech/fastj/example/model2d/Main.java b/src/example/java/tech/fastj/example/model2d/Main.java index 68967b70..149cefa1 100644 --- a/src/example/java/tech/fastj/example/model2d/Main.java +++ b/src/example/java/tech/fastj/example/model2d/Main.java @@ -3,7 +3,7 @@ import tech.fastj.engine.FastJEngine; import tech.fastj.math.Pointf; import tech.fastj.graphics.Display; -import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.util.DrawUtil; import tech.fastj.graphics.game.Model2D; import tech.fastj.graphics.game.Polygon2D; diff --git a/src/example/java/tech/fastj/example/polygon2d/Main.java b/src/example/java/tech/fastj/example/polygon2d/Main.java index 97199ebe..d326c612 100644 --- a/src/example/java/tech/fastj/example/polygon2d/Main.java +++ b/src/example/java/tech/fastj/example/polygon2d/Main.java @@ -3,7 +3,7 @@ import tech.fastj.engine.FastJEngine; import tech.fastj.math.Pointf; import tech.fastj.graphics.Display; -import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.util.DrawUtil; import tech.fastj.graphics.game.Polygon2D; import tech.fastj.systems.control.SimpleManager; @@ -51,7 +51,7 @@ public void init(Display display) { /* You can set the following properties of a Polygon2D: * - Mesh (Pointf[]) - * - Color + * - Paint (solid color, gradient) * - PaintFilled (render the outline or fill) * - Rotation * - Scale @@ -66,7 +66,7 @@ public void init(Display display) { * - Translated by (20, 10) */ Pointf[] largeSquareMesh = DrawUtil.createBox(625f, 25.5f, 47.9f); Polygon2D largeSquare = new Polygon2D(largeSquareMesh) - .setColor(Color.blue) + .setPaint(Color.blue) .setFilled(false); /* As you can see from the code above, many of the methods Polygon2D contains allow for From 0257128fa8d54d78970c3b35a37c4ea9e1fd2933 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 19/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- src/example/java/tech/fastj/example/polygon2d/Main.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/example/java/tech/fastj/example/polygon2d/Main.java b/src/example/java/tech/fastj/example/polygon2d/Main.java index d326c612..ecc2ac62 100644 --- a/src/example/java/tech/fastj/example/polygon2d/Main.java +++ b/src/example/java/tech/fastj/example/polygon2d/Main.java @@ -51,7 +51,11 @@ public void init(Display display) { /* You can set the following properties of a Polygon2D: * - Mesh (Pointf[]) +<<<<<<< HEAD * - Paint (solid color, gradient) +======= + * - Color +>>>>>>> 0ac5fa4 ((#20) Added examples) * - PaintFilled (render the outline or fill) * - Rotation * - Scale From 66e49a755f62b18b6621f3cbf02a169f899a13da Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Tue, 25 May 2021 00:11:00 -0400 Subject: [PATCH 20/27] (#20) Added examples - polygon2d - Creating Polygon2D objects - text2d - Creating Text2D objects - model2d - Creating Model2D objects - modelreadwrite - Reading & Writing Model2D objects - logging - FastJ logging - fastjengineconfig - FastJEngine Configuration --- .../java/tech/fastj/example/fastjengineconfig/Main.java | 2 +- src/example/java/tech/fastj/example/modelreadwrite/Main.java | 2 +- src/example/java/tech/fastj/example/polygon2d/Main.java | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/example/java/tech/fastj/example/fastjengineconfig/Main.java b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java index 93537406..72a78b5c 100644 --- a/src/example/java/tech/fastj/example/fastjengineconfig/Main.java +++ b/src/example/java/tech/fastj/example/fastjengineconfig/Main.java @@ -5,7 +5,7 @@ import tech.fastj.math.Point; import tech.fastj.math.Pointf; import tech.fastj.graphics.Display; -import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.util.DrawUtil; import tech.fastj.graphics.game.Polygon2D; import tech.fastj.systems.control.SimpleManager; diff --git a/src/example/java/tech/fastj/example/modelreadwrite/Main.java b/src/example/java/tech/fastj/example/modelreadwrite/Main.java index 289a7a71..60d2a88d 100644 --- a/src/example/java/tech/fastj/example/modelreadwrite/Main.java +++ b/src/example/java/tech/fastj/example/modelreadwrite/Main.java @@ -2,7 +2,7 @@ import tech.fastj.engine.FastJEngine; import tech.fastj.math.Pointf; -import tech.fastj.graphics.DrawUtil; +import tech.fastj.graphics.util.DrawUtil; import tech.fastj.graphics.game.Model2D; import tech.fastj.graphics.game.Polygon2D; diff --git a/src/example/java/tech/fastj/example/polygon2d/Main.java b/src/example/java/tech/fastj/example/polygon2d/Main.java index ecc2ac62..4ea4c9ca 100644 --- a/src/example/java/tech/fastj/example/polygon2d/Main.java +++ b/src/example/java/tech/fastj/example/polygon2d/Main.java @@ -51,11 +51,7 @@ public void init(Display display) { /* You can set the following properties of a Polygon2D: * - Mesh (Pointf[]) -<<<<<<< HEAD - * - Paint (solid color, gradient) -======= * - Color ->>>>>>> 0ac5fa4 ((#20) Added examples) * - PaintFilled (render the outline or fill) * - Rotation * - Scale From af26e1db1b6378417f71578d3aacb4b008812a7d Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 27 Jun 2021 13:33:15 -0400 Subject: [PATCH 21/27] fix issue with trying to close display without it being displayed --- src/main/java/tech/fastj/engine/FastJEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(); From db24201ff15d98a9388b2af063a33b51390005e7 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 27 Jun 2021 13:35:17 -0400 Subject: [PATCH 22/27] fixed issue with keyChecker trying to start after shutting down --- .../tech/fastj/systems/input/keyboard/Keyboard.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 daf08d7e..d7fcc585 100644 --- a/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java +++ b/src/main/java/tech/fastj/systems/input/keyboard/Keyboard.java @@ -23,7 +23,7 @@ public class Keyboard implements KeyListener { private static final Map Keys = new HashMap<>(); private static String lastKeyPressed = ""; - private static final ScheduledExecutorService KeyChecker = Executors.newSingleThreadScheduledExecutor(); + private static ScheduledExecutorService keyChecker; private static final Map> KeyEventProcessor = Map.of( KeyEvent.KEY_PRESSED, (inputManager, keyEvent) -> { @@ -67,7 +67,8 @@ public class Keyboard implements KeyListener { /** Initializes the keyboard. */ public static void init() { - KeyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); + keyChecker = Executors.newSingleThreadScheduledExecutor(); + keyChecker.scheduleWithFixedDelay(Keyboard::keyCheck, 1, 1, TimeUnit.MILLISECONDS); } /** Updates each key if it was recently pressed. */ @@ -225,7 +226,11 @@ public static boolean areKeysDown() { public static void stop() { reset(); - KeyChecker.shutdownNow(); + + if (keyChecker != null) { + keyChecker.shutdownNow(); + } + keyChecker = null; } @Override From 8d43e85fa022554387f48ae9efcb531732e80b7d Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 27 Jun 2021 13:53:13 -0400 Subject: [PATCH 23/27] (#20) Changed fastjengineconfig example to include target fps/ups --- .../{fastjengineconfig => engineconfig}/Main.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) rename src/example/java/tech/fastj/example/{fastjengineconfig => engineconfig}/Main.java (82%) diff --git a/src/example/java/tech/fastj/example/fastjengineconfig/Main.java b/src/example/java/tech/fastj/example/engineconfig/Main.java similarity index 82% rename from src/example/java/tech/fastj/example/fastjengineconfig/Main.java rename to src/example/java/tech/fastj/example/engineconfig/Main.java index 481b7755..1ab6fb84 100644 --- a/src/example/java/tech/fastj/example/fastjengineconfig/Main.java +++ b/src/example/java/tech/fastj/example/engineconfig/Main.java @@ -1,4 +1,4 @@ -package tech.fastj.example.fastjengineconfig; +package tech.fastj.example.engineconfig; import tech.fastj.engine.FastJEngine; import tech.fastj.engine.HWAccel; @@ -75,6 +75,19 @@ public static void main(String[] args) { 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(); } } From 25ed14d5867a1a2c598ab8e1f2f5b0e6c135f172 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 27 Jun 2021 13:58:08 -0400 Subject: [PATCH 24/27] updated comments in module-info --- src/example/java/module-info.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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; } From 4e0ee8d74b2402d1838fa2b3284774e093e96b1a Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 27 Jun 2021 13:58:26 -0400 Subject: [PATCH 25/27] removed stray commit merge comments --- src/example/java/tech/fastj/example/polygon2d/Main.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/example/java/tech/fastj/example/polygon2d/Main.java b/src/example/java/tech/fastj/example/polygon2d/Main.java index 73519839..49869bcf 100644 --- a/src/example/java/tech/fastj/example/polygon2d/Main.java +++ b/src/example/java/tech/fastj/example/polygon2d/Main.java @@ -51,11 +51,7 @@ public void init(Display display) { /* You can set the following properties of a Polygon2D: * - Mesh (Pointf[]) -<<<<<<< HEAD - * - Color -======= * - Paint (solid color, gradient) ->>>>>>> e9b11c827a41835f1ac3015178f140626cb74912 * - PaintFilled (render the outline or fill) * - Rotation * - Scale From ab61cc8b22e185343a77c932bae2bccb4e65e355 Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 27 Jun 2021 14:35:56 -0400 Subject: [PATCH 26/27] (#20) Added keyboard example --- .../tech/fastj/example/keyboard/Main.java | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 src/example/java/tech/fastj/example/keyboard/Main.java 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..8e857e6f --- /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 pressed and released. + * + * 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(); + } +} From a214f1f4dab7068f648cfde557f5aa81effa33ee Mon Sep 17 00:00:00 2001 From: lucasstarsz Date: Sun, 27 Jun 2021 14:39:50 -0400 Subject: [PATCH 27/27] update comments in keyboard example to reflect actual usage --- src/example/java/tech/fastj/example/keyboard/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/example/java/tech/fastj/example/keyboard/Main.java b/src/example/java/tech/fastj/example/keyboard/Main.java index 8e857e6f..5eb76d60 100644 --- a/src/example/java/tech/fastj/example/keyboard/Main.java +++ b/src/example/java/tech/fastj/example/keyboard/Main.java @@ -35,7 +35,7 @@ public void init(Display display) { * - 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 pressed and 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. */