Skip to content

Commit

Permalink
Implement SoundSource Entities. Allow individual falloff ranges for S…
Browse files Browse the repository at this point in the history
…FXPlaybacks.
  • Loading branch information
nightm4re94 committed Sep 7, 2020
1 parent ab5529a commit 2840217
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 23 deletions.
106 changes: 106 additions & 0 deletions src/de/gurkenlabs/litiengine/entities/SoundSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package de.gurkenlabs.litiengine.entities;

import de.gurkenlabs.litiengine.Game;
import de.gurkenlabs.litiengine.environment.tilemap.MapObjectType;
import de.gurkenlabs.litiengine.environment.tilemap.TmxType;
import de.gurkenlabs.litiengine.graphics.RenderType;
import de.gurkenlabs.litiengine.physics.Collision;
import de.gurkenlabs.litiengine.resources.Resources;
import de.gurkenlabs.litiengine.sound.SFXPlayback;
import de.gurkenlabs.litiengine.sound.Sound;

@EntityInfo(renderType = RenderType.OVERLAY)
@CollisionInfo(collision = false, collisionType = Collision.NONE)
@TmxType(MapObjectType.SOUNDSOURCE)
public class SoundSource extends Entity {

private int volume;
private int range;

private boolean loop;
private Sound sound;
private SFXPlayback playback;

public SoundSource() {
}

public SoundSource(Sound sound) {
this.setSound(sound);
}

public SoundSource(String name) {
this.setSound(name);
}

public SoundSource(double x, double y) {
this.setX(x);
this.setY(y);
}

public SoundSource(double x, double y, double width, double height) {
this(x, y);
this.setWidth(width);
this.setHeight(height);
}

public int getVolume() {
return volume;
}

public void setVolume(int volume) {
this.volume = volume;
}

public boolean isLoop() {
return loop;
}

public void setLoop(boolean loop) {
this.loop = loop;
}

public Sound getSound() {
return sound;
}

public SFXPlayback getPlayback() {
return this.playback;
}

public String getSoundName() {
return this.sound.getName();
}

public int getRange() {
return range;
}

public void setRange(int range) {
this.range = range;
}

public void setSound(String name) {
this.sound = Resources.sounds().get(name);
}

public void setSound(Sound sound) {
this.sound = sound;
}

public void play() {
this.playback = Game.audio().playSound(this.getSound(), this, this.isLoop(), this.getRange());
}

public void pause() {
this.getPlayback().pausePlayback();
}

public void resume() {
this.getPlayback().resumePlayback();
}

public void stop() {
this.getPlayback().cancel();
}

}
58 changes: 58 additions & 0 deletions src/de/gurkenlabs/litiengine/environment/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import de.gurkenlabs.litiengine.entities.LightSource;
import de.gurkenlabs.litiengine.entities.MapArea;
import de.gurkenlabs.litiengine.entities.Prop;
import de.gurkenlabs.litiengine.entities.SoundSource;
import de.gurkenlabs.litiengine.entities.Spawnpoint;
import de.gurkenlabs.litiengine.entities.StaticShadow;
import de.gurkenlabs.litiengine.entities.Trigger;
Expand Down Expand Up @@ -95,6 +96,7 @@ public final class Environment implements IRenderable {
private final Collection<Creature> creatures = ConcurrentHashMap.newKeySet();
private final Collection<StaticShadow> staticShadows = ConcurrentHashMap.newKeySet();
private final Collection<LightSource> lightSources = ConcurrentHashMap.newKeySet();
private final Collection<SoundSource> soundSources = ConcurrentHashMap.newKeySet();
private final Collection<Spawnpoint> spawnPoints = ConcurrentHashMap.newKeySet();
private final Collection<MapArea> mapAreas = ConcurrentHashMap.newKeySet();
private final Collection<Trigger> triggers = ConcurrentHashMap.newKeySet();
Expand All @@ -117,6 +119,7 @@ public final class Environment implements IRenderable {
registerMapObjectLoader(new MapAreaMapObjectLoader());
registerMapObjectLoader(new StaticShadowMapObjectLoader());
registerMapObjectLoader(new CreatureMapObjectLoader());
registerMapObjectLoader(new SoundSourceMapObjectLoader());
}

/**
Expand Down Expand Up @@ -484,6 +487,7 @@ public void clear() {
this.mobileEntities.clear();
this.lightSources.clear();
this.spawnPoints.clear();
this.soundSources.clear();
this.mapAreas.clear();
this.triggers.clear();

Expand Down Expand Up @@ -1427,6 +1431,54 @@ public Spawnpoint getSpawnpoint(final String name) {
return getByName(this.spawnPoints, name);
}

/**
* Gets an immutable collection containing all {@link SoundSource} entities on this environment.
*
* <p>
* To add or remove entities, use the corresponding methods on this environment.
* </p>
*
* @return An immutable collection with all {@link SoundSource} entities.
*
* @see #add(IEntity)
* @see #addAll(Iterable)
* @see #remove(IEntity)
* @see #removeAll(Iterable)
*/
public Collection<SoundSource> getSoundSources() {
return Collections.unmodifiableCollection(this.soundSources);
}

/**
* Gets the {@link SoundSource} with the specified map ID from this environment.
*
* @param mapId
* The map ID of the entity.
*
* @return The {@link SoundSource} with the specified map ID or null if no entity is found.
*
* @see #getSpawnpoint(String)
* @see #getSpawnPoints()
*/
public SoundSource getSoundSource(final int mapId) {
return getById(this.soundSources, mapId);
}

/**
* Gets the {@link SoundSource} with the specified name from this environment.
*
* @param name
* The name of the entity.
*
* @return The {@link SoundSource} with the specified name or null if no entity is found.
*
* @see #getSpawnpoint(int)
* @see #getSpawnPoints()
*/
public SoundSource getSoundSource(final String name) {
return getByName(this.soundSources, name);
}

/**
* Gets an immutable collection containing all {@link StaticShadow} entities on this environment.
*
Expand Down Expand Up @@ -1789,6 +1841,9 @@ public void remove(final IEntity entity) {
if (entity instanceof Spawnpoint) {
this.spawnPoints.remove(entity);
}
if (entity instanceof SoundSource) {
this.soundSources.remove(entity);
}

if (entity instanceof StaticShadow) {
this.staticShadows.remove(entity);
Expand Down Expand Up @@ -2248,6 +2303,9 @@ private void addEntity(final IEntity entity) {
if (entity instanceof Spawnpoint) {
this.spawnPoints.add((Spawnpoint) entity);
}
if (entity instanceof SoundSource) {
this.soundSources.add((SoundSource) entity);
}

if (entity instanceof StaticShadow) {
this.staticShadows.add((StaticShadow) entity);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package de.gurkenlabs.litiengine.environment;

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

import de.gurkenlabs.litiengine.entities.IEntity;
import de.gurkenlabs.litiengine.entities.SoundSource;
import de.gurkenlabs.litiengine.environment.tilemap.IMapObject;
import de.gurkenlabs.litiengine.environment.tilemap.MapObjectProperty;
import de.gurkenlabs.litiengine.environment.tilemap.MapObjectType;

public class SoundSourceMapObjectLoader extends MapObjectLoader {

protected SoundSourceMapObjectLoader() {
super(MapObjectType.SOUNDSOURCE);
}

@Override
public Collection<IEntity> load(Environment environment, IMapObject mapObject) {
Collection<IEntity> entities = new ArrayList<>();
if (!this.isMatchingType(mapObject)) {
return entities;
}

final SoundSource sound = this.createSoundSource(mapObject);
loadDefaultProperties(sound, mapObject);

entities.add(sound);

return entities;
}

protected SoundSource createSoundSource(IMapObject mapObject) {
SoundSource sound = new SoundSource();
sound.setSound(mapObject.getStringValue(MapObjectProperty.SOUND_NAME));
sound.setVolume(mapObject.getIntValue(MapObjectProperty.SOUND_VOLUME));
sound.setLoop(mapObject.getBoolValue(MapObjectProperty.SOUND_LOOP));
sound.setRange(mapObject.getIntValue(MapObjectProperty.SOUND_RANGE));

return sound;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public final class MapObjectProperty {
public static final String SOUND_VOLUME = "soundVolume";
public static final String SOUND_LOOP = "soundLoop";
public static final String SOUND_NAME = "soundName";
public static final String SOUND_RANGE = "soundRange";

// static shadow
public static final String SHADOW_TYPE = "shadowType";
Expand Down
9 changes: 9 additions & 0 deletions src/de/gurkenlabs/litiengine/graphics/DebugRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.DecimalFormat;
Expand All @@ -18,6 +19,7 @@
import de.gurkenlabs.litiengine.entities.ICollisionEntity;
import de.gurkenlabs.litiengine.entities.ICombatEntity;
import de.gurkenlabs.litiengine.entities.IEntity;
import de.gurkenlabs.litiengine.entities.SoundSource;
import de.gurkenlabs.litiengine.environment.Environment;
import de.gurkenlabs.litiengine.environment.tilemap.IMap;
import de.gurkenlabs.litiengine.environment.tilemap.ITile;
Expand Down Expand Up @@ -102,6 +104,13 @@ public static void renderEntityDebugInfo(final Graphics2D g, final IEntity entit
if (Game.config().debug().renderBoundingBoxes()) {
g.setColor(Color.RED);
Game.graphics().renderOutline(g, entity.getBoundingBox());

if (entity instanceof SoundSource) {
final int range = ((SoundSource) entity).getRange();
final float[] dash1 = { 10f };
final BasicStroke dashed = new BasicStroke(.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
Game.graphics().renderOutline(g, new Ellipse2D.Double(entity.getBoundingBox().getCenterX() - range, entity.getBoundingBox().getCenterY() - range, range * 2d, range * 2d), dashed);
}
}

if (Game.config().debug().renderCollisionBoxes() && entity instanceof ICollisionEntity) {
Expand Down
1 change: 1 addition & 0 deletions src/de/gurkenlabs/litiengine/graphics/RenderEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ public void renderEntity(final Graphics2D g, final IEntity entity) {

if (Game.config().debug().renderBoundingBoxes()) {
g.setColor(new Color(255, 0, 0, 50));
renderOutline(g, new Rectangle2D.Double(entity.getX(), entity.getY(), img.getWidth(), img.getWidth()));
ShapeRenderer.renderOutlineTransformed(g, new Rectangle2D.Double(renderLocation.getX(), renderLocation.getY(), img.getWidth(), img.getWidth()), animationController.getAffineTransform(), 0.25f);
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/de/gurkenlabs/litiengine/sound/SFXPlayback.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ public class SFXPlayback extends SoundPlayback {
private Sound sound;
private FloatControl panControl;
private Supplier<Point2D> source;
private VolumeControl distance;
private int range;
private VolumeControl volume;
private boolean loop;

SFXPlayback(Sound sound, Supplier<Point2D> source, boolean loop) throws LineUnavailableException {
SFXPlayback(Sound sound, Supplier<Point2D> source, boolean loop, int range) throws LineUnavailableException {
super(sound.getFormat());
this.loop = loop;
this.sound = sound;
this.panControl = this.line.isControlSupported(FloatControl.Type.PAN) ? (FloatControl) this.line.getControl(FloatControl.Type.PAN) : null;
this.source = source;
this.distance = this.createVolumeControl();
this.range=range;
this.volume = this.createVolumeControl();
}

@Override
Expand All @@ -46,9 +48,9 @@ void updateLocation(Point2D listenerLocation) {
if (this.panControl != null) {
this.panControl.setValue(dist > 0 ? (float) (dx / dist) : 0f);
}
this.distance.set(Game.config().sound().getSoundVolume() * (float) Math.max(1.0 - dist / Game.audio().getMaxDistance(), 0.0));
this.volume.set(Game.config().sound().getSoundVolume() * (float) Math.max(1.0 - dist / this.range, 0.0));
} else {
this.distance.set(Game.config().sound().getSoundVolume());
this.volume.set(Game.config().sound().getSoundVolume());
}
}

Expand Down
Loading

1 comment on commit 2840217

@nightm4re94
Copy link
Member Author

Choose a reason for hiding this comment

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

This resolves #217.

Please sign in to comment.