Skip to content
This repository was archived by the owner on Dec 24, 2025. It is now read-only.

Commit c65bf77

Browse files
committed
fix(powerup): spawn multiple balls from original ball position instead of paddle
Updated MultipleBallPowerUp logic to correctly duplicate existing balls (x2 total) at their positions with slight velocity offset. Adjusted BallFactory to preserve SpawnData position and avoid fallback to paddle when spawning from PowerUps.
1 parent 2d10408 commit c65bf77

3 files changed

Lines changed: 25 additions & 25 deletions

File tree

src/main/java/com/github/codestorm/bounceverse/components/properties/powerup/types/ball/MultipleBallPowerUp.java

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44

55
import com.almasb.fxgl.dsl.FXGL;
66
import com.almasb.fxgl.entity.Entity;
7+
import com.almasb.fxgl.entity.SpawnData;
78
import com.almasb.fxgl.physics.PhysicsComponent;
89
import com.github.codestorm.bounceverse.components.properties.powerup.types.PowerUp;
910
import com.github.codestorm.bounceverse.typing.enums.EntityType;
1011
import javafx.geometry.Point2D;
1112

1213
/**
1314
* PowerUp nhân đôi toàn bộ bóng hiện có.
14-
* Mỗi bóng sinh thêm 1 bóng mới tách từ vị trí của nó và bay lệch nhẹ sang 2 hướng.
15+
* Mỗi bóng sinh thêm 1 bóng mới tách từ vị trí của nó và bay lệch nhẹ sang 2
16+
* hướng.
1517
*/
1618
public final class MultipleBallPowerUp extends PowerUp {
1719

@@ -22,8 +24,6 @@ public MultipleBallPowerUp() {
2224
@Override
2325
public void apply(Entity paddle) {
2426
var balls = FXGL.getGameWorld().getEntitiesByType(EntityType.BALL);
25-
26-
// copy list để tránh ConcurrentModificationException khi spawn trong loop
2727
var currentBalls = List.copyOf(balls);
2828

2929
for (Entity ball : currentBalls) {
@@ -34,37 +34,35 @@ public void apply(Entity paddle) {
3434
if (velocity.magnitude() < 1e-3)
3535
return;
3636

37-
// tạo 2 bóng lệch trái/phải
38-
spawnSplitBall(pos, velocity, 20);
39-
spawnSplitBall(pos, velocity, -20);
37+
// chỉ nhân đôi: mỗi bóng cũ sinh thêm 1 bản sao duy nhất
38+
spawnDuplicateBall(pos, velocity);
4039
});
4140
}
4241
}
4342

44-
private void spawnSplitBall(Point2D pos, Point2D velocity, double deg) {
45-
double angle = Math.toRadians(deg);
46-
Point2D newVelocity = rotateVector(velocity, angle);
43+
private void spawnDuplicateBall(Point2D pos, Point2D velocity) {
44+
// lệch nhẹ góc bay để tránh trùng hướng
45+
Point2D newVelocity = rotateVector(velocity, 15);
4746

48-
// spawn tại vị trí bóng cũ, nhưng dịch nhẹ theo hướng mới để tránh overlap
47+
// spawn tại vị trí bóng gốc (dịch nhẹ 1 chút)
4948
Point2D spawnPos = pos.add(newVelocity.normalize().multiply(8));
5049

51-
Entity newBall = FXGL.spawn("ball", spawnPos);
50+
Entity newBall = FXGL.spawn("ball", new SpawnData(spawnPos.getX(), spawnPos.getY()));
5251

53-
// ép đặt velocity sau khi spawn (ghi đè mọi mặc định trong BallFactory)
5452
newBall.getComponentOptional(PhysicsComponent.class).ifPresent(newPhys -> {
5553
newPhys.setLinearVelocity(newVelocity);
5654

57-
// đảm bảo ngay frame sau velocity vẫn giữ nguyên
55+
// giữ velocity ổn định sau 1 frame
5856
FXGL.runOnce(() -> newPhys.setLinearVelocity(newVelocity), javafx.util.Duration.millis(20));
5957
});
6058
}
6159

62-
private static Point2D rotateVector(Point2D v, double angleRad) {
63-
double cos = Math.cos(angleRad);
64-
double sin = Math.sin(angleRad);
60+
private static Point2D rotateVector(Point2D v, double deg) {
61+
double rad = Math.toRadians(deg);
62+
double cos = Math.cos(rad);
63+
double sin = Math.sin(rad);
6564
return new Point2D(
6665
v.getX() * cos - v.getY() * sin,
67-
v.getX() * sin + v.getY() * cos
68-
);
66+
v.getX() * sin + v.getY() * cos);
6967
}
7068
}

src/main/java/com/github/codestorm/bounceverse/factory/entities/BallFactory.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,14 @@ protected EntityBuilder getBuilder(SpawnData data) {
6767
public Entity spawnBall(SpawnData data) {
6868
final boolean attached = data.hasKey("attached") && Boolean.TRUE.equals(data.get("attached"));
6969

70-
// ✅ Ưu tiên dùng vị trí từ SpawnData nếu có
71-
Point2D pos;
70+
Point2D pos = null;
7271
if (data.hasKey("x") && data.hasKey("y")) {
7372
pos = new Point2D(data.getX(), data.getY());
7473
} else if (data.hasKey("position")) {
7574
pos = (Point2D) data.get("position");
76-
} else {
77-
pos = null;
7875
}
7976

80-
if (pos == null || (pos.getX() == 0 && pos.getY() == 0)) {
77+
if (pos == null) {
8178
var paddleOpt = FXGL.getGameWorld().getEntitiesByType(EntityType.PADDLE).stream().findFirst();
8279
if (paddleOpt.isPresent()) {
8380
var paddle = paddleOpt.get();
@@ -87,6 +84,11 @@ public Entity spawnBall(SpawnData data) {
8784
}
8885
}
8986

90-
return getBuilder(new SpawnData(pos.getX(), pos.getY()).put("attached", attached)).buildAndAttach();
87+
// giữ nguyên SpawnData gốc để không mất thông tin pos
88+
data.put("attached", attached);
89+
data.put("x", pos.getX());
90+
data.put("y", pos.getY());
91+
return getBuilder(data).buildAndAttach();
9192
}
93+
9294
}

src/main/java/com/github/codestorm/bounceverse/systems/init/GameSystem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ else if (y == 3) {
124124
}
125125
// 💣 Hàng cuối (index = 5) là explodingBrick để test nổ lan
126126
else if (y == 5) {
127-
type = "strongBrick";
127+
type = "explodingBrick";
128128
}
129129
// 💎 Các hàng còn lại là gạch thường
130130
else {

0 commit comments

Comments
 (0)