Added directional sound.

This commit is contained in:
Andrew Lalis 2021-06-30 20:51:16 +02:00
parent 3b9519cbca
commit b8311cd0b5
5 changed files with 79 additions and 22 deletions

View File

@ -80,7 +80,7 @@ public class Client {
team.setScore(t.getScore()); team.setScore(t.getScore());
} }
} }
this.soundManager.play(update.getSoundsToPlay()); this.soundManager.play(update.getSoundsToPlay(), myPlayer);
} }
public void setWorld(World world) { public void setWorld(World world) {

View File

@ -1,32 +1,56 @@
package nl.andrewlalis.aos_client; package nl.andrewlalis.aos_client;
import nl.andrewlalis.aos_core.geom.Vec2;
import nl.andrewlalis.aos_core.model.Player;
import nl.andrewlalis.aos_core.net.data.Sound; import nl.andrewlalis.aos_core.net.data.Sound;
import nl.andrewlalis.aos_core.net.data.SoundType;
import javax.sound.sampled.*; import javax.sound.sampled.*;
import java.io.*; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class SoundManager { public class SoundManager {
private static final int CLIP_COUNT = 10; private static final float HEARING_RANGE = 50.0f;
private final Map<String, List<Clip>> soundData = new HashMap<>(); private final Map<String, List<Clip>> soundData = new HashMap<>();
private final Map<String, Integer> clipIndexes = new HashMap<>(); private final Map<String, Integer> clipIndexes = new HashMap<>();
public void play(List<Sound> sounds, Player player) {
for (Sound sound : sounds) {
this.play(sound, player);
}
}
public void play(List<Sound> sounds) { public void play(List<Sound> sounds) {
for (Sound sound : sounds) { for (Sound sound : sounds) {
this.play(sound); this.play(sound, null);
} }
} }
public void play(Sound sound) { public void play(Sound sound) {
var clip = this.getClip(sound.getType().getSoundName()); this.play(sound, null);
}
public void play(Sound sound, Player player) {
var clip = this.getClip(sound.getType());
if (clip == null) { if (clip == null) {
return; return;
} }
clip.setFramePosition(0); clip.setFramePosition(0);
setVolume(clip, sound.getVolume()); float v = sound.getVolume();
if (player != null && sound.getPosition() != null) {
float dist = player.getPosition().dist(sound.getPosition());
v *= (Math.max(HEARING_RANGE - dist, 0) / HEARING_RANGE);
}
if (v <= 0.0f) return;
if (player != null && player.getTeam() != null && sound.getPosition() != null) {
setPan(clip, player.getPosition(), sound.getPosition(), player.getTeam().getOrientation());
}
setVolume(clip, v);
clip.start(); clip.start();
} }
@ -36,7 +60,19 @@ public class SoundManager {
gainControl.setValue(20f * (float) Math.log10(volume)); gainControl.setValue(20f * (float) Math.log10(volume));
} }
private Clip getClip(String sound) { private void setPan(Clip clip, Vec2 playerPos, Vec2 soundPos, Vec2 playerOrientation) {
Vec2 soundDir = soundPos
.sub(playerPos)
.rotate(playerOrientation.perp().angle())
.unit();
float pan = Math.max(Math.min(soundDir.dot(Vec2.RIGHT), 1.0f), -1.0f);
if (Float.isNaN(pan)) pan = 0f;
FloatControl panControl = (FloatControl) clip.getControl(FloatControl.Type.PAN);
panControl.setValue(pan);
}
private Clip getClip(SoundType soundType) {
String sound = soundType.getSoundName();
var clips = this.soundData.get(sound); var clips = this.soundData.get(sound);
if (clips == null) { if (clips == null) {
InputStream is = Client.class.getResourceAsStream("/nl/andrewlalis/aos_client/sound/" + sound); InputStream is = Client.class.getResourceAsStream("/nl/andrewlalis/aos_client/sound/" + sound);
@ -48,8 +84,8 @@ public class SoundManager {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
is.transferTo(bos); is.transferTo(bos);
byte[] data = bos.toByteArray(); byte[] data = bos.toByteArray();
clips = new ArrayList<>(CLIP_COUNT); clips = new ArrayList<>(soundType.getClipBufferCount());
for (int i = 0; i < CLIP_COUNT; i++) { for (int i = 0; i < soundType.getClipBufferCount(); i++) {
var ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(data)); var ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(data));
var clip = AudioSystem.getClip(); var clip = AudioSystem.getClip();
clip.open(ais); clip.open(ais);
@ -64,7 +100,7 @@ public class SoundManager {
} }
} }
int index = this.clipIndexes.get(sound); int index = this.clipIndexes.get(sound);
if (index >= CLIP_COUNT) { if (index >= soundType.getClipBufferCount()) {
index = 0; index = 0;
} }
Clip clip = clips.get(index); Clip clip = clips.get(index);

View File

@ -9,6 +9,9 @@ import java.util.concurrent.ThreadLocalRandom;
public record Vec2(float x, float y) implements Serializable { public record Vec2(float x, float y) implements Serializable {
public static final Vec2 ZERO = new Vec2(0, 0); public static final Vec2 ZERO = new Vec2(0, 0);
public static final Vec2 UP = new Vec2(0, -1); public static final Vec2 UP = new Vec2(0, -1);
public static final Vec2 DOWN = new Vec2(0, 1);
public static final Vec2 RIGHT = new Vec2(1, 0);
public static final Vec2 LEFT = new Vec2(-1, 0);
public float mag() { public float mag() {

View File

@ -8,24 +8,26 @@ import java.util.Map;
* efficient transmission to clients. * efficient transmission to clients.
*/ */
public enum SoundType { public enum SoundType {
SHOT_SMG(0, "ak47shot1.wav"), SHOT_SMG(0, "ak47shot1.wav", 25),
SHOT_RIFLE(1, "m1garand-shot1.wav"), SHOT_RIFLE(1, "m1garand-shot1.wav", 25),
SHOT_SHOTGUN(2, "shotgun-shot1.wav"), SHOT_SHOTGUN(2, "shotgun-shot1.wav", 25),
RELOAD(3, "reload.wav"), RELOAD(3, "reload.wav", 10),
CHAT(4, "chat.wav"), CHAT(4, "chat.wav", 5),
DEATH(5, "death.wav"), DEATH(5, "death.wav", 5),
BULLET_IMPACT_1(6, "bullet_impact_1.wav"), BULLET_IMPACT_1(6, "bullet_impact_1.wav", 10),
BULLET_IMPACT_2(7, "bullet_impact_2.wav"), BULLET_IMPACT_2(7, "bullet_impact_2.wav", 10),
BULLET_IMPACT_3(8, "bullet_impact_3.wav"), BULLET_IMPACT_3(8, "bullet_impact_3.wav", 10),
BULLET_IMPACT_4(9, "bullet_impact_4.wav"), BULLET_IMPACT_4(9, "bullet_impact_4.wav", 10),
BULLET_IMPACT_5(10, "bullet_impact_5.wav"); BULLET_IMPACT_5(10, "bullet_impact_5.wav", 10);
private final byte code; private final byte code;
private final String soundName; private final String soundName;
private final int clipBufferCount;
SoundType(int code, String soundName) { SoundType(int code, String soundName, int clipBufferCount) {
this.code = (byte) code; this.code = (byte) code;
this.soundName = soundName; this.soundName = soundName;
this.clipBufferCount = clipBufferCount;
} }
public byte getCode() { public byte getCode() {
@ -36,6 +38,10 @@ public enum SoundType {
return soundName; return soundName;
} }
public int getClipBufferCount() {
return clipBufferCount;
}
private static final Map<Byte, SoundType> typeIndex = new HashMap<>(); private static final Map<Byte, SoundType> typeIndex = new HashMap<>();
static { static {
for (var val : values()) { for (var val : values()) {

View File

@ -60,6 +60,18 @@ gun-settings:
bullet-speed: 90 bullet-speed: 90
base-damage: 40 base-damage: 40
- name: M-249
category: SMG
color: "#001942"
max-clip-count: 3
clip-size: 100
bullets-per-round: 1
accuracy: 0.08
shot-cooldown-time: 0.03
reload-time: 3.5
bullet-speed: 80
base-damage: 35
- name: M1 Garand - name: M1 Garand
category: RIFLE category: RIFLE
color: "#452d06" color: "#452d06"