Skip to content

Commit

Permalink
Resolve #415 - Implement customizable particle outline thickness.
Browse files Browse the repository at this point in the history
  • Loading branch information
nightm4re94 committed Sep 6, 2024
1 parent 4143196 commit 5ce5d6a
Show file tree
Hide file tree
Showing 10 changed files with 411 additions and 311 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package de.gurkenlabs.litiengine.environment;

import java.util.ArrayList;
import java.util.Collection;

import de.gurkenlabs.litiengine.Align;
import de.gurkenlabs.litiengine.Valign;
import de.gurkenlabs.litiengine.configuration.Quality;
import de.gurkenlabs.litiengine.entities.IEntity;
import de.gurkenlabs.litiengine.environment.tilemap.IMapObject;
import de.gurkenlabs.litiengine.environment.tilemap.MapObjectProperty;
import de.gurkenlabs.litiengine.environment.tilemap.MapObjectProperty.Particle;
import de.gurkenlabs.litiengine.environment.tilemap.MapObjectType;
import de.gurkenlabs.litiengine.environment.tilemap.xml.MapObject;
import de.gurkenlabs.litiengine.graphics.emitters.Emitter;
Expand All @@ -18,15 +16,16 @@
import de.gurkenlabs.litiengine.physics.Collision;
import de.gurkenlabs.litiengine.util.ArrayUtilities;
import de.gurkenlabs.litiengine.util.ColorHelper;
import java.util.ArrayList;
import java.util.Collection;

public class EmitterMapObjectLoader extends MapObjectLoader {

protected EmitterMapObjectLoader() {
super(MapObjectType.EMITTER);
}

@Override
public Collection<IEntity> load(Environment environment, IMapObject mapObject) {
@Override public Collection<IEntity> load(Environment environment, IMapObject mapObject) {
Collection<IEntity> entities = new ArrayList<>();
if (!this.isMatchingType(mapObject)) {
return entities;
Expand Down Expand Up @@ -86,6 +85,8 @@ public static EmitterData createEmitterData(IMapObject mapObject) {
mapObject.getFloatValue(MapObjectProperty.Particle.DELTA_ANGLE_MAX, 0)));
data.setParticleTTL(new ParticleParameter(mapObject.getFloatValue(MapObjectProperty.Particle.TTL_MIN, 0),
mapObject.getFloatValue(MapObjectProperty.Particle.TTL_MAX, 0)));
data.setOutlineThickness(new ParticleParameter(mapObject.getFloatValue(Particle.OUTLINETHICKNESS_MIN, 1f),
mapObject.getFloatValue(MapObjectProperty.Particle.OUTLINETHICKNESS_MAX, 1f)));

data.setCollision(mapObject.getEnumValue(MapObjectProperty.COLLISION_TYPE, Collision.class, EmitterData.DEFAULT_COLLISION));
data.setRequiredQuality(mapObject.getEnumValue(MapObjectProperty.REQUIRED_QUALITY, Quality.class, EmitterData.DEFAULT_REQUIRED_QUALITY));
Expand Down Expand Up @@ -122,34 +123,34 @@ public static void updateMapObject(EmitterData emitterData, IMapObject mo) {
String commaSeperatedColors = ArrayUtilities.join(emitterData.getColors());
mo.setValue(MapObjectProperty.Emitter.COLORS, commaSeperatedColors);

// Particle parameters, min bounds
mo.setValue(MapObjectProperty.Particle.OFFSET_X_MIN, emitterData.getParticleOffsetX().getMinValue());
mo.setValue(MapObjectProperty.Particle.OFFSET_Y_MIN, emitterData.getParticleOffsetY().getMinValue());
mo.setValue(MapObjectProperty.Particle.STARTWIDTH_MIN, emitterData.getParticleWidth().getMinValue());
mo.setValue(MapObjectProperty.Particle.STARTHEIGHT_MIN, emitterData.getParticleHeight().getMinValue());
mo.setValue(MapObjectProperty.Particle.VELOCITY_X_MIN, emitterData.getVelocityX().getMinValue());
mo.setValue(MapObjectProperty.Particle.VELOCITY_Y_MIN, emitterData.getVelocityY().getMinValue());
mo.setValue(MapObjectProperty.Particle.ACCELERATION_X_MAX, emitterData.getAccelerationX().getMaxValue());
mo.setValue(MapObjectProperty.Particle.ACCELERATION_X_MIN, emitterData.getAccelerationX().getMinValue());
mo.setValue(MapObjectProperty.Particle.ACCELERATION_Y_MAX, emitterData.getAccelerationY().getMaxValue());
mo.setValue(MapObjectProperty.Particle.ACCELERATION_Y_MIN, emitterData.getAccelerationY().getMinValue());
mo.setValue(MapObjectProperty.Particle.DELTAWIDTH_MIN, emitterData.getDeltaWidth().getMinValue());
mo.setValue(MapObjectProperty.Particle.DELTAHEIGHT_MIN, emitterData.getDeltaHeight().getMinValue());
mo.setValue(MapObjectProperty.Particle.ANGLE_MAX, emitterData.getAngle().getMaxValue());
mo.setValue(MapObjectProperty.Particle.ANGLE_MIN, emitterData.getAngle().getMinValue());
mo.setValue(MapObjectProperty.Particle.DELTA_ANGLE_MAX, emitterData.getDeltaAngle().getMaxValue());
mo.setValue(MapObjectProperty.Particle.DELTA_ANGLE_MIN, emitterData.getDeltaAngle().getMinValue());
mo.setValue(MapObjectProperty.Particle.TTL_MIN, emitterData.getParticleTTL().getMinValue());
// Particle parameters, max bounds
mo.setValue(MapObjectProperty.Particle.DELTAHEIGHT_MAX, emitterData.getDeltaHeight().getMaxValue());
mo.setValue(MapObjectProperty.Particle.DELTAHEIGHT_MIN, emitterData.getDeltaHeight().getMinValue());
mo.setValue(MapObjectProperty.Particle.DELTAWIDTH_MAX, emitterData.getDeltaWidth().getMaxValue());
mo.setValue(MapObjectProperty.Particle.DELTAWIDTH_MIN, emitterData.getDeltaWidth().getMinValue());
mo.setValue(MapObjectProperty.Particle.OFFSET_X_MAX, emitterData.getParticleOffsetX().getMaxValue());
mo.setValue(MapObjectProperty.Particle.OFFSET_X_MIN, emitterData.getParticleOffsetX().getMinValue());
mo.setValue(MapObjectProperty.Particle.OFFSET_Y_MAX, emitterData.getParticleOffsetY().getMaxValue());
mo.setValue(MapObjectProperty.Particle.STARTWIDTH_MAX, emitterData.getParticleWidth().getMaxValue());
mo.setValue(MapObjectProperty.Particle.OFFSET_Y_MIN, emitterData.getParticleOffsetY().getMinValue());
mo.setValue(MapObjectProperty.Particle.OUTLINETHICKNESS_MAX, emitterData.getOutlineThickness().getMaxValue());
mo.setValue(MapObjectProperty.Particle.OUTLINETHICKNESS_MIN, emitterData.getOutlineThickness().getMinValue());
mo.setValue(MapObjectProperty.Particle.STARTHEIGHT_MAX, emitterData.getParticleHeight().getMaxValue());
mo.setValue(MapObjectProperty.Particle.STARTHEIGHT_MIN, emitterData.getParticleHeight().getMinValue());
mo.setValue(MapObjectProperty.Particle.STARTWIDTH_MAX, emitterData.getParticleWidth().getMaxValue());
mo.setValue(MapObjectProperty.Particle.STARTWIDTH_MIN, emitterData.getParticleWidth().getMinValue());
mo.setValue(MapObjectProperty.Particle.TTL_MAX, emitterData.getParticleTTL().getMaxValue());
mo.setValue(MapObjectProperty.Particle.TTL_MIN, emitterData.getParticleTTL().getMinValue());
mo.setValue(MapObjectProperty.Particle.VELOCITY_X_MAX, emitterData.getVelocityX().getMaxValue());
mo.setValue(MapObjectProperty.Particle.VELOCITY_X_MIN, emitterData.getVelocityX().getMinValue());
mo.setValue(MapObjectProperty.Particle.VELOCITY_Y_MAX, emitterData.getVelocityY().getMaxValue());
mo.setValue(MapObjectProperty.Particle.ACCELERATION_X_MAX, emitterData.getAccelerationX().getMaxValue());
mo.setValue(MapObjectProperty.Particle.ACCELERATION_Y_MAX, emitterData.getAccelerationY().getMaxValue());
mo.setValue(MapObjectProperty.Particle.DELTAWIDTH_MAX, emitterData.getDeltaWidth().getMaxValue());
mo.setValue(MapObjectProperty.Particle.DELTAHEIGHT_MAX, emitterData.getDeltaHeight().getMaxValue());
mo.setValue(MapObjectProperty.Particle.ANGLE_MAX, emitterData.getAngle().getMaxValue());
mo.setValue(MapObjectProperty.Particle.DELTA_ANGLE_MAX, emitterData.getDeltaAngle().getMaxValue());
mo.setValue(MapObjectProperty.Particle.TTL_MAX, emitterData.getParticleTTL().getMaxValue());
mo.setValue(MapObjectProperty.Particle.VELOCITY_Y_MIN, emitterData.getVelocityY().getMinValue());

mo.setValue(MapObjectProperty.COLLISION_TYPE, emitterData.getCollision());
mo.setValue(MapObjectProperty.REQUIRED_QUALITY, emitterData.getRequiredQuality());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ public static final class Particle {
public static final String FADE = "particleFade";
public static final String FADEONCOLLISION = "particleFadeOnCollision";
public static final String OUTLINEONLY = "particleOutlineOnly";
public static final String OUTLINETHICKNESS_MIN = "particleMinOutlineThickness";
public static final String OUTLINETHICKNESS_MAX = "particleMaxOutlineThickness";
public static final String ANTIALIASING = "particleAntiAliasing";

private Particle() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ public Emitter() {
this.emitterData.setSpawnAmount(info.spawnAmount());
this.emitterData.setSpawnRate(info.spawnRate());
this.emitterData.setEmitterDuration(info.duration());
this.emitterData.setParticleTTL(
new ParticleParameter(info.particleMinTTL(), info.particleMaxTTL()));
this.emitterData.setParticleTTL(new ParticleParameter(info.particleMinTTL(), info.particleMaxTTL()));
this.emitterData.setUpdateRate(info.particleUpdateRate());
this.emitterData.setOriginAlign(info.originAlign());
this.emitterData.setOriginValign(info.originValign());
Expand Down Expand Up @@ -134,8 +133,7 @@ public void activate() {
/**
* Adds a particle to this Emitter's list of Particles.
*
* @param particle
* the particle
* @param particle the particle
*/
public void addParticle(final Particle particle) {
if (this.isStopped()) {
Expand Down Expand Up @@ -188,7 +186,7 @@ public Point2D getOrigin() {

protected void updateOrigin() {
this.origin = new Point2D.Double(getX() + data().getOriginAlign().getValue(getWidth()),
getY() + data().getOriginValign().getValue(getHeight()));
getY() + data().getOriginValign().getValue(getHeight()));
}

public IRenderable getRenderable(RenderType type) {
Expand Down Expand Up @@ -237,8 +235,7 @@ public boolean isPaused() {
/**
* Sets the paused.
*
* @param paused
* the new paused
* @param paused the new paused
*/
public void setPaused(final boolean paused) {
this.paused = paused;
Expand Down Expand Up @@ -285,8 +282,8 @@ public void setEmitterData(final String emitterXmlPath) {
@Override
public boolean timeToLiveReached() {
return this.activated
&& this.getTimeToLive() > 0
&& this.getAliveTime() >= this.getTimeToLive();
&& this.getTimeToLive() > 0
&& this.getAliveTime() >= this.getTimeToLive();
}

public void togglePaused() {
Expand Down Expand Up @@ -333,7 +330,7 @@ public void update() {

this.aliveTime = Game.time().since(this.activationTick);
if ((this.data().getSpawnRate() == 0
|| Game.time().since(this.lastSpawn) >= this.data().getSpawnRate())) {
|| Game.time().since(this.lastSpawn) >= this.data().getSpawnRate())) {
this.lastSpawn = Game.time().now();
this.spawnParticle();
}
Expand Down Expand Up @@ -373,7 +370,7 @@ protected Particle createNewParticle() {
}
case TEXT -> {
String text = data().getTexts().isEmpty() ? EmitterData.DEFAULT_TEXT
: Game.random().choose(data().getTexts());
: Game.random().choose(data().getTexts());
return new TextParticle(text).init(data());
}
case SPRITE -> {
Expand All @@ -382,7 +379,7 @@ protected Particle createNewParticle() {
return null;
}
return new SpriteParticle(sprite).setAnimateSprite(data().isAnimatingSprite())
.setLoopSprite(data().isLoopingSprite()).init(data());
.setLoopSprite(data().isLoopingSprite()).init(data());
}
default -> {
return new RectangleParticle(width, height).init(data());
Expand All @@ -393,8 +390,7 @@ protected Particle createNewParticle() {
/**
* Particle can be removed.
*
* @param particle
* the particle
* @param particle the particle
* @return true, if successful
*/
protected boolean particleCanBeRemoved(final Particle particle) {
Expand All @@ -415,29 +411,27 @@ protected void spawnParticle() {
}

/**
* Render particles of this effect. The particles are always rendered relatively to this effects render location. A
* particle doesn't have an own map location. It is always relative to the effect it is assigned to.
* Render particles of this effect. The particles are always rendered relatively to this effects render location. A particle doesn't have an own map
* location. It is always relative to the effect it is assigned to.
*
* @param g
* The graphics object to draw on.
* @param renderType
* The render type.
* @param g The graphics object to draw on.
* @param renderType The render type.
*/
private void renderParticles(final Graphics2D g, final RenderType renderType) {
if (Game.config().graphics().getGraphicQuality().getValue() < this.data().getRequiredQuality()
.getValue()) {
.getValue()) {
return;
}

final Rectangle2D viewport =
Game.screens() != null && Game.world().camera() != null
? Game.world().camera().getViewport()
: null;
Game.screens() != null && Game.world().camera() != null
? Game.world().camera().getViewport()
: null;
for (Particle particle : this.particles) {
if (((!particle.usesCustomRenderType() && renderType == RenderType.NONE)
|| (particle.usesCustomRenderType() && particle.getCustomRenderType() == renderType))
&& viewport != null
&& viewport.intersects(particle.getBoundingBox(getOrigin()))) {
|| (particle.usesCustomRenderType() && particle.getCustomRenderType() == renderType))
&& viewport != null
&& viewport.intersects(particle.getBoundingBox(getOrigin()))) {
particle.render(g, getOrigin());
}
}
Expand Down
Loading

0 comments on commit 5ce5d6a

Please sign in to comment.