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
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: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ dependencies {
implementation 'com.github.almasb:fxgl:21.1'
implementation 'com.google.guava:guava:33.5.0-jre'
implementation 'com.moandjiezana.toml:toml4j:0.7.2'
implementation 'com.google.auto.service:auto-service-annotations:1.1.1'
annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
implementation 'com.google.guava:guava:33.5.0-jre'
}

application {
Expand Down
19 changes: 10 additions & 9 deletions src/main/java/com/github/codestorm/bounceverse/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -291,16 +291,17 @@ public static final class Compatibility {
public static void throwIfNotCompatible(EntityType onlyFor, Component... params) {
for (var param : params) {
final var annotation = param.getClass().getAnnotation(ForEntity.class);
if (annotation != null) {
final var paramSet = EnumSet.copyOf(Arrays.asList(annotation.value()));
if (paramSet.isEmpty() || paramSet.contains(onlyFor)) {
continue;
}
if (annotation == null) {
continue;
}

final var paramEntityTypeSet = EnumSet.copyOf(Arrays.asList(annotation.value()));
if (!paramEntityTypeSet.contains(onlyFor)) {
throw new IllegalArgumentException(
String.format(
"Class '%s' does not compatible for entity has '%s' type.",
param.getClass().getSimpleName(), onlyFor.name()));
}
throw new IllegalArgumentException(
String.format(
"Class '%s' does not compatible for entity has '%s' type.",
param.getClass().getSimpleName(), onlyFor.name()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.github.codestorm.bounceverse.typing.annotations.ForEntity;
import java.util.ArrayList;
import java.util.List;
import javafx.util.Duration;

/**
*
Expand Down Expand Up @@ -61,4 +62,8 @@ public double getScaleHeight() {
public void setScaleHeight(double scaleHeight) {
this.scaleHeight = scaleHeight;
}

public ScaleChange(Duration duration) {
super(duration, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* @see CanUndo
*/
public abstract class UndoableBehavior extends Behavior implements CanUndo {
protected boolean removeWhenUndo = true;
protected Duration duration = Duration.INDEFINITE;
private List<Object> modified = null;
private TimerAction current;
Expand Down Expand Up @@ -67,14 +68,41 @@ public final void undo() {
if (undoLogic(modified)) {
current = null;
modified = null;
if (removeWhenUndo) {
entity.removeComponent(this.getClass());
}
}
}

@Override
public void onRemoved() {
undo();
}

public Duration getDuration() {
return duration;
}

public void setDuration(Duration duration) {
this.duration = duration;
}

public boolean isRemoveWhenUndo() {
return removeWhenUndo;
}

public void setRemoveWhenUndo(boolean removeWhenUndo) {
this.removeWhenUndo = removeWhenUndo;
}

public UndoableBehavior() {}

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

public UndoableBehavior(Duration duration, boolean removeWhenUndo) {
this(duration);
this.removeWhenUndo = removeWhenUndo;
}
Comment on lines +100 to +107
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding required constructors to the abstract class UndoableBehavior is a breaking change that requires all subclasses to define explicit constructors. Consider providing a default no-arg constructor or documenting this breaking change.

Copilot uses AI. Check for mistakes.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.github.codestorm.bounceverse.components.properties.powerup;

import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.component.Component;
import com.almasb.fxgl.entity.component.CoreComponent;
import com.github.codestorm.bounceverse.Utilities;
import com.github.codestorm.bounceverse.components.properties.Property;
import com.github.codestorm.bounceverse.typing.annotations.ForEntity;
import com.github.codestorm.bounceverse.typing.enums.EntityType;
import com.google.common.collect.MutableClassToInstanceMap;
import java.util.Map;
import org.jetbrains.annotations.NotNull;

/**
*
*
* <h1>{@link PowerUpContainer}</h1>
*
* Giống như một cái túi, nơi lưu trữ {@link Component} bên trong {@link Entity} và không kích hoạt
* logic của các component đó.
*/
@ForEntity({EntityType.POWER_UP})
@CoreComponent
public final class PowerUpContainer extends Property {
private MutableClassToInstanceMap<Component> container = MutableClassToInstanceMap.create();

/**
* Gán trực tiếp các {@link Component} lên trên {@link Entity}.
*
* @param entity Entity.
*/
public void addTo(Entity entity) {
for (var entry : container.entrySet()) {
final var component = entry.getValue();
// TODO: Gán việc kiểm tra trên chính Entity/Component thay vì thủ tục ntn
Utilities.Compatibility.throwIfNotCompatible((EntityType) entity.getType(), component);
entity.addComponent(entry.getValue());
}
}

/**
* Thêm các {@link Component} vào {@link #container}.
*
* @param components Các component
* @see MutableClassToInstanceMap#putAll(Map)
*/
public void put(@NotNull Component... components) {
for (var component : components) {
container.put(component.getClass(), component);
}
}

public PowerUpContainer(Component... components) {
put(components);
}

public MutableClassToInstanceMap<Component> getContainer() {
return container;
}

public void setContainer(MutableClassToInstanceMap<Component> container) {
this.container = container;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.EntityFactory;
import com.github.codestorm.bounceverse.factory.entities.*;
import org.jetbrains.annotations.NotNull;

public final class GameSystem extends System {
private GameSystem() {}
Expand All @@ -11,7 +12,7 @@ public static GameSystem getInstance() {
return GameSystem.Holder.INSTANCE;
}

private static void addFactory(EntityFactory... factories) {
private static void addFactory(@NotNull EntityFactory... factories) {
for (var factory : factories) {
FXGL.getGameWorld().addEntityFactory(factory);
}
Expand All @@ -24,34 +25,39 @@ private static void spawnWalls() {
FXGL.spawn("wallRight");
}

@Override
public void apply() {
addFactory(
new WallFactory(),
new BrickFactory(),
new BulletFactory(),
new PaddleFactory(),
new BallFactory());

// Wall
spawnWalls();

// Brick
private static void spawnBrick() {
for (int y = 1; y <= 6; y++) {
for (int x = 1; x <= 10; x++) {
FXGL.spawn("normalBrick", 85 * x, 35 * y);
}
}
}

// Paddle
private static void spawnPaddle() {
double px = FXGL.getAppWidth() / 2.0 - 60;
double py = FXGL.getAppHeight() - 40;
FXGL.spawn("paddle", px, py);
}

// Ball
private static void spawnBall() {
FXGL.spawn("ball");
}

@Override
public void apply() {
addFactory(
new WallFactory(),
new BrickFactory(),
new BulletFactory(),
new PaddleFactory(),
new BallFactory());

spawnWalls();
spawnBrick();
spawnPaddle();
spawnBall();
}

/**
* Lazy-loaded singleton holder. <br>
* Follow <a href= "https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* {@link System} quản lý Input trong game. <br>
* <i>Đây là một Singleton, cần lấy instance thông qua {@link #getInstance()}</i>.
*/
public class InputSystem extends System {
public final class InputSystem extends System {
public static InputSystem getInstance() {
return InputSystem.Holder.INSTANCE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@
import com.almasb.fxgl.physics.box2d.dynamics.FixtureDef;
import com.github.codestorm.bounceverse.Utilities;
import com.github.codestorm.bounceverse.components.behaviors.HealthDeath;
import com.github.codestorm.bounceverse.components.behaviors.paddle.PaddleShooting;
import com.github.codestorm.bounceverse.typing.enums.EntityType;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
import org.jetbrains.annotations.NotNull;

/**
Expand Down Expand Up @@ -87,7 +85,6 @@ public final class BrickFactory implements EntityFactory {
*/
@NotNull @Spawns("normalBrick")
public static Entity newNormalBrick(SpawnData pos) {
return newBrick(
new Point2D(pos.getX(), pos.getY()), DEFAULT_HP, new PaddleShooting(Duration.ONE));
return newBrick(new Point2D(pos.getX(), pos.getY()), DEFAULT_HP);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.almasb.fxgl.entity.EntityFactory;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.entity.Spawns;
import com.github.codestorm.bounceverse.components.behaviors.ScaleChange;
import com.github.codestorm.bounceverse.components.behaviors.paddle.PaddleShooting;
import com.github.codestorm.bounceverse.typing.enums.EntityType;
import javafx.scene.paint.Color;
Expand Down Expand Up @@ -38,8 +37,8 @@ public Entity newPaddle(SpawnData data) {
.type(EntityType.PADDLE)
.viewWithBBox(view)
.collidable()
.with(new ScaleChange(), new PaddleShooting(DEFAULT_SHOOT_COOLDOWN))
.with(new PaddleShooting(DEFAULT_SHOOT_COOLDOWN))
.build();
// TODO: Thêm điều chỉnh tốc độ
// TODO: Thêm Dashing
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.github.codestorm.bounceverse.factory.entities;

import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.EntityFactory;
import com.almasb.fxgl.entity.component.Component;
import com.almasb.fxgl.physics.BoundingShape;
import com.almasb.fxgl.physics.HitBox;
import com.almasb.fxgl.physics.PhysicsComponent;
import com.almasb.fxgl.texture.Texture;
import com.github.codestorm.bounceverse.components.properties.powerup.PowerUpContainer;
import com.github.codestorm.bounceverse.typing.enums.DirectionUnit;
import com.github.codestorm.bounceverse.typing.enums.EntityType;
import javafx.geometry.Point2D;
import org.jetbrains.annotations.NotNull;

/**
*
*
* <h1>{@link PowerUpFactory}</h1>
*
* Factory để tạo các entity loại {@link EntityType#POWER_UP} trong trò chơi.
*
* @see EntityFactory
*/
public final class PowerUpFactory implements EntityFactory {
public static final double DEFAULT_RADIUS = 10;
public static final double DEFAULT_SPEED = 10;

/**
* Tạo mới một PowerUp. Đây là một "abstract" method.
*
* @param pos Vị trí
* @param has Những gì PowerUp này sẽ cung cấp
* @return Entity PowerUp
*/
private Entity newPowerUp(Point2D pos, Texture texture, Component... has) {
final var hitbox = new HitBox(BoundingShape.circle(DEFAULT_RADIUS));

return FXGL.entityBuilder()
.type(EntityType.POWER_UP)
.bbox(hitbox)
.at(pos)
.view(texture)
.collidable()
.with(getPhysicsComponent(), new PowerUpContainer(has))
.buildAndAttach();
}

@NotNull private static PhysicsComponent getPhysicsComponent() {
final var velocity = DirectionUnit.DOWN.getVector().mul(DEFAULT_SPEED);

var physics = new PhysicsComponent();
physics.setOnPhysicsInitialized(
() -> {
physics.setLinearVelocity(velocity.toPoint2D());
physics.setAngularVelocity(0);
physics.getBody().setFixedRotation(true);
physics.getBody().setLinearDamping(0f);
physics.getBody().setAngularDamping(0f);
});
return physics;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@
*
* <h1>@{@link ForEntity}</h1>
*
* Đánh dấu class chỉ định là phù hợp cho entity nào. <br>
* <b>Nếu chỉ định tất cả entity, hãy truyền vào mảng rỗng {@code {}}.</b> <br>
* Ràng buộc đánh dấu class chỉ định là phù hợp cho entity nào. <br>
* <br>
* Sử dụng {@link Utilities.Compatibility#throwIfNotCompatible(EntityType, Component...)} để kiểm
* tra.
* tra. <br>
* <br>
*
* <h2>Ví dụ</h2>
*
* <ul>
* <li>Cho phép tất cả: Không thêm annotation này.
* <li>Cho phép cụ thể: {@code @ForEntity(A)} hoặc {@code @ForEntity({A, B, C})}
* <li>Không cho phép: {@code @ForEntity({})}
* </ul>
*
* @see EntityType
*/
Expand Down
Loading