Skip to content
This repository was archived by the owner on Dec 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
6229cc2
feat: Brick
ManhTanTran Sep 29, 2025
9dc0071
ci: remove ratchetFrom configuration in spotless (#2)
thnhmai06 Sep 29, 2025
7418ab1
feat(brick): add PowerBrick and update Brick, ExoplodeBrick, Protecte…
ManhTanTran Sep 30, 2025
b4f0622
docs(brick): add Javadoc for Brick, ExoplodeBrick, PowerBrick, Protec…
ManhTanTran Sep 30, 2025
89c507a
refactor(brick): remove NormalBrick and StrongBrick
ManhTanTran Sep 30, 2025
2453417
feat(paddle): add ExpendPaddle, LaserPaddle, ShrinkPaddle and update …
ManhTanTran Sep 30, 2025
90d06b7
Implement abstract class Ball (#3)
minngoc1213 Sep 30, 2025
b0844df
feat: Brick (#1)
ManhTanTran Sep 30, 2025
bfd5534
feat: Add PowerUp class (#5)
thnhmai06 Sep 30, 2025
0025b5f
feat(paddle): add ExpendPaddle, LaserPaddle, ShrinkPaddle and update …
ManhTanTran Oct 1, 2025
bac5f52
feat(paddle): add ExpendPaddle, LaserPaddle, ShrinkPaddle and update …
ManhTanTran Oct 1, 2025
3001013
refactor: remove brick and gameManager packages
ManhTanTran Oct 1, 2025
9ebb12d
chore: Update .gitignore and add commit instructions
thnhmai06 Oct 1, 2025
f803b3c
Merge pull request #6
ManhTanTran Oct 1, 2025
5d7487b
docs: Update documentation links in PowerUp and Ball classes
thnhmai06 Oct 1, 2025
43bcfc5
feat(brick): refactor and document brick module (Factory, Component, …
ManhTanTran Oct 5, 2025
106fcb6
feat(game): add GameManager and BounceVerseApp for game initialization
ManhTanTran Oct 5, 2025
f0211c3
feat(paddle): add PaddleComponent and variants (Expand, Shrink, Laser…
ManhTanTran Oct 7, 2025
e5f75a4
Brick (#7)
ManhTanTran Oct 7, 2025
169ad53
refactor: remove duplicate `paddle` folder
thnhmai06 Oct 7, 2025
84c357f
feat/GameApplication (#8)
ManhTanTran Oct 8, 2025
7419cd4
ci: update workflow setup steps for clarity
thnhmai06 Oct 8, 2025
06eb0b7
chore: remove debug script parameters from run configurations
thnhmai06 Oct 8, 2025
30e005b
feat(brick): implement explosion logic and health management refactor
ManhTanTran Oct 8, 2025
f11276a
refactor: reorganize component structure and improve entity tagging (…
thnhmai06 Oct 9, 2025
47520f5
(skip ci) Merge 'main' to 'feature/paddle'
thnhmai06 Oct 9, 2025
c0e00af
chore: remove unused logging dependencies from build.gradle
thnhmai06 Oct 11, 2025
91e1aca
chore: update output directory for build artifacts
thnhmai06 Oct 11, 2025
d4075ca
Merge branch 'main' into feature/paddle
ManhTanTran Oct 13, 2025
0079733
Add game systems template (#13)
thnhmai06 Oct 13, 2025
a2d0010
chore: update project JDK language level to JDK_24_PREVIEW
thnhmai06 Oct 13, 2025
9ae062f
feat(components): add new paddle behaviors and properties (Bullet, Wi…
ManhTanTran Oct 14, 2025
1b6deaa
fix: resolve merge conflicts in BrickExplode and BrickHealth
ManhTanTran Oct 14, 2025
232d231
Merge branch 'main' into feature/paddle
ManhTanTran Oct 14, 2025
0b066f4
refactor: migrate paddle and bullet systems to new structure
ManhTanTran Oct 14, 2025
e00a5d2
refactor(paddle): adjust PaddleFactory, Shoot and Width property for…
ManhTanTran Oct 14, 2025
5b6e38b
feat(wall): add WallFactory and Wall components with Move property fo…
ManhTanTran Oct 14, 2025
943832b
feat(physics): handle paddle-wall collision in CollisionSystem
ManhTanTran Oct 14, 2025
abb1bd8
feat(data): add WALL entity type for collision system
ManhTanTran Oct 14, 2025
486f670
feat(behavior): update BrickExplode logic for new collision handling
ManhTanTran Oct 14, 2025
36c85d4
feat(paddle-wall): add Move component update and WallFactory with cor…
ManhTanTran Oct 14, 2025
70f8315
(skip ci) refactor: rename components and update imports for consistency
thnhmai06 Oct 15, 2025
67fdea5
[skip ci] Add and refactor Systems, Core (#15)
thnhmai06 Oct 18, 2025
8a096ea
[skip ci] refactor: rename spotlessCheck.yml to spotless.yml for cons…
thnhmai06 Oct 18, 2025
3bd4d40
[skip ci] chore: Remove log files
thnhmai06 Oct 20, 2025
8f753cf
Replace `For*` interface tag by annotation (#16)
thnhmai06 Oct 20, 2025
4082505
feat: add Attack and Attributes components for entity interactions
thnhmai06 Oct 21, 2025
689f690
fix(paddle): fix freeze paddle
thnhmai06 Oct 21, 2025
7f86037
ci: update CI conditions to use startsWith for skip ci
thnhmai06 Oct 21, 2025
1754186
chore: correct spelling and rename classes for consistency
thnhmai06 Oct 21, 2025
0db9962
Merge pull request #10 from CodeStormOOP/feature/paddle
thnhmai06 Oct 27, 2025
8b5ef50
[skip ci] chore: add CODEOWNERS
thnhmai06 Oct 21, 2025
1f97c73
Add Ball entity and Ball, Brick physic/collision components (#14)
minngoc1213 Oct 22, 2025
e057c29
ci: update version of actions/upload-artifact
thnhmai06 Oct 22, 2025
d8e7579
ci(buildRelease): change update artifact to update release
thnhmai06 Oct 22, 2025
97a94ce
[skip ci] chore: remove `/system/` ignore folder
thnhmai06 Oct 22, 2025
3b0d940
chore!: update JDK setup to use Eclipse Temurin 24
thnhmai06 Oct 25, 2025
240827a
docs: add Javadoc writing guide and update guide.md
thnhmai06 Oct 26, 2025
d44bfa8
[skip ci] docs: update Javadoc class symbols table for clarity
thnhmai06 Oct 26, 2025
5ba7a55
Merge remote-tracking branch 'origin/dev'
thnhmai06 Oct 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/dev/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ Chi tiết: [Spotless Gradle Plugin](https://github.com/diffplug/spotless/tree/m
* **Commits:** [Conventional Commits](https://www.conventionalcommits.org/) (và viết message bằng **Tiếng Anh**)
* **Files Structure:**
[Gradle project Structure](https://docs.gradle.org/current/userguide/organizing_gradle_projects.html)

Ngoài ra:
* [Hướng dẫn viết javadoc](javadoc.md)
55 changes: 55 additions & 0 deletions docs/dev/javadoc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# 📄 Viết Javadoc

### 💾 Format

Javadoc được viết tuân theo các quy tắc javadoc cơ bản và viết trên format HTML.

### 🏗️ Cấu trúc

Trên IDE, khi bạn di chuyển lên trên đầu lớp/method và viết `/**` rồi Enter, IDE sẽ tự sinh ra cho bạn khung để bạn viết
javadoc. Cấu trúc của dự án chúng ta sẽ là:

- Đối với Lớp:

```java
/**
*
*
* <h1>?{@link Tên Lớp}</h1>
*
* Mô tả lớp... Có thể sử dụng {@link Class nào đó#TP trong class} để liên kết <br>
* <b>Chú ý: Sử dụng thẻ br để xuống dòng</b> <br>
* <i>Plot Twist: tui cũng ko bt viết gì ở đây nữa</i>
*
* @see ...
*/

```

trong đó `?` ở Tên lớp sẽ là:

| Loại lớp | 📚 Class | 📱Interface | 🔢 Enum | ❗ Exception | 📍 Annotation | 📝 Record |
|----------|----------|-------------|---------|-------------|---------------|-----------|
| Kí hiệu | | % | # | ! | @ | $ |

**VD:** `ThisIsClass`, `%Interface`, `!StackoverflowException`, `#EntityType`

- Đối với method:

```java
/**
* Hàm này thực hiện chức năng gì... .
*
* @params Input1 Đầu vào 1
* @params Input2 Đầu vào 2
* @return Kết quả của hàm
* @throws Exception nếu có lỗi xảy ra...
*/

```

### ❗Chú ý

- Formating docs sau khi viết code xong. (Phím tắt thường là `Alt` + `Shift` + `F`)

### Bạn có thể xem source code trong dự án để xem ví dụ.
279 changes: 279 additions & 0 deletions src/main/java/com/github/codestorm/bounceverse/Utils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
package com.github.codestorm.bounceverse;

import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.time.TimerAction;
import com.github.codestorm.bounceverse.data.types.DirectionUnit;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import javafx.geometry.Rectangle2D;
import javafx.scene.shape.Circle;
import javafx.util.Duration;

/** Utilities. */
public final class Utils {
private Utils() {}

/** Input/Output utilities. */
public static final class IO {
private 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 on " + 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. <br>
* 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());
}
scanner.close();
return res;
}
}

public static final class Time {
/**
* Thời gian hồi để thực hiện lại gì đó. Thực hiện thông qua {@link #current}
*
* @see ActiveCooldown
*/
public static final class Cooldown {
private final ActiveCooldown current = new ActiveCooldown();
private Duration duration = Duration.INDEFINITE;

public Duration getDuration() {
return duration;
}

/**
* Đặt thời lượng cooldown mới. <br>
* <b>Lưu ý: Chỉ áp dụng cho cooldown mới.</b>
*
* @param duration Thời lượng mới
*/
public void setDuration(Duration duration) {
this.duration = duration;
}

public ActiveCooldown getCurrent() {
return current;
}

public Cooldown() {}

public Cooldown(Duration duration) {
this.duration = duration;
}

/** Cooldown thời điểm hiện tại. Giống như một wrapper của {@link TimerAction}. */
public final class ActiveCooldown {
private TimerAction waiter = null;
private double timestamp = Double.NaN;
private Runnable onExpiredCallback = null;

/** Hành động khi cooldown hết. */
private void onExpired() {
timestamp = Double.NaN;
if (onExpiredCallback != null) {
onExpiredCallback.run();
}
}

/**
* Callback thực thi khi cooldown hết hạn.
*
* @param callback Callback sẽ thực thi
*/
public void setOnExpired(Runnable callback) {
this.onExpiredCallback = callback;
}

/**
* Kiểm tra Cooldown hiện tại hết hạn chưa.
*
* @return {@code true} nếu hết hạn, ngược lại {@code false}.
*/
public boolean expired() {
return (waiter == null) || waiter.isExpired();
}

/** Khiến cooldown hết hạn ngay (nếu có). */
public void expire() {
if (!expired()) {
waiter.expire();
}
}

/** Set một cooldown mới. */
public void makeNew() {
expire();

final var gameTimer = FXGL.getGameTimer();
waiter = gameTimer.runOnceAfter(this::onExpired, duration);
timestamp = gameTimer.getNow();
}

/** Tạm dừng cooldown. */
public void pause() {
if (!expired()) {
waiter.pause();
}
}

/** Tiếp tục cooldown. */
public void resume() {
if (!expired()) {
waiter.resume();
}
}

public boolean isPaused() {
return !expired() && waiter.isPaused();
}

/**
* Lấy thời gian còn lại của cooldown.
*
* @return Thời gian còn lại
*/
public Duration getTimeLeft() {
if (expired()) {
return Duration.ZERO;
}
final var elapsed = Duration.millis(FXGL.getGameTimer().getNow() - timestamp);
return duration.subtract(elapsed);
}

/**
* Giảm thời gian hồi đi một lượng thời gian.
*
* @param duration Thời lượng giảm.
*/
public void reduce(Duration duration) {
if (!expired()) {
waiter.update(duration.toMillis());
}
}

private ActiveCooldown() {}
}
}
}

public static final class Geometric {
/**
* Lọc các Entity trong phạm vi Hình tròn.
*
* @param circle Hình tròn
* @return Các entity
*/
public static List<Entity> getEntityInCircle(Circle circle) {
final var cx = circle.getCenterX();
final var cy = circle.getCenterY();
final var radius = circle.getRadius();

return getEntityInCircle(cx, cy, radius);
}

/**
* Lọc các Entity trong phạm vi Hình tròn.
*
* @param cx Tâm X
* @param cy Tâm Y
* @param radius Bán kính
* @return Các entity
*/
public static List<Entity> getEntityInCircle(double cx, double cy, double radius) {
final Rectangle2D outRect =
new Rectangle2D(cx - radius, cy - radius, 2 * radius, 2 * radius);
return FXGL.getGameWorld().getEntitiesInRange(outRect).stream()
.filter(
e -> {
double nearestX =
Math.max(e.getX(), Math.min(cx, e.getX() + e.getWidth()));
double nearestY =
Math.max(e.getY(), Math.min(cy, e.getY() + e.getHeight()));
double dx = cx - nearestX;
double dy = cy - nearestY;
return (dx * dx + dy * dy) <= radius * radius;
})
.toList();
}
}

public static final class Collision {
public static DirectionUnit getCollisionDirection(Entity source, Entity target) {
var fromBox = source.getBoundingBoxComponent();
var toBox = target.getBoundingBoxComponent();

var fCenter = fromBox.getCenterWorld();
var tCenter = toBox.getCenterWorld();

var direction = tCenter.subtract(fCenter);

return Math.abs(direction.getX()) > Math.abs(direction.getY())
? direction.getX() > 0 ? DirectionUnit.RIGHT : DirectionUnit.LEFT
: direction.getY() > 0 ? DirectionUnit.DOWN : DirectionUnit.UP;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.github.codestorm.bounceverse.data.contracts;

import java.util.List;

/**
*
*
* <h1>{@link CanExecute}</h1>
*
* Có thể thực thi hành động nào đó.
*/
public interface CanExecute {
/**
* Thực thi hành động.
*
* @param data Dữ liệu truyền vào
*/
void execute(List<Object> data);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.codestorm.bounceverse.data.contracts;

import com.github.codestorm.bounceverse.components.behaviors.UndoableBehavior;

/**
*
*
* <h1>{@link CanUndo}</h1>
*
* Có thể hoàn tác trạng thái về lúc trước khi thực thi. Chỉ hỗ trợ thực thi 1 lần.
*
* @see UndoableBehavior
*/
public interface CanUndo extends CanExecute {
/** Hoàn tác trạng thái về trước đó. */
void undo();
}
Loading
Loading