Stopping Audio

This topic contains 10 replies, has 4 voices, and was last updated by  Joethemonkey101 3 years, 8 months ago.

Viewing 11 posts - 1 through 11 (of 11 total)
Author Posts
Author Posts
June 29, 2010 at 9:26 pm #222837

Joethemonkey101
@joethemonkey101

Hey guys. I want to add a sprite to my main menu that when tapped turns of the audio for the whole app. When it’s tapped again, I want the audio to go back. How can I go about doing this? I already have the sprite and 2 pictures for selected and disabled.

June 29, 2010 at 10:33 pm #288738

Kitsune
@kitsune

Here’s how to mute it with SimpleAudioEngine:

[[SimpleAudioEngine sharedEngine] setMuted: YES/NO];

June 30, 2010 at 1:54 am #288739

Joethemonkey101
@joethemonkey101

How do I connect that with my sprite? Can you show me an example please?

June 30, 2010 at 12:52 pm #288740

Joethemonkey101
@joethemonkey101

You know, like a mute button.

June 30, 2010 at 1:50 pm #288741

Synsoft
@synsoft

for something like a Mute Button I would use a mode button. basically it is two states On/Off and what they do for on and off is whatever you code them to be. Dad and Geek did a good write up on it. check it out. http://geekanddad.wordpress.com/2010/06/22/enemies-and-combat-how-to-make-a-tile-based-game-with-cocos2d-part-3/

June 30, 2010 at 2:06 pm #288742

Joethemonkey101
@joethemonkey101

@Synsoft that’s a page on using a tilemap

June 30, 2010 at 3:55 pm #288743

Synsoft
@synsoft

if you read it, there is a section on creating modes so that the character can shoot projectiles.

June 30, 2010 at 10:25 pm #288744

Joethemonkey101
@joethemonkey101

Oh ok thanks

August 24, 2010 at 4:55 pm #288745

Joethemonkey101
@joethemonkey101

I always have trouble using modes. I end up with 3 errors when I try using it for a audio on/off toggle. Here’s my code.

//init method
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
sound = [CCMenuItemImage itemFromNormalImage:@"soundon.png" selectedImage:@"soundon.png" disabledImage:@"soundoff.png" target:self selector:@selector(sound:)];
sound.position = ccp(460, 15);
int mode;
mode = 0;
if (mode == 0) {
soundStatus = 1; //warning - Assignment makes pointer from integer without cast
[[SimpleAudioEngine sharedEngine] setMuted:YES];
}

-(void) spriteCheck:(UITouch *)touchLocation {
CGPoint location = [touchLocation locationInView:[touchLocation view]];
location = [[CCDirector sharedDirector] convertToGL:location];

soundRect = CGRectMake((sound.position.x-(sound.contentSize.width)/2), (sound.position.y-(sound.contentSize.height)/2), (sound.contentSize.width), (sound.contentSize.height));
if (CGRectContainsPoint(soundRect, location)) {
}
}

-(void) soundTapped: (id) sender {
if (soundStatus.mode == 1) { //warning - Comparison between pointer and integer
soundStatus.mode = 0;
} else {
soundStatus.mode = 1; //warning - Passing argument 1 of setMode makes pointer from integer without a cast
}

}

August 24, 2010 at 10:20 pm #288746

chrisco
Participant
@chrisco

Hey Joe,

I honestly think for your sake, you should ignore the term ‘mode’. This came up a while back when you were trying to create a pause button, and if I remember right, that turned into a confusing mess and the thread got closed…

Think about what you’re trying to accomplish. Essentially you want to toggle the sound between two different states, sound on or off. So what type of variable would best handle two different states? Booleans – they can only ever be 0/1, yes/no, on/off, and true/false – nothing in between.

In this case you need to keep track of the sound state not within a single method, but throughout your classes life, right? So for that, you’ll need to create a class member. Let’s call it _shouldPlaySound – so in your header file:

BOOL _shouldPlaySound;

Since you may have objects other than your main layer class wanting to play sounds, it would be helpful if they could check and see if they should be or not – the easiest way to do this is by creating a property. So in your header file again, add this:

@property (nonatomic,readwrite,assign) BOOL shouldPlaySound;

I’ve removed the underscore from the variable’s name when creating a property. This is a personal preference but I find it helpful to quickly see if I’m working with a property or directly with the variable at a glance.

So at this point, you can go into your .m file. Since we’ve created the property, we also need to synthesize the accessors. So under the @implementation YourClass line, add the following:

@synthesize shouldPlaySound = _shouldPlaySound;

What this does is generate accessors at compile-time – accessors will allow you to get or set the value of the variable represented by the property, in this case _shouldPlaySound.

self.shouldPlaySound // to get a value
self.shouldPlaySound = TRUE // to set a value

or:

[self shouldPlaySound] // to get a value
[self setShouldPlaySound:TRUE] // to set a value

So now we can finally implement some code. You’ll want to have a starting value for _shouldPlaySound, and I’m going to assume that by default, yes, you want the sound to play. So in the -init method of your class:

- (id)init... {
if ((self = [super init])) {
.....
_shouldPlaySound = TRUE;
}
}

So that’s a start – now you want to be able to toggle this using your soundTapped: method:

- (void)soundTapped:(id)sender {
if (_shouldPlaySound) {
_shouldPlaySound = FALSE;
} else {
_shouldPlaySound = TRUE;
}
}

That’s it – tapping your sound button will toggle whether or not your sound should play. But obviously, this is just a useless property unless you actually use it :P

So if you want to determine whether a sound should play from within your main class where we’ve added this variable, you would do something like the following:

if (_shouldPlaySound) {
[[SimpleAudioEngine sharedEngine] playEffect:@"gunshot.aif"];
}

// or this would also work
if (self.shouldPlaySound) {
[[SimpleAudioEngine sharedEngine] playEffect:@"gunshot.aif"];
}

So why did we go through the hassle of creating a property, and synthesizing it’s accessors if we can just access the _soundShouldPlay directly? Well, that works fine within the class that own’s the variable, but what if you have a Character class that plays a sound when the character gets hurt?

// From inside your Character Class
-(void)hurtCharacter {
if (mainLayerClass.shouldPlaySound) {
[[SimpleAudioEngine sharedEngine] playEffect:@"ouch.aif"];
}
}

There is a bit of a problem here though, and that’s what happens when you switch scenes. Your MainLayerClass gets wiped out of memory, and so does your user’s choice to mute the sounds or not. So where would be a better place to hold a variable like _shouldPlaySound? You could move it into your game’s AppDelegate, so that any class in your game can access the value by calling:

[[UIApplication sharedApplication] delegate].shouldPlaySound

or set it by calling:

[[[UIApplication sharedApplication] delegate] setShouldPlaySound:FALSE];

The AppDelegate is a great place for gamewide states like this. Just don’t overuse it – ask yourself if it makes sense to put a property there, not just because it’s convenient.

Hope that helps. There might be some errors in here, as I’m writing this quickly while I should be working :P

Chris

August 24, 2010 at 10:47 pm #288747

Joethemonkey101
@joethemonkey101

Thanks again @chrisco. I’ll try using that method instead.

Viewing 11 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic.