-
-
Notifications
You must be signed in to change notification settings - Fork 628
Open
Description
Discussed in #1434
Originally posted by LifeDrainingCoding September 17, 2025
I wonder , why FXGL doesn't have Timer Component that will schedule task by given interval?
This will allows devs to execute tasks to each entity individually at individually calculated interval.
My use case: I have a Marble that's shoots projectiles , and when this projectile collides with another Marble that will lower it's radius or disappear. Shoot rate of Marble depends on it's radius, so i need update interval every radius change.
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.entity.components.BoundingBoxComponent;
import com.almasb.fxgl.entity.components.CollidableComponent;
import com.almasb.fxgl.entity.components.ViewComponent;
import com.almasb.fxgl.physics.BoundingShape;
import com.almasb.fxgl.physics.HitBox;
import com.almasb.fxgl.physics.PhysicsComponent;
import com.almasb.fxgl.physics.box2d.dynamics.BodyDef;
import com.almasb.fxgl.physics.box2d.dynamics.BodyType;
import com.almasb.fxgl.physics.box2d.dynamics.FixtureDef;
import com.lifedrained.fxglphysicstest.FXGLTest;
import com.lifedrained.fxglphysicstest.components.TimerComponent;
import com.lifedrained.fxglphysicstest.types.TypeOf;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
import java.util.UUID;
import static com.lifedrained.fxglphysicstest.SpawnDataKeys.*;
public class Marble extends Entity {
protected boolean isShooting =false;
protected PhysicsComponent physics;
protected BodyDef bodyDef;
protected FixtureDef fixtureDef;
protected ViewComponent view;
protected BoundingBoxComponent bbox;
protected TimerComponent timer = new TimerComponent();
protected double radius, mass,area , density = 0;
public Marble(SpawnData data) {
super();
setX(data.getX());
setY(data.getY());
setType(TypeOf.MARBLE_TYPE);
radius = data.get(RADIUS);
mass = data.get(MASS);
bodyDef = new BodyDef();
bodyDef.setUserData(UUID.randomUUID().toString());
fixtureDef = new FixtureDef();
fixtureDef.setFriction(0.1f);
fixtureDef.setRestitution(0.1f);
updateMassRelated(0);
view = getComponent(ViewComponent.class);
view.clearChildren();
view.addChild(new Circle(radius, Color.RED));
physics = new PhysicsComponent();
physics.setBodyDef(bodyDef);
physics.setFixtureDef(fixtureDef);
physics.setBodyType(BodyType.DYNAMIC);
bbox = getBoundingBoxComponent();
bbox.addHitBox(new HitBox(BoundingShape.circle(radius)));
addComponent(new CollidableComponent(true));
addComponent(physics);
addComponent(timer);
}
public void setRadius(double radius) {
this.radius = radius;
updateBody();
}
public void updateBody(){
view.clearChildren();
view.addChild(new Circle(radius, Color.RED));
bbox.clearHitBoxes();
bbox.addHitBox(new HitBox(BoundingShape.circle(radius)));
setupTimer();
}
public void startShooting(){
if (!isShooting){
isShooting = true;
setupTimer();
}
}
public void shoot(){
if (isActive()) {
double x, y;
SpawnData spawnData = new SpawnData(0, 0);
spawnData.put(OWNER, this);
Bullet bullet = new Bullet(spawnData);
x = radius * Math.cos(bullet.getRadiansDirection())+getX();
y = radius * Math.sin(bullet.getRadiansDirection())+getY();
bullet.setPosition(x, y);
FXGL.getGameWorld().addEntity(bullet);
}
}
private void setupTimer(){
timer.clear();
timer.runAtInterval(this::shoot, Duration.millis(2000*(FXGLTest.DEFAULT_RADIUS / radius)));
}
}And simple realization of TimerComponent :
import com.almasb.fxgl.entity.component.Component;
import com.almasb.fxgl.time.Timer;
import javafx.util.Duration;
public class TimerComponent extends Component {
private Timer timer = new Timer();
@Override
public void onUpdate(double tpf) {
super.onUpdate(tpf);
timer.update(tpf);
}
public void runAtInterval(Runnable action, Duration duration) {
timer.runAtInterval(action,duration );
}
public void runOnceAfter(Runnable action, Duration duration) {
timer.runOnceAfter(action,duration);
}
public void clear(){
timer.clear();
}
}Metadata
Metadata
Assignees
Labels
No labels