diff --git a/res/map.txt b/res/map.txt index 22a1590..081b804 100644 --- a/res/map.txt +++ b/res/map.txt @@ -5,12 +5,14 @@ CONFIG: # - background.color - The color of the background, as string # - spawn.x - The X coordinate for spawning # - spawn.y - The Y coordinate for spawning +# - music.file - The wav file to play, without the extension. filepath in res/mus/ # Note that the coordinates MUST be integers. A tile is 20x20, so if you want to # set the spawn to third tile over, it would be 20*3, which equals 60. # background.color=#000000 spawn.x=23 spawn.y=10 +music.file=chip # # The configuration ends with the empty line (ex, the one below). diff --git a/res/mus/chip.wav b/res/mus/chip.wav new file mode 100644 index 0000000..ef9630d Binary files /dev/null and b/res/mus/chip.wav differ diff --git a/res/mus/derp.wav b/res/mus/derp.wav new file mode 100644 index 0000000..8be2d15 Binary files /dev/null and b/res/mus/derp.wav differ diff --git a/res/tileset.txt b/res/tileset.txt index 96fad55..a37547e 100644 --- a/res/tileset.txt +++ b/res/tileset.txt @@ -67,6 +67,7 @@ # # Valid case-insensitive commands include: # - kill; - Kill the player +# - sound=; - Play an audio file. Do not include .wav extension. Path is relative to res/mus/ # - dither=; - Enable/Disable dithering while on tile # - filter=; - Sets the percent darkness to apply # - teleport=; - teleports to the comma separated x,y coordinates. If there is a + or - sign before one of the coordinates, it will teleport relatively. Ex. teleport=5,+1 will go to x=5 y=y+1 @@ -92,7 +93,7 @@ L tiles/lava fluid nojump dangerous default animation={500,tiles/lava,tiles/lava C tiles/dirt checkpoint _ tiles/ice speed=0.4 acceleration=0.0008 nojump slippery particle={color:#A1CAFF,count:1,iteration:35,lifetime:400,front:true,xacceleration:[-0.02|0.02],yacceleration:[-0.02|0.02]} G tiles/gravel acceleration=0.1 speed=0.5 particle={color:#A9A9A9,count:5,front:false,iteration:35,lifetime:800,xacceleration:[-0.001|0.001],yacceleration:[-0.001|0.001]} -X tiles/gravel teleport=+0,+22 +X tiles/gravel event={onentry:b} teleport=+0,+22 ~ tiles/test solid # Path tiles @@ -117,6 +118,11 @@ a ( particle={color:#5B2D00,count:1,iteration:25,lifetime:500,xacceleration:[-0.001|0.001],yacceleration:[-0.001|0.001],front:false} ) +b ( + a;a;a;a;a;a;a;a;a;a;a; + sound=derp; +) + [entities] # Default entities diff --git a/src/game/Game.java b/src/game/Game.java index a25435f..ffd751a 100644 --- a/src/game/Game.java +++ b/src/game/Game.java @@ -12,6 +12,7 @@ import java.nio.file.*; import java.text.*; import javax.imageio.*; +import javax.sound.sampled.*; import tileeditor.*; public class Game extends JPanel { @@ -109,6 +110,7 @@ public class Game extends JPanel { public BufferedImage particles_back = null; // optimize by rendering particles in a separate thread public BufferedImage particles_front = null; public String commands = ""; + public SoundPlayer mainplayer = null; public static void main(String[] args) { if(args.length != 0 && (args[0].equalsIgnoreCase("--tileeditor") || args[0].equalsIgnoreCase("-e"))) @@ -564,7 +566,13 @@ else if(yacceleration < -speed) } }}).start(); + // audio playing thread + new Thread(new Runnable() {@Override public void run() { + if(mainplayer != null) + mainplayer.loop(); + }}).start(); + // F3 statistics-updating thread new java.util.Timer().scheduleAtFixedRate(new TimerTask() {@Override public void run() { fps = frames; frames = 0; @@ -573,7 +581,7 @@ else if(yacceleration < -speed) particlecount = particles.size(); }}, 1000, 1000); - + respawn(); } @@ -712,6 +720,11 @@ public void loadMap(String name) throws Exception { this.setSpawn(this.spawnx, -tilesize * Double.parseDouble(val), true); this.y = this.spawny; break; + case "music.file": + if(mainplayer != null) + mainplayer.dispose(); + this.mainplayer = new SoundPlayer(new File("../res/mus/" + val + ".wav")); + break; default: System.out.println("Unknown config option \"" + key + "\" for map file \"" + name + "\"."); break; @@ -1393,6 +1406,9 @@ public void executeFunction(String config, String funcname) { // TODO: Make an e case "dither": eightbit = Boolean.parseBoolean(val); break; + case "sound": + new SoundPlayer(new File("../res/mus/" + val + ".wav")).play(); + break; case "filter": tile.filter = (int)((Double.parseDouble(val)) * 2.54); tile.filterset = true; @@ -1592,6 +1608,82 @@ public Event(String name, Tile tile) { } } +class SoundPlayer { + private File file = null; + private Clip clip = null; + private FloatControl controls = null; + private long position = 0; + + public SoundPlayer(File file) { + this.file = file; + + try { + this.clip = AudioSystem.getClip(); + this.clip.open(AudioSystem.getAudioInputStream(file.toURI().toURL().openStream())); + this.controls = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + } catch (Exception e) { + System.err.println("Failed to initialize sound player for file " + file.getAbsolutePath()); + e.printStackTrace(); + } + } + + public void play() { + this.clip.setMicrosecondPosition(position); + this.clip.start(); + } + + public void stop() { + this.position = 0; + this.clip.stop(); + this.clip.flush(); + } + + public void restart() { + stop(); + play(); + } + + public void loop() { + this.stop(); + this.clip.loop(Clip.LOOP_CONTINUOUSLY); + } + + public void pause() { + this.position = clip.getMicrosecondPosition(); + + this.clip.stop(); + this.clip.flush(); + } + + // call this when done with audio + public void dispose() { + try { + this.clip.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + this.clip = null; + } + } + + // 0f-1f I think? + public void setVolume(float volume) { + this.controls.setValue((float) Math.min(this.controls.getMaximum(), Math.max(this.controls.getMinimum(), volume))); + } + + public float getVolume() { + return this.controls.getValue(); + } + + public boolean isPlaying() { + return this.clip != null && this.clip.isRunning(); + } + + public File getFile() { + return this.file; + } +} + class Colors { // all of the colors in the images public static final int[] colors = new int[] {