Game Development Community

Gahh!! triggers. Can't get it to work.

by Mike Rowley · in Torque Game Engine · 09/14/2006 (12:49 pm) · 13 replies

History:
I modified and renamed the default triggers.cs to underwatertrigger.cs to customise it to my needs.

//-----------------------------------------------------------------------------
// Torque Game Engine 
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
 //Modified by MikeR
//-----------------------------------------------------------------------------
// DefaultTrigger is used by the mission editor.  This is also an example
// of trigger methods and callbacks.

datablock TriggerData(UnderwaterTrigger)
{
   // The period is value is used to control how often the console
   // onTriggerTick callback is called while there are any objects
   // in the trigger.  The default value is 100 MS.
   tickPeriodMS = 100;

};


//-----------------------------------------------------------------------------

function UnderwaterTrigger::onEnterTrigger(%this,%trigger,%obj)
{
   // This method is called whenever an object enters the %trigger
   // area, the object is passed as %obj.  The default onEnterTrigger
   // method (in the C++ code) invokes the ::onTrigger(%trigger,1) method on
   // every object (whatever it's type) in the same group as the trigger.
   Parent::onEnterTrigger(%this,%trigger,%obj);
    StopAmbientSound(AudioAmbientMusicProfile);
    echo("\nEntering Underwater trigger area");
}

function UnderwaterTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
   // This method is called whenever an object leaves the %trigger
   // area, the object is passed as %obj.  The default onLeaveTrigger
   // method (in the C++ code) invokes the ::onTrigger(%trigger,0) method on
   // every object (whatever it's type) in the same group as the trigger.
   Parent::onLeaveTrigger(%this,%trigger,%obj);
   StartAmbientSound(AudioAmbientMusicProfile);
    echo("\nExiting Underwater trigger area");
}

function UnderwaterTrigger::onTickTrigger(%this,%trigger)
{
   // This method is called every tickPerioMS, as long as any
   // objects intersect the trigger. The default onTriggerTick
   // method (in the C++ code) invokes the ::onTriggerTick(%trigger) method on
   // every object (whatever it's type) in the same group as the trigger.

   // You can iterate through the objects in the list by using these
   // methods:
   //    %this.getNumObjects();
   //    %this.getObject(n);
   Parent::onTickTrigger(%this,%trigger);
}
  function StartAmbientSound(%handle)
{
if (!alxIsPlaying(%handle))
alxPlay(%handle);
}

function StopAmbientSound(%handle)
{
if (alxIsPlaying(%handle))
alxStop(%handle);
}

What I'm doing here is: I have an ambient sound playing when the player enters the game. It's a repeating sound that loops endlessly.
I have setup my trigger area under the water. (hearing birds chirping whilst you are underwater would be kinda strange) This trigger should stop the ambient sound from playing while the player is inside the trigger area, and restart it when the player leaves the area. I put 2 echo statements in to make sure that my trigger was being implemented.
As I don't want to stop all sound, I took the functions from the audioProfiles.cs and added it to the end of my trigger.cs then changed the function so that it was specific to my needs.
Now, when the player enters the trigger area, the echo statement does indeed print in the console, but the sound continues playing. With it written as: AudioAmbientMusicProfile, I get no errors, but the sound continues playing. if I write the datablock name AudioAmbientMusic, the music continues playing, but I get an error in the console telling me that it can't find the datablock.
What am I missing here? I know this should work somehow.
Thanks for your help in advance. :)

#1
09/14/2006 (3:05 pm)
This is a complete aside - because you'll probably want to do this for woods versus meadow or inside versus outside but there actually are separate onEnterLiquid and onLeaveLiquid routines that are called. The routine onEnterLiquid even has a coverage percentage so your sound could continue until your character is actually under water as opposed to knee-deep.

The starter.fps uses the liquid enter and leave - although the damage assessment subroutine is broken. I haven't lookd into it but also check the screenflash is set to blue when underwater and then unset when your water coverage isn't complete. This seems like exactly the kind of triggering you're looking for with the water in this case.

=Tod
#2
09/14/2006 (3:10 pm)
That does sound like something to look into. Thanks for the heads up. :)
I will need to get the trigger working tho, as I'll be using different sounds for different places in the game.
Thanks. I'll look into the onEnterLiquid parts.
#3
09/15/2006 (12:20 am)
Update:
I have this partially working. I can get the sound to start, but not stop.

In audioProfiles.cs:

new AudioDescription(AudioAmbientMusic)
{
   volume   = 0.8;
   isLooping= true;
   is3D     = false;
   type     = $MusicAudioType;
};
 new AudioDescription(AudioAmbientMusic2)
{
   volume   = 0.3;
   isLooping= true;
   is3D     = false;
   type     = $MusicAudioType;
};

new AudioProfile(WaterSound)
{
   filename = "~/data/sound/water.wav";
   description = "AudioAmbientMusic2";
	preload = true;
};
 function StartAmbient(%handle)
{
if (!alxIsPlaying(%handle))
alxPlay(%handle);
}

function StopAmbient(%handle)
{
if (alxIsPlaying(%handle))
alxStop(%handle);
}
my trigger.cs:
//-----------------------------------------------------------------------------
// Torque Game Engine 
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
 //Modified by MikeR
//-----------------------------------------------------------------------------
// DefaultTrigger is used by the mission editor.  This is also an example
// of trigger methods and callbacks.

datablock TriggerData(UnderwaterTrigger)
{
   // The period is value is used to control how often the console
   // onTriggerTick callback is called while there are any objects
   // in the trigger.  The default value is 100 MS.
   tickPeriodMS = 100;

};


//-----------------------------------------------------------------------------

function UnderwaterTrigger::onEnterTrigger(%this,%trigger,%obj)
{
   // This method is called whenever an object enters the %trigger
   // area, the object is passed as %obj.  The default onEnterTrigger
   // method (in the C++ code) invokes the ::onTrigger(%trigger,1) method on
   // every object (whatever it's type) in the same group as the trigger.
   Parent::onEnterTrigger(%this,%trigger,%obj);

   StartAmbient(WaterSound);
    echo("\nEntering Underwater trigger area");
}

function UnderwaterTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
   // This method is called whenever an object leaves the %trigger
   // area, the object is passed as %obj.  The default onLeaveTrigger
   // method (in the C++ code) invokes the ::onTrigger(%trigger,0) method on
   // every object (whatever it's type) in the same group as the trigger.
   Parent::onLeaveTrigger(%this,%trigger,%obj);

   StopAmbient (WaterSound);
    echo("\nExiting Underwater trigger area");
}

function UnderwaterTrigger::onTickTrigger(%this,%trigger)
{
   // This method is called every tickPerioMS, as long as any
   // objects intersect the trigger. The default onTriggerTick
   // method (in the C++ code) invokes the ::onTriggerTick(%trigger) method on
   // every object (whatever it's type) in the same group as the trigger.

   // You can iterate through the objects in the list by using these
   // methods:
   //    %this.getNumObjects();
   //    %this.getObject(n);
   Parent::onTickTrigger(%this,%trigger);
}
Is there a known bug that prevents a trigger from stopping what it started?
#4
09/15/2006 (12:59 am)
You're mixin up the handle for the sound and the AudioProfile name...
You need to store the sound handle in a global var or a player specific var, e.g.
function StartAmbient(%handle, %profile)
{
if (!alxIsPlaying(%handle))
%handle = alxPlay(%profile);
}

function StopAmbient(%handle)
{
if (alxIsPlaying(%handle))
alxStop(%handle);
}
and in your trigger:
StartAmbient(%obj.underwaterSound, WaterSound);
...
StopAmbient (%obj.underwaterSound);
#5
09/16/2006 (2:47 pm)
I don't have anyting that says "UnderwaterSound". is that a new name that is created for the watersound when it is implemented?
Or do I need to change the discription?
(I've tried changing the discription. It didin't do anything different.)
edit to add
I've tried every combination I can think of in the console. I cannot get sound to stop after it's been started. I don't know what's wrong.
Edit further to add console log)

==>StartAmbientSound(WaterSound);  [b]This started the sound[/b]
Received info request from a master server [].
==>(StopAmbientSound(WaterSound); [b]This did nothing[/b]
Syntax error in input. [b]oops. I mispelledsomething[/b]
DirectInput deactivated.
   keyboard0 input device created.
   mouse0 input device created.
Activating DirectInput...
==>StopAmbientSound(WaterSound); [b]This did nothing[/b]
Received info request from a master server [].
DirectInput deactivated.
   keyboard0 input device created.
   mouse0 input device created.
Activating DirectInput...
Sending heartbeat to master server []
==>alxStop(WaterSound); [b]This did nothing[/b]

The only way i have been able to stop sound is to call "alxStopAll();" but that stops alll sound. I shouldn't need to call that eccept when the client closes. I can find no call or function to stop a running sound.
#6
09/17/2006 (1:09 pm)
Did you read what I posted?
You can't do "alxStop(ProfileName)"...
the basic logic is
$myHandle = alxPlay(WaterSound);
...
alxStop($myHandle);

OR, as I posted above, you can store it with the object (if you have a reference to it, e.g. in your trigger) instead of a global var,
e.g.
%obj.waterSound = alxPlay(WaterSound);

alxStop(%obj.waterSound);

If you just use what I posted in the above thread it should work...
#7
09/17/2006 (1:43 pm)
Ok, sorry for the confusion. I'm still learning.

I've changed my trigger.cs to the following: (only pertinent parts)

//my sound for this trigger
  new AudioProfile(WaterSound)
{
   filename = "~/data/sound/water1.wav";
   description = "AudioAmbientMusic2";
	preload = true;
};
//my function for playing this sound

function StartAmbientSound(%handle, %profile)
{
if (!alxIsPlaying(%handle))
%UnderWaterSound = alxPlay(WaterSound);
}

function StopAmbientSound(%handle)
{
if (alxIsPlaying(%handle))
alxStop(%UnderWaterSound);
}
//Comments and trigger data
function UnderwaterTrigger::onEnterTrigger(%this,%trigger,%obj)
{
   Parent::onEnterTrigger(%this,%trigger,%obj);
   StartAmbientSound(%obj.UnderwaterSound, WaterSound);
    echo("\nEntering Underwater trigger area");
}

function UnderwaterTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
   Parent::onLeaveTrigger(%this,%trigger,%obj);
   
   StopAmbientSound (%obj.UnderwaterSound);
    echo("\nExiting Underwater trigger area");
}

I am still doing something wrong, as I'm still having the same problem. Sound starts, but doesn't stop.
To make sure I'm understanding correctly: (using the above code)

%handle Would be "UnderwaterSound"
and
%profile would be "WaterSound"

or am I backwards?? (happens too often)
if I am correct, and since this is defined and implemented only in this particular trigger, should I remove %handle altogether and replace it with UnderwaterSound?
#8
09/17/2006 (2:43 pm)
You should take your time and double-check your scripts ...
there are quite some errors in there, here is a corrected version...
and remember
%somevar is a LOCAL variable and
$somevar is GLOBAL...
You've totally mixed up my suggestion, your original code, a mix of undeclared local vars etc.
Anyways, here goes....
//my sound for this trigger
  new AudioProfile(WaterSound)
{
   filename = "~/data/sound/water1.wav";
   description = "AudioAmbientMusic2";
	preload = true;
};
//my function for playing this sound

function StartAmbientSound(%handle, %profile)
{
if (!alxIsPlaying(%handle))
%handle = alxPlay(%profile);
}

function StopAmbientSound(%handle)
{
if (alxIsPlaying(%handle))
alxStop(%handle);
}
//Comments and trigger data
function UnderwaterTrigger::onEnterTrigger(%this,%trigger,%obj)
{
   Parent::onEnterTrigger(%this,%trigger,%obj);
   StartAmbientSound(%obj.UnderwaterSound, WaterSound);
    echo("\nEntering Underwater trigger area");
}

function UnderwaterTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
   Parent::onLeaveTrigger(%this,%trigger,%obj);
   
   StopAmbientSound (%obj.UnderwaterSound);
    echo("\nExiting Underwater trigger area");
}
This is untested, I hope everything's correct now.
#9
09/17/2006 (3:06 pm)
I'm officially bald now. :D

I have made the changes you showed above. Quadriple checked to make sure my code was the same as yours.
Walk into trigger.....sound starts playing
Walk out of trigger....sound continues playing.

Thankyou for your help. I think I need to do a little more studying before I continue. I can figure out what the code does, but really don't understand why. And really don't understand why it isn't working.
#10
09/17/2006 (9:28 pm)
Well, for starters you're not defining your music handle variable. Secondly, your trying to stop "UnderwaterSound", which I assume is a profile yet in your posted scripts it doesn't exist anywhere. Even if it did, you don't stop a sound by using its profile, you must use its handle. Thirdly, and this is a matter of opinion, why do you need to create another two functions to start and stop a sound when all this has been done for your in head code.

This is all you need to play and stop a sound.

$MusicAudioType = 4;

new AudioDescription(AudioAmbientMusic2)
{
   volume    = 0.3;
   isLooping = true;
   is3D      = false;
   type      = $MusicAudioType;
};

//my sound for this trigger
new AudioProfile(WaterSound)
{
   filename    = "~/data/sound/water1.wav";
   description = "AudioAmbientMusic2";
   preload     = true;
};

//Comments and trigger data
function UnderwaterTrigger::onEnterTrigger(%this,%trigger,%obj)
{
   Parent::onEnterTrigger(%this,%trigger,%obj);

   $MusicHandle = alxPlay(WaterSound);
   echo("\nEntering Underwater trigger area");
}

function UnderwaterTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
   Parent::onLeaveTrigger(%this,%trigger,%obj);
   
   alxStop($musicHandle);
   echo("\nExiting Underwater trigger area");
}


That will work my friend.
#11
09/17/2006 (9:39 pm)
If you still need to use your stop function, I assume this will stop the sound on a per client basis, all you need to change is the following:

Declare your handle variable. Client\AudioProfiles.cs may be a good place to store this.
$MusicAudioType = 4;

Refer to that handle when using your stop command.
StopAmbientSound (%obj.musicHandle);

Aside from those two changes, the rest of Stefan's script (posted above) should work.
#12
09/19/2006 (3:56 pm)
NOW I understand what you guys are talking about whey you say "stop the $handle". (that was one of my questions above.)
I had no idea what you were talking about. $MusicAudioType=4; is in audioProfiles.cs with the rest of them. I added it whilst working thru Ken Finneys book. It seems the functions are depreciated in 1.4 (his book used 1.2 or 3)
Thanks for the help.
#13
09/22/2006 (5:02 pm)
First off, thankyou both for your help. This is working properly now. :)

Now, one more question to clear up the loose ends.

Why is it you can call:

alxPlay(datablock name) and it plays the sound
but, you can't call:
alxStop(datablock name) //does nothing ??

Logic says that if you can start a sound using the datablock name, that you should also be able to stop it the same way.
I'm just wondering. TGE is great. :)