Sound Management and Ash

162 views
Skip to first unread message

Niels Wijers

unread,
Dec 11, 2012, 5:08:58 PM12/11/12
to ash-fr...@googlegroups.com
Hey Guys,

i have two questions about using soundsfx and music ik games.
  1. how do you implement sounds in games, just with creating new sounds or may a library (which)?
  2. and if you guys have any ideas to implement sounds in ash? maybe use a signleton of may adding soundfx components to entities and parse them trough as SoundFxSystem or something
thx in advance

Richard

unread,
Dec 12, 2012, 7:42:41 AM12/12/12
to ash-fr...@googlegroups.com
Hi Niels

Sound is an odd one because we're so used to playing sounds immediately and not waiting for the game loop to get to the audio playing system before playing them, but to maintain the entity/component/system architecture that is what you have to do. So there will be an AudioComponent with the data associated with sounds that belong to a particular entity and an AudioSystem that starts, stops and generally manages the sounds for all entities.

This is the Audio component I've used in Stick Tennis. Each entity that makes sounds has an AudioComponent. This contains collections of Sounds that should be played, that are playing, that should be stopped, whether they loop, etc. Like this...

public class AudioComponent
{
  // instructions to audio system
  public var volume : Number = 1;
  public var toPlay : Vector.<Class> = new Vector.<Class>();
  public var toPlaySequence : Vector.<Vector.<Class>> = new Vector.<Vector.<Class>>();
  public var toLoop : Vector.<Class> = new Vector.<Class>();
  public var toStop : Vector.<Class> = new Vector.<Class>();
  // used by audio system to manage the sounds that are playing
  public var currentVolume : Number = 1;
  public var transform : SoundTransform = new SoundTransform();
  public var playing : Vector.<SoundWrapper> = new Vector.<SoundWrapper>();
  public var looping : Vector.<SoundWrapper> = new Vector.<SoundWrapper>();
}

The AudioComponent class also has methods to make setting the data easier (just a play() method that adds the sound to the toPlay vector, etc. Nothing fancy). If I want to play a sound, I add it to the toPlay vector, then the AudioSystem will play it. Similarly with the toLoop, toStop and toPlaySequence vectors. Setting the volume property will cause the AudioSystem to adjust the volume of all sounds belonging to this entity.

SoundWrapper is a simple value object with the bits I may need later once a sound is playing

public
class SoundWrapper
{
  public var type : Class;
  public var nextVector.<Class>;
  public var sound : Sound;
  public var channel : SoundChannel;
}

It's not as pretty as it could be, but I've not had time to explore it further. I want to get sound into the asteroids demo so I can investigate this method a bit more and show this way to do it.

Richard

Phillip Chertok

unread,
Dec 12, 2012, 8:14:18 AM12/12/12
to ash-fr...@googlegroups.com
I guess now you just need to make sure your sounds are coming from a pool for memory management sake, where you did not really have to worry about this before as a monolithic SoundManager class would tend to take care of this problem for you.


--
You received this message because you are subscribed to the Google Groups "Ash Framework" group.
Visit this group at http://groups.google.com/group/ash-framework?hl=en.
 
 



--
Phillip Chertok

Niels Wijers

unread,
Dec 12, 2012, 1:44:36 PM12/12/12
to ash-fr...@googlegroups.com
 thx for the answer Richard,

I was also going this direction. the nice thing when using a system is that you can change the sound if you have for example a spatial component and change the panning of the sound or so.

a thing where i have trouble with is the fact my code for activation or modifying sound classes are every where through my other systems 

Op woensdag 12 december 2012 13:42:41 UTC+1 schreef Richard het volgende:

Richard

unread,
Dec 13, 2012, 4:54:38 AM12/13/12
to ash-fr...@googlegroups.com
There's a few things you can do to simplify that.

1. Add methods to the Audio component for playing specific sounds -

public function jump() : void
{
  toPlay.push( JumpSound );
}

2. Use flags in a component, and let the audio system worry about playing the correct sounds -

public class Flags
{
  public var jump : Boolean;
}

public class UserControlSystem
{
  public function update( time : Number ) : void
  {
    node.flags.jump = false; // if I set the flag last time around, it's now turned off
    if( ... )
    {
      ...
      node.flags.jump = true;
    }
  }
}

public class AudioSystem
{
  public function update( time : Number ) : void
  {
    if( node.flags.jump )
    {
      // play the jump sound effect
    }
  }
}

This can get pretty complicated since different entities may want to respond differently to that event. I wouldn't use thismethod myself but I mention it in case there's a benefit or an improvement that I haven't thought of.

3. Use events, or signals. This requires sticking to a few strict rules (something I intend to write about at greater length sometime).

a. Systems may dispatch events/signals but they may not listen for them. Systems execute in strict sequence as dictated by the update loop. They may not react to events/signals because that would cause them to execute out of sequence.

b. Components may listen for events/signals but the only permitted reaction is to alter their own data. Components don't contain core game logic, but just as they may contain methods to assist in manipulating their internal data, so they may have listener methods to manipulate their own internal data.

So, for example

public class Signals
{
  public var jump : Signal0 = new Signal0();
}

public class UserControlSystem
{
  public function update( time : Number ) : void
  {
    if( ... )
    {
      ...
      node.signals.jump.dispatch();
    }
  }
}

public class Audio
{
  public var toPlay : Vector.<Class> = new Vector.<Class>();
  
  public function jumpListener() : void
  {
    toPlay.push( Jump );
  }
}

You will add a Signals component to the entity and wire the appropriate listeners within the entity's components. Then any system can dispatch any of those signals and other components that are listening for the signal, like the audio component, will alter their state accordingly.

I favour option 1 for it's simplicity or option 3 because it decouples the system (in this example) from the audio component.

Richard

Niels Wijers

unread,
Dec 13, 2012, 8:09:28 AM12/13/12
to ash-fr...@googlegroups.com
Nice, i like the third option but i dont know yet how to implement this nicely. i think number three could be also an nice solution for collision handlers when you use a physics engine

i think i'll start to use option 1 and maybe later try to experiment with the third one

thx, great answers


Op donderdag 13 december 2012 10:54:38 UTC+1 schreef Richard het volgende:

Billy Belfield

unread,
Jan 11, 2013, 4:19:10 PM1/11/13
to ash-fr...@googlegroups.com
A couple questions about the approach you used in stick tennis:

1.  Do you have a way to set # of loops, or is assumed sounds either play once or loop infinitely?
2.  In the SoundSystem do you create a new AudioWrapper for each new sound that is played, or do they stay cached?
3.  As for caching the Sound objects themselves, do you use a separate SoundManager for this or do it all in the system?

Thanks for the examples!

billy

Richard

unread,
Jan 20, 2013, 6:43:22 AM1/20/13
to ash-fr...@googlegroups.com
Hi Billy

1. I assume loops are infinite, because that's all I needed. It wouldn't be hard to add a number to the looping, but I didn't need that.

2. I create a new AudioWrapper each time, but cache the Sound object itself. But you could cache the wrappers, or pool them for reuse.

3. I use a separate SoundCache to cache the sound objects. That makes the system a little simpler.

Richard
Reply all
Reply to author
Forward
0 new messages