Playing Sounds.

From TrainzOnline
Jump to: navigation, search

Trainz is capable of doing quite sophisticated tricks with sound files. We will use a file which contains a single 'ding' but loops it around continuously as long as the doors to the shed are open. This involves the use of a separate programming thread. A thread runs independently of any other code within your script. It's a bit like leaving the kettle boiling while you answer the front door, the kettle will look after itself until it boils. In the same way our thread will look after itself until something tells it to stop.

include "Buildable.gs"

class Tutorial isclass Buildable {

   bool doorsOpen = false;

   public void Init(void) {
      inherited();
      SetFXCoronaTexture("corona",null);
      AddHandler(me,"Object","","ObjectHandler");
   }

   Asset GetCorona(string mesh, string effect) {
      Soup meshtable = GetAsset().GetConfigSoup().GetNamedSoup("mesh-table");
      Soup effects = meshtable.GetNamedSoup(mesh).GetNamedSoup("effects");
      KUID kuid = effects.GetNamedSoup(effect).GetNamedTagAsKUID("texture-kuid");
      return World.FindAsset(kuid);
   }

/* This is the bell ringing method, the keyword thread signifies that it is to run
   independently of any other code.  You will remember our global variable, doorsOpen
   which is set to true or false in the ObjectHandler method. RingTheBell uses a while
   loop to monitor this variable and will keep running until doorsOpen becomes false.
   World.Play2DSound() plays a non-positional sound, that is it can be heard anywhere 
   on the route. I've added a call to Sleep after the sound is played, enough time to allow the 
   sound to play, plus a short pause. On the next loop the method will check to see if the doors
   are still open and run again if so. Once they have closed the while loop and the method 
   will end. All of this runs independently of other parts of the class code. */

   thread void RingTheBell(void) {
      while (doorsOpen) {
         World.Play2DSound(GetAsset(),"bell.wav");
         Sleep(1.5);
      }
   }

/* When the doors are opened we call the thread RingTheBell to start the bell ringing.
   There is no need to stop it, this will happen automatically. */

   void ObjectHandler(Message msg) {
      Vehicle vehicle = cast<Vehicle>msg.src;
      if (!vehicle) return;
      if (msg.minor == "InnerEnter") {
         doorsOpen = true;
         SetMeshAnimationState("default", true);
         SetFXCoronaTexture("corona",GetCorona("default","corona"));
         RingTheBell();
      }
      else if (msg.minor == "InnerLeave") {
         doorsOpen = false;
         SetMeshAnimationState("default", false);
         SetFXCoronaTexture("corona",null);
      }
   }

};

I've used World.Play2DSound() to ring the bell because you will hear it no matter how far away from the shed the camera is zoomed. It would actually be more appropriate to use a different method, World.PlaySound() which will appear to come from one speaker or the other, depending on where you are, and will fall off in volume as you get further away from the building. The call for this would be World.PlaySound(me,"bell.wav",1000,10,100,me,"a.corona"); (See Note 1) You might like to try a substitution to hear the difference.

Note 1. If you get a compiler error for this call, try World.PlaySound(GetAsset(),"bell.wav",1000.0,10.0,100.0,me,"a.corona"). There were some changes for TS12 that may prevent the original code from working.

Next Tutorial: Hiding Meshes.

Back to Getting Started

Personal tools