Architecture: Preloading same sounds?

Hello,

My game has 50 animals, each making unique sounds. When the game starts up, 5-25 random animals will be on the screen (it will be different between each player). When player picks up an animal, the animal makes a noise.

I don’t want to preload all 50 animal sounds at the beginning of the game because the player might not need all of the sounds (if they only see 5 and then leave the game).

Right now, I have it so when the player picks up an animal, it preloads that sound and plays it. But if the player picks up the same animal 3 times in a row, it will preload the sound 3 times. Is there a way to detect if a sound has been preloaded so as not to load it again?

Or is there a better way for me to do this? Any suggestions please. :slight_smile:


Along those lines, unloading effects would requiring knowing which sounds were loaded. I am thinking of tracking the loaded sounds in a list and then looping through it to unload in the end. Is this correct?

Thank you for your help!

Maybe you could build a type to represent your data. Either a struct, or a class.
If my assumptions about cocos are wrong, and this is a needless abstraction, then ignore this:

// Struct :
//   Manually set the attributes as you modify them. Keeping a list of this wouldn't be so bad.
typedef struct {
  bool loaded;
  std::string name;
}  SoundInfo;

// Class:
//   Makes more sense imo, since the data has state. Your desired behavior can be handled
//   internally. Untested.

#include "SimpleAudioEngine.h"
class MySound
{
public:
  MySound(const std::string newName);
  ~MySound();
  void load();
  void unload();
  const bool play();

  const bool getIsLoaded();
private:
  bool isLoaded;
  std::string name;
};

MySound::MySound(const std::string newName) : isLoaded(false), name("")
{
  name = newName;
  this->load();
}

MySound::~MySound() {this->unload();}

void MySound::load()
{
  if (!this->isLoaded)
  {
    SimpleAudioEngine::sharedEngine()->preloadEffect(name.c_str());
  }
}

void MySound::unload()
{
  if (this->isLoaded)
  {
    SimpleAudioEngine::sharedEngine()->unloadEffect(name.c_str());
  }
}

const bool MySound::play()
{
  // You can silently fail and return an error (return false), or preload the sound and then play it (return true).
  if (!isLoaded) {this->load();}
  SimpleAudioEngine::sharedEngine()->playEffect(name.c_str());
  return true;
}

const bool MySound::getIsLoaded() {return isLoaded;}

// Using MySound:
//   Scenario: There's a dog, a cow, and a duck.
MySound dogBark("bark.wav");
MySound cowMoo("moo.wav");
MySound duckQuack("quack.wav");

//  If they leave scope, they will be destroyed and unloaded automatically, until then you can play them
//  with a "fire and forget" philosophy. Now you don't need their handling logic muddying up your scene logic.
// Their lifecycle is up to you.
void playerPicksUpAnimalCallback(AnimalNode* const animal)
{
  const int ANIMAL_TYPE = animal->getTag();
  enum {DOG, COW, DUCK, PIG, SNAKE};
  switch (ANIMAL_TYPE)
  {
    case DOG:
      dogBark.play();
      break;
    case COW:
      cowMoo.play();
      break;
    case DUCK:
      duckQuack.play();
      break;
    // etc.
  };
}

What do you think about something like this?

Ah wow Justin! Thank you so much for putting a lot of thought into this! Abstracting it like the way you did would suffice.

Thank you so much! :smiley: