private static final float IDEAL_FRAME_RATE = 30f;
ActorSystem currentActorSystem;
PhysicsSystem currentPhysicsSystem;
ObjectPool<Actor> actorPool;
AbstractBackground gradationBackground;
ActorBuilder fireworksBallBuilder;
frameRate(IDEAL_FRAME_RATE);
colorMode(HSB, 360f, 100f, 100f, 100f);
gradationBackground = new GradationBackground(width, height, color(240f, 100f, 10f, 30f), color(240f, 100f, 40f, 30f), 2f);
gradationBackground.display();
translate(width * 0.5f, 0f);
currentPhysicsSystem.update();
currentActorSystem.run();
if (frameCount % 240 == 30) launchFireworks();
if (mousePressed) drawDebugInfo();
currentActorSystem = new ActorSystem();
currentPhysicsSystem = new PhysicsSystem();
currentPhysicsSystem.addForceField(new GravityForceField(currentPhysicsSystem.bodyList));
currentPhysicsSystem.addForceField(new StableAtmosphereDragForceField(currentPhysicsSystem.bodyList));
void initializeObjectPool() {
actorPool = new ObjectPool<Actor>(4096);
for (int i = 0; i < actorPool.poolSize; i++) {
Actor newObject = new Actor();
newObject.belongingPool = actorPool;
actorPool.add(newObject);
Actor ball = fireworksBallBuilder.build(random(-50f, 50f), height, 0f, - 100f / IDEAL_FRAME_RATE);
ball.lifetimeFrameCount = int((4f + random(-0.5f, 0.5f)) * IDEAL_FRAME_RATE);
currentActorSystem.registerNewActor(ball);
text(round(frameRate) + " FPS", 10f, 20f);
text(actorPool.index + " particles", 10f, 40f);
void defineActorTypes() {
ActorBuilder burningGunpowderBuilder = new ActorBuilder();
burningGunpowderBuilder.pool = actorPool;
burningGunpowderBuilder.displayer = new ShrinkActorDisplayer(createLightImage(1f, 1f, 0.9f, 1f, 1f, 10));
burningGunpowderBuilder.component = new ImmutablePhysicsBodyComponent(0.005f, 0.02f);
burningGunpowderBuilder.lifetimeFrameCount = int(IDEAL_FRAME_RATE * 0.5f);
ActorBuilder flashingGunpowderBuilder = new ActorBuilder();
flashingGunpowderBuilder.pool = actorPool;
flashingGunpowderBuilder.component = new ImmutablePhysicsBodyComponent(0.005f, 0.02f);
flashingGunpowderBuilder.lifetimeFrameCount = int(IDEAL_FRAME_RATE * 2.5f);
ActorBuilder gunpowderBallBuilder = new ActorBuilder();
gunpowderBallBuilder.pool = actorPool;
gunpowderBallBuilder.component = new ImmutablePhysicsBodyComponent(0.2f, 0.05f);
gunpowderBallBuilder.lifetimeFrameCount = int(IDEAL_FRAME_RATE * 4.5f);
gunpowderBallBuilder.actionList.add(new LeaveGunpowderFireAction(flashingGunpowderBuilder));
ArrayList<ActorDisplayer> displayerCandidateList = new ArrayList<ActorDisplayer>();
displayerCandidateList.add(new FlashActorDisplayer(createLightImage(1f, 1f, 1f, 1f, 1f, 20)));
displayerCandidateList.add(new FlashActorDisplayer(createLightImage(1f, 0.5f, 0.5f, 1f, 1f, 20)));
displayerCandidateList.add(new FlashActorDisplayer(createLightImage(1f, 0.75f, 0.5f, 1f, 1f, 20)));
displayerCandidateList.add(new FlashActorDisplayer(createLightImage(1f, 1f, 0.5f, 1f, 1f, 20)));
displayerCandidateList.add(new FlashActorDisplayer(createLightImage(0.5f, 0.75f, 1f, 1f, 1f, 20)));
displayerCandidateList.add(new FlashActorDisplayer(createLightImage(0.75f, 0.5f, 1f, 1f, 1f, 20)));
displayerCandidateList.add(new FlashActorDisplayer(createLightImage(1f, 0.5f, 6f, 1f, 1f, 20)));
fireworksBallBuilder = new ActorBuilder();
fireworksBallBuilder.pool = actorPool;
fireworksBallBuilder.displayer = new ShrinkActorDisplayer(createLightImage(1f, 1f, 0.9f, 1f, 4f, 20));
fireworksBallBuilder.component = new ImmutablePhysicsBodyComponent(70f, 0.03f);
ExplodeFireAction explode = new ExplodeFireAction(gunpowderBallBuilder);
for(ActorDisplayer currentObject : displayerCandidateList) {
explode.displayerCandidateList.add(currentObject);
fireworksBallBuilder.actionList.add(explode);
fireworksBallBuilder.actionList.add(new BurnFireAction(burningGunpowderBuilder));
final PImage createLightImage(float redFactor, float greenFactor, float blueFactor, float alphaFactor, float lightRadius, int graphicsSize) {
float halfSideLength = graphicsSize / 2f;
PImage newImage = createImage(graphicsSize, graphicsSize, ARGB);
for (int pixelYPosition = 0; pixelYPosition < graphicsSize; pixelYPosition++) {
for (int pixelXPosition = 0; pixelXPosition < graphicsSize; pixelXPosition++) {
float distanceFromCenter = max(sqrt(sq(halfSideLength - pixelXPosition) + sq(halfSideLength - pixelYPosition)), 1f);
float exponent = ((log(255)) / log(halfSideLength)) / (1f - log(lightRadius) / log(halfSideLength));
float alphaRatio = pow(lightRadius / distanceFromCenter, exponent);
newImage.pixels[pixelXPosition + pixelYPosition * graphicsSize] = color(255f * redFactor, 255f * greenFactor, 255f * blueFactor, 255f * alphaFactor * alphaRatio);