Python: resetting timer (Sound script available)

Hello,
I’ve got a quick python question for all you masters.
I’m trying to make a very efficient sound fader script which simply fades in a sound when a sensor is true, then fades it out when it goes false. The issue here is that I need the script to reset a timer to 0 only once, when the sensor initially enters the true state. So far I have not succeeded, it resets it constantly until the sensor becomes false again. Anyone know how to clear this up?
The file: www.gorilla3d.com/plantperson/soundfader.blend

Any other suggestions are welcome as well.

It’s not registering the Actuator in your demo, think you forgot to pack the data.

But, if I understand you correctly, you want something like This Sound Fadeout I’ve adapted from your Blend.

I didn’t forget, I left it out intentionally. I figured that anyone who actually wanted to test the script could provide their own sound.

I can’t download your file over this slow connection, I’m afraid.

Then Here’s a version without the sound file packed, you’ll have to add one too allow it to work.

I haven’t looked at Nigholith’s file, this idea is just so you don’t have to download anything.

Add a boolean prop called “init” or something. Make it true. Then add this code:

if own.init == 1:
  own.timer = 0
  own.init = 0

Assuming that “own” is the object and “timer” is the timer.

That file is still over 5 megs.

Nigholiths’ code:


from GameLogic import *
cont=GameLogic.getCurrentController()
own=cont.getOwner()


#Bricks
sens=cont.getSensor("sensor1")
snd=cont.getActuator("sound")
always=cont.getSensor("always")

#Properties
if always.isPositive()==True:
    volume=own.level-(own.time/3.5)

#Clockwork
if own.boolprop == 1 and own.trigger == 0:
    GameLogic.addActiveActuator(snd,1)
    own.boolprop = 0
    
if sens.isPositive()==True and own.trigger==0:
    own.fade=1
    own.time=0
    own.trigger=1
if own.fade==1:
    snd.setGain(volume)
if own.trigger==1 and own.time > 4:
    GameLogic.addActiveActuator(snd,0)
print volume

Thanks Social, but without the Logic brick Properties it’s not very workable, uploaded the wrong file by mistake, Here’s the correct smaller file. And sorry for the inefficient code adaptation, it’s a bit hacked together :wink:

Thanks Nigholith. It’s getting a bit late here, so I’m not thinking quite straight, but from what I see your file is not what I need. Sorry if I sound a little irritated here, but like I said, I’m a bit tired: I asked for help with a specific problem, but instead you’re trying to write my script for me, and the script you’ve created is not the script I want. Still no one has answered my original question (although I think the answer may lie in your script, I just have yet to find it).

All I want to know is how I can get the actuator to reset the timer and then let it go. I think I can script it myself from there on.

Heh, I do tend to over extend myself in situations of aid. I’ve learnt when explaining the solution to a problem you can never be too detailed, but clearly that’s not for everybody.

The short of it, is the resolution is both in my Blend and in Toomais’ post.

Doesn’t the script by Nigholith do that - and therefore answers the original question?

You want the actuator to reset the timer? Don’t you mean “sensor”?

It was late and I couldn’t figure out how the script worked. Also, it didn’t do what I wanted it to do, and thus was not an entirely good solution.

Yes, I’ve been known to mix those two up when I’m not thinking. Thou thinkst rightly.

Anyway, thanks for everyones’ help, here is my little script, you can use it if you want. :smiley:

#PlantPerson's Sound Fader Script
#Name your sensor sensor1 and your sound actuator sound
#You also need an always sensor,  or you can set true and false
#pulse modes on sensor1
#Add properties Timer time, Bool fade (false), Float level,
#Bool used (false), and Float negvol.
#Contact PlantPerson at gmail.

from GameLogic import *
cont=GameLogic.getCurrentController()
own=cont.getOwner()


#Bricks
sens=cont.getSensor("sensor1")
snd=cont.getActuator("sound")

#Properties
volume=own.time*0.2
own.level=volume
own.negvol=1/own.time
used=own.used
switch=own.fade

#Clockwork
if sens.isPositive()==True and used==0:
    own.used=1

if sens.isPositive()==True and own.fade==0:
    own.time=0
    own.fade=1
    
elif sens.isPositive()==True and own.fade==1:
    GameLogic.addActiveActuator(snd,1)
    snd.setGain(volume)
    
elif used==1:

    if sens.isPositive()==False and own.fade==1:
        own.time=1
        own.fade=0

    elif sens.isPositive()==False and own.fade==0:
        if own.negvol>0.1:
            GameLogic.addActiveActuator(snd,1)
            snd.setGain(own.negvol)
        
        if own.negvol<0.1:
            GameLogic.addActiveActuator(snd,0)

PlantPerson>

There is no reason to do a “==True” for “.isPositive()” - just do “if sens.isPositive()”.

If there is ever a situation that can’t be covered by an “else” block (for “==False”), “if not sens.isPositive()” is also an alternative.

Try not to create unnecessary variables - “switch” would be a good example of one, as would “used”.

Also, instead of making multiple blocks, you can have the same sensor trigger multiple actions in one block:


if sens.isPositive():
    if own.used == 0:
        own.used = 1
    if own.fade == 0:
        own.fade = 1
        own.time = 0

I don’t know why, but I get a strong impression that this script is wrong somehow. Can you describe exactly what you want to happen when the user hits/holds/lets go of the space bar. I mean I can see your script and what it’s doing, but I don’t know if I’m looking at bugs, or functionality you actually want to be in there.

I think we can simplify this some more.

Thanks for your help, Social…I’m still learning Python, and I appreciate your help with efficiency. It’s very important at this point. I’ll work on implementing the changes you suggest.

The script does exactly what I want it to. First there is no sound, then once the spacebar is pressed, the sound fades in and continues to play until the spacebar is released. Then it fades out. I’ll be using this script for localized sound fx, i.e., making background sounds which play only in specific areas.

EDIT:
Here’s a new version with Social’s suggested improvements:

#PlantPerson's Sound Fader Script
#Name your sensor sensor1 and your sound actuator sound
#You also need an always sensor,  or you can set true and false
#pulse modes on sensor1
#Add properties Timer time, Bool fade (false), Float level,
#Bool used (false), and Float negvol.
#Contact PlantPerson at gmail.

from GameLogic import *
cont=GameLogic.getCurrentController()
own=cont.getOwner()


#Bricks
sens=cont.getSensor("sensor1")
snd=cont.getActuator("sound")

#Properties
volume=own.time*0.2
own.level=volume
own.negvol=1/own.time
used=own.used
switch=own.fade

#Clockwork
if sens.isPositive():
    if used==0:
        own.used=1
        
    elif used==1:
        if own.fade==0:
            own.time=0
            own.fade=1
            
        elif own.fade==1:
            GameLogic.addActiveActuator(snd,1)
            snd.setGain(volume)

elif not sens.isPositive() and used==1:
    if own.fade==1:
        own.time=1
        own.fade=0
    
    elif own.fade==0:
        if own.negvol>0.1:
            GameLogic.addActiveActuator(snd,1)
            snd.setGain(own.negvol)
        
        if own.negvol<0.1:
            GameLogic.addActiveActuator(snd,0)

cont = GameLogic.getCurrentController()
own = cont.getOwner()

sens = cont.getSensor("sensor1")
snd = cont.getActuator("sound")

if sens.isPositive():
    if own.volume < 1:
        own.volume += 0.003
        GameLogic.addActiveActuator(snd, 1)
else:
    if own.volume > 0:
        own.volume -= 0.003
    else:
        GameLogic.addActiveActuator(snd, 0)

snd.setGain(own.volume)

Instead of a timer property, you can just use the tick rate itself. So the only prop you need to have is “volume”.

PS: You don’t have to import GameLogic anymore, because it’s imported for you automatically.

Also, about “elif”:


if a == x:
    pass
elif b == y:
    pass
else:         # else will run only if "a != x" and "b != y"
    pass 

########

if a == x:
    pass
if b == y:
    pass
else:       # else will run only if "b != y" - regardless of the first "if" control
    pass

So you can just use plain “if” statements for most things, and “elif” for occasions that call for it.

Wow, thanks a lot Social, your way is much more efficient, and actually less choppy than mine. It didn’t occur to me to try using the tic rate.

About elif, a while ago someone told me that using elif arguments was more efficient than making everything be an if, because all ifs are evaluated but elifs are only evaluated if the previous “if” was false. Is that true?

Yes, that’s true. However you shouldn’t use “elif” in situations that don’t call for it. That brings no gain in efficiency, but does a great deal in generating potentially confusing/unnecessary code (which some would argue to be worse than actually writing inefficient code).

For example, in the script you wrote:


if used==0:
    own.used=1

elif used==1:
    if own.fade==0
        own.time=0
        own.fade=1

# ^ "Why is he using 'elif'?" would be the first thing to pop into my head.
# Because it's just a two state deal:

if used:
    if own.fade == 0
        own.time = 0
        own.fade = 0
else:
    own.used = 1

# It's either true (!= 0) or false (0). 
# In other words; a boolean, and a boolean doesn't require an elif.

I hope that made sense.

Yes, I see now. Thanks for your help.

My 5 cents:

 
if...:
elif ...:
else:

is similar to:

 
if ...:
else: 
    if ...:
    else:

ELIF makes the source a bit more readable.