This repository was archived by the owner on Dec 24, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Add game systems template #13
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
ce6ddbf
feat: add configuration loading and game settings management
thnhmai06 a5c065b
feat: implement game configuration loading and management
thnhmai06 fa2b5c8
feat: add collision handling and launch options management
thnhmai06 514ae9d
feat: enhance configuration loading with error handling
thnhmai06 4da8273
feat: implement scene management and enhance collision handling
thnhmai06 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,15 @@ | ||
| package com.github.codestorm.bounceverse; | ||
|
|
||
| import com.almasb.fxgl.app.ApplicationMode; | ||
| import com.almasb.fxgl.app.GameApplication; | ||
| import com.almasb.fxgl.app.GameSettings; | ||
| import com.almasb.fxgl.dsl.FXGL; | ||
| import com.github.codestorm.bounceverse.factory.BrickFactory; | ||
| import com.github.codestorm.bounceverse.factory.SceneFactory; | ||
| import com.github.codestorm.bounceverse.systems.LaunchOption; | ||
| import com.github.codestorm.bounceverse.systems.physics.CollisionSystem; | ||
| import java.io.IOException; | ||
| import java.util.Properties; | ||
| import javafx.scene.paint.Color; | ||
|
|
||
| /** | ||
|
|
@@ -18,13 +24,70 @@ | |
| * gạch và dành được điểm số cao nhất. Nhưng liệu mọi thứ chỉ đơn giản như vậy?</i> | ||
| */ | ||
| public final class Bounceverse extends GameApplication { | ||
| public static final String name = "Bounceverse"; | ||
| private static LaunchOption launchOption; | ||
|
|
||
| /** | ||
| * Cấu hình game. | ||
| * | ||
| * <p>Sử dụng {@link #loadConfigs()} để load các config. | ||
| */ | ||
| private static final class Configs { | ||
| private static final String ROOT = "/configs/"; | ||
|
|
||
| /** Cấu hình game bên trong hệ thống game. */ | ||
| private static final class System { | ||
| public static Properties settings; | ||
|
|
||
| private System() {} | ||
| } | ||
|
|
||
| /** Cấu hình game bên ngoài hệ thống game. */ | ||
| private static final class Options { | ||
| public static Properties DEFAULT; // Cấu hình mặc định của trò chơi | ||
|
|
||
| private Options() {} | ||
| } | ||
|
|
||
| /** | ||
| * Load game configs. | ||
| * | ||
| * @throws IOException if an error occurred when reading from the input stream. | ||
| */ | ||
| public static void loadConfigs() throws IOException { | ||
| Options.DEFAULT = Utils.IO.loadProperties(ROOT + "default.properties"); | ||
| System.settings = Utils.IO.loadProperties(ROOT + "system/settings.properties"); | ||
| } | ||
|
|
||
| private Configs() {} | ||
| } | ||
|
|
||
| @Override | ||
| protected void initSettings(GameSettings settings) { | ||
| settings.setWidth(900); | ||
| settings.setHeight(600); | ||
| settings.setTitle(name); | ||
| try { | ||
| Configs.loadConfigs(); | ||
| } catch (IOException e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| // Basic | ||
| settings.setTitle(Configs.System.settings.getProperty("settings.name")); | ||
| settings.setVersion(Configs.System.settings.getProperty("settings.version")); | ||
| settings.setCredits(Utils.IO.readTextFile("credits.txt")); | ||
| settings.setApplicationMode( | ||
| Boolean.parseBoolean(Configs.System.settings.getProperty("settings.devMode")) | ||
| ? ApplicationMode.DEVELOPER | ||
| : (launchOption.isDebug()) | ||
| ? ApplicationMode.DEBUG | ||
| : ApplicationMode.RELEASE); | ||
|
|
||
| // Display | ||
| settings.setWidth(Integer.parseInt(Configs.Options.DEFAULT.getProperty("width"))); | ||
| settings.setHeight(Integer.parseInt(Configs.Options.DEFAULT.getProperty("height"))); | ||
|
Comment on lines
+83
to
+84
|
||
| settings.setFullScreenAllowed(true); | ||
|
|
||
| // In-app | ||
| settings.setSceneFactory(new SceneFactory()); | ||
| settings.setMainMenuEnabled(true); | ||
| settings.setIntroEnabled(true); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -35,12 +98,18 @@ protected void initGame() { | |
| var brick2 = FXGL.spawn("normalBrick", 200, 200); | ||
| } | ||
|
|
||
| @Override | ||
| protected void initPhysics() { | ||
| CollisionSystem.getInstance().apply(); | ||
| } | ||
|
|
||
| @Override | ||
| protected void initUI() { | ||
| FXGL.getGameScene().setBackgroundColor(Color.web("#2B2B2B")); | ||
| } | ||
|
|
||
| public static void main(String[] args) { | ||
| launchOption = new LaunchOption(args); | ||
| launch(args); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||||||||||||||||||||||
| package com.github.codestorm.bounceverse; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||
| import java.io.InputStream; | ||||||||||||||||||||||||||
| import java.util.*; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** Utilities. */ | ||||||||||||||||||||||||||
| public final class Utils { | ||||||||||||||||||||||||||
| /** Input/Output utilities. */ | ||||||||||||||||||||||||||
| public static final class IO { | ||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Load .properties file. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * @param path Relative path | ||||||||||||||||||||||||||
| * @return Parsed properties | ||||||||||||||||||||||||||
| * @throws IOException if an error occurred when reading from the input stream. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| public static Properties loadProperties(String path) throws IOException { | ||||||||||||||||||||||||||
| InputStream fileStream = IO.class.getResourceAsStream(path); | ||||||||||||||||||||||||||
| if (fileStream == null) { | ||||||||||||||||||||||||||
| throw new IOException("Cannot open InputStream in" + path); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Properties prop = new Properties(); | ||||||||||||||||||||||||||
| prop.load(fileStream); | ||||||||||||||||||||||||||
| fileStream.close(); | ||||||||||||||||||||||||||
| return prop; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Convert an array of key=value pairs into a hashmap. The string "key=" maps key onto "", | ||||||||||||||||||||||||||
| * while just "key" maps key onto null. The value may contain '=' characters, only the first | ||||||||||||||||||||||||||
| * "=" is a delimiter. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * <p>Source code from <a href="https://stackoverflow.com/a/52940215/16410937">here</a>. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * @param args command-line arguments in the key=value format (or just key= or key) | ||||||||||||||||||||||||||
| * @param defaults a map of default values, may be null. Mappings to null are not copied to | ||||||||||||||||||||||||||
| * the resulting map. | ||||||||||||||||||||||||||
| * @param whiteList if not null, the keys not present in this map cause an exception (and | ||||||||||||||||||||||||||
| * keys mapped to null are ok) | ||||||||||||||||||||||||||
| * @return a map that maps these keys onto the corresponding values. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| public static HashMap<String, String> parseArgs( | ||||||||||||||||||||||||||
| String[] args, | ||||||||||||||||||||||||||
| HashMap<String, String> defaults, | ||||||||||||||||||||||||||
| HashMap<String, String> whiteList) { | ||||||||||||||||||||||||||
| // HashMap allows null values | ||||||||||||||||||||||||||
| HashMap<String, String> res = new HashMap<>(); | ||||||||||||||||||||||||||
| if (defaults != null) { | ||||||||||||||||||||||||||
| for (Map.Entry<String, String> e : defaults.entrySet()) { | ||||||||||||||||||||||||||
| if (e.getValue() != null) { | ||||||||||||||||||||||||||
| res.put(e.getKey(), e.getValue()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| for (String s : args) { | ||||||||||||||||||||||||||
| String[] kv = s.split("=", 2); | ||||||||||||||||||||||||||
| if (whiteList != null && !whiteList.containsKey(kv[0])) { | ||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| res.put(kv[0], kv.length < 2 ? null : kv[1]); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| return res; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Read text file (txt) and put all lines into {@link List}. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * @param path File path | ||||||||||||||||||||||||||
| * @return All lines in text file | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| public static List<String> readTextFile(String path) { | ||||||||||||||||||||||||||
| var res = new ArrayList<String>(); | ||||||||||||||||||||||||||
| var scanner = new Scanner(path); | ||||||||||||||||||||||||||
| while (scanner.hasNext()) { | ||||||||||||||||||||||||||
| res.add(scanner.next()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
Comment on lines
+75
to
+78
|
||||||||||||||||||||||||||
| var scanner = new Scanner(path); | |
| while (scanner.hasNext()) { | |
| res.add(scanner.next()); | |
| } | |
| InputStream fileStream = IO.class.getResourceAsStream(path); | |
| if (fileStream == null) { | |
| throw new RuntimeException("Cannot open InputStream in " + path); | |
| } | |
| var scanner = new Scanner(fileStream); | |
| while (scanner.hasNextLine()) { | |
| res.add(scanner.nextLine()); | |
| } |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/github/codestorm/bounceverse/factory/SceneFactory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.github.codestorm.bounceverse.factory; | ||
|
|
||
| import com.almasb.fxgl.app.scene.FXGLMenu; | ||
| import com.github.codestorm.bounceverse.scenes.MainMenu; | ||
| import org.jetbrains.annotations.NotNull; | ||
|
|
||
| public class SceneFactory extends com.almasb.fxgl.app.scene.SceneFactory { | ||
| @NotNull @Override | ||
| public FXGLMenu newMainMenu() { | ||
| return new MainMenu(); | ||
| } | ||
| } |
11 changes: 11 additions & 0 deletions
11
src/main/java/com/github/codestorm/bounceverse/scenes/MainMenu.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.github.codestorm.bounceverse.scenes; | ||
|
|
||
| import com.almasb.fxgl.app.scene.FXGLDefaultMenu; | ||
| import com.almasb.fxgl.app.scene.MenuType; | ||
|
|
||
| public class MainMenu extends FXGLDefaultMenu { | ||
| public MainMenu() { | ||
| super(MenuType.MAIN_MENU); | ||
| // TODO: Customize Main Menu | ||
| } | ||
| } |
23 changes: 23 additions & 0 deletions
23
src/main/java/com/github/codestorm/bounceverse/systems/LaunchOption.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package com.github.codestorm.bounceverse.systems; | ||
|
|
||
| import com.github.codestorm.bounceverse.Utils; | ||
|
|
||
| /** | ||
| * | ||
| * | ||
| * <h1>{@link LaunchOption}</h1> | ||
| * | ||
| * Các tùy chọn khởi động được áp dụng trong game. | ||
| */ | ||
| public final class LaunchOption { | ||
| private boolean debug = false; | ||
|
|
||
| public boolean isDebug() { | ||
| return debug; | ||
| } | ||
|
|
||
| public LaunchOption(String... args) { | ||
| var map = Utils.IO.parseArgs(args, null, null); | ||
| debug = Boolean.parseBoolean(map.getOrDefault("debug", "false")); | ||
| } | ||
| } |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/github/codestorm/bounceverse/systems/System.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.github.codestorm.bounceverse.systems; | ||
|
|
||
| /** | ||
| * | ||
| * | ||
| * <h1>{@link System}</h1> | ||
| * | ||
| * Hệ thống logic trong game. <b>Các lớp kế thừa nên thiết kế dựa trên (lazy-loaded) Singleton.</b> | ||
| * | ||
| * <p>Tất cả logic của hệ thống được áp dụng thông qua {@link #apply()}. | ||
| */ | ||
| public abstract class System { | ||
| /** | ||
| * Áp dụng logic của hệ thống vào game. | ||
| * | ||
| * <p>Sử dụng trên {@link com.github.codestorm.bounceverse.Bounceverse} | ||
| */ | ||
| public abstract void apply(); | ||
|
|
||
| protected System() {} | ||
| } |
46 changes: 46 additions & 0 deletions
46
src/main/java/com/github/codestorm/bounceverse/systems/physics/CollisionSystem.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package com.github.codestorm.bounceverse.systems.physics; | ||
|
|
||
| import com.github.codestorm.bounceverse.systems.System; | ||
|
|
||
| /** | ||
| * | ||
| * | ||
| * <h1>{@link CollisionSystem}</h1> | ||
| * | ||
| * Hệ thống xử lý va chạm. | ||
| * | ||
| * <p><i>Đây là một Singleton, cần lấy instance thông qua {@link #getInstance()}</i>. | ||
| * | ||
| * @see System | ||
| */ | ||
| public final class CollisionSystem extends System { | ||
| /** | ||
| * Lazy-loaded singleton holder. | ||
| * | ||
| * <p>Follow <a href="https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom"> | ||
| * Initialization-on-demand holder idiom</a>. | ||
| */ | ||
| private static final class Holder { | ||
| static final CollisionSystem INSTANCE = new CollisionSystem(); | ||
| } | ||
|
|
||
| public static CollisionSystem getInstance() { | ||
| return Holder.INSTANCE; | ||
| } | ||
|
|
||
| // ? Tạo các Group CollisionHandler ở đây (dùng composition) | ||
|
|
||
| @Override | ||
| public void apply() { | ||
| // ? Viết các logic CollisionHandler ở đây. eg: | ||
| // getPhysicsWorld().addCollisionHandler(new CollisionHandler(EntityType.PLAYER, | ||
| // EntityType.COIN) { | ||
| // @Override | ||
| // protected void onCollisionBegin(Entity player, Entity coin) { | ||
| // coin.removeFromWorld(); | ||
| // } | ||
| // }); | ||
| } | ||
|
|
||
| private CollisionSystem() {} | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| width=1024 | ||
| height=768 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # settings | ||
| settings.name=Bounceverse | ||
| settings.version=1.0.0 | ||
| settings.devMode=true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| - Game - | ||
|
|
||
| CodeStorm team | ||
|
|
||
| Leader: | ||
| Mai Thành (@thnhmai06) | ||
|
|
||
| Members: | ||
| Mạnh Tân (@ManhTanTran) | ||
| Minh Ngọc (@minngoc1213) | ||
| Anh Tuấn (@huynhtuan372) | ||
|
|
||
| -o0o- |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will fail because
readTextFilehas a bug where it passes the path string directly to Scanner constructor. The path should be prefixed with '/' to read from resources:Utils.IO.readTextFile(\"/credits.txt\").