BGE Runs Script Twice

Context: I have a game that I wanted to add a sound to. Since I was using Python, I had my script play a sound using aud, though the game played the sound twice. I changed it trigger a sensor, and the sound still went twice. I soon found out that the script was running twice, so I dissected my game trying to figure it out.
Eventually I made a new .blend file and added a single cube. I set an Always sensor with a tap pulse to run a python script with one line:
And when I ran it there were two As in the console.

Question: Has BGE always run scripts twice? I’ve never had this issue before but I usually don’t have scripts run. It also doesn’t run it twice on the same frame, since the sound playing twice is somewhat noticeable (enough for a short click to sound like two)
Is there a fix for this?

Moved to #game-engine:game-engine-support-and-discussion.

It has always been like that.

You can check the sensor status to execute the script only one time:

import bge

cont = bge.logic.getCurrentController()

if cont.sensors["sensorName"].status == bge.logic.KX_INPUT_JUST_ACTIVATED:
    #run the script

or ensure in another way that the script isn’t executed twice:

import bge

cont = bge.logic.getCurrentController()
own = cont.owner
scene = bge.logic.getCurrentScene()

# examples
if "init" not in own:
    #run the script
    own["init"] = True

if "init" not in scene:
    #run the script
    scene["init"] = 1

if not hasattr(bge.logic, "init"):
    #run the script
    bge.logic.init = True


It’s like aWeirdOwl said, but some more details about it: the sensors have statuses that indicate its status on the current frame. By default, the sensor sends KX_SENSOR_INACTIVE when not triggered, KX_SENSOR_JUST_ACTIVATED when just triggered (during one single frame), KX_SENSOR_ACTIVE when its pulse is still positive (such as pressing and holding a button) and KX_SENSOR_JUST_DEACTIVATED when just deactivated (such as releasing a button, during one single frame). Most of the time, checking these statuses is not needed, only checking the sensor.positive status would be enough.

Below there’s an example of a sound played correctly with aud, including an optimization to avoid loading and buffering the sound each time the sensor is triggered. (96.9 KB)

import bge
import aud
from bge.logic import expandPath

cont = bge.logic.getCurrentController()
own = cont.owner
sensor = cont.sensors["Spacebar"]

# Will run on sensor positive pulse
if sensor.positive:
    # Will run once even with the sensor with pulse mode enabled
    if sensor.status == 1: # bge.logic.KX_SENSOR_JUST_ACTIVATED == 1
        # Loads and buffers the factory into scene if not already loaded
        if not "Factory" in own.scene:
            own.scene["Factory"] = aud.Factory(expandPath("//choice2.wav")).buffer()
            print("> Factory loaded and buffered at time", bge.logic.getRealTime())
        # Play factory if already loaded
        if "Factory" in own.scene:
            print("Factory played at time", bge.logic.getRealTime())