Bon alors j'ai fait un script qui permet de mettre de l'audio dans tous les wagons de tous les trains d'un coaster en utilisant les StaticSound, et la possibilité d'avoir plusieurs musiques différentes par train. Le script tient en fait dans 2 scripts différents.
Alors avant toute chose, je vais lister les quelques inconvénients et problème qu'il est impossible de résoudre avec les fonctions de l'API. Comme je créé plusieurs sons diffusant la même musique (un par wagon de chaque train), j'ai du mettre le flag des musiques à FLAG_SHARED, pour être sur que toutes les musiques des différentes sources sont bien synchronisées entre elles. La première conséquence, c'est qu'il est nécessaire d'avoir des fichiers audio destinés pour chaque train, y compris si c'est exactement la même musique pour tous les train (5 trains = 5 musiques). La deuxième conséquence concerne la durée de la musique, il faut qu'elle soi assez longue pour tenir jusqu'au trigger arrêtant la musique ou un trigger permettant de changer de musique, mais il faut aussi qu'elle soi suffisamment courte pour que le train, lors de son passage au tour suivant, puisse avoir sa musique qui redémarre de zéro, parce que sinon la musique continue en mémoire (bien qu'on ne l'entende pas), et reprend à sa position en mémoire.
Remarque importante :
Les fichiers audio sont chargés sous forme de ressource associée au script et non directement depuis le nom du fichier.
Le premier fichier représente une classe permettant de définir des fichiers audio pour un train. En principe ce fichier n'est pas à modifier, sauf les 3 constantes au début, qui représentent respectivement le volume, le temps de fondu au lancement de la musique en secondes, et le temps de fondu à l'arrêt de la musique en secondes aussi.
OnboardMusicTrain :
Code:
import com.nolimitscoaster.*;
import nlvm.math3d.*;
public class OnboardMusicTrain
{
//Constantes
private static final float GAIN = 1.0f;
private static final float START_FADE_TIME = 1.0f;
private static final float STOP_FADE_TIME = 1.0f;
//Variables membres
private Train mTrain;
private int mCarCount;
private int mMusicCount;
private StaticSound[][] mMusics;
private int mIndexOfCurrentMusic;
//Constructeur
public OnboardMusicTrain(Train train, int MusicCount)
{
mTrain = train;
mMusicCount = MusicCount;
mCarCount = mTrain.getCarCount();
mMusics = new StaticSound[mMusicCount][mCarCount];
mIndexOfCurrentMusic = -1;
}
//Fonction permettant d'ajouter une musique
public final bool SetMusic(int index, String MusicId)
{
if(index < 0 || index >= mMusicCount)
{
System.err.println("Index out of limits");
return false;
}
for(int i = mCarCount - 1; i >= 0; i--)
{
StaticSound newSS = StaticSound.loadFromResourceId(MusicId, StaticSound.FLAG_SHARED);
if(newSS == null)
{
System.err.println("Music file cannot be found or opened: '" + MusicId + "'");
return false;
}
newSS.setEnvironmentMode(StaticSound.E_ENVMODE_SAME_AS_LISTENER);
mMusics[index][i] = newSS;
}
return true;
}
public final void UpdatePosition()
{
Vector3f fo = new Vector3f();
Vector3f to = new Vector3f();
Vector3f ro = new Vector3f();
Vector3f pos = new Vector3f();
for(int i = mCarCount - 1; i >= 0; i--)
{
mTrain.getCarOrientationAndPosition(i, fo, to, ro, pos);
for(int j = mMusicCount - 1; j >= 0 ; j--)
{
mMusics[j][i].setPosition(pos);
}
}
}
public final Train getTrain()
{
return mTrain;
}
public final void playMusic(int index)
{
if(index < 0 || index >= mMusicCount) return;
for(int i = mCarCount - 1; i >= 0; i--)
{
mMusics[index][i].stop();
mMusics[index][i].setGain(0);
mMusics[index][i].play();
mMusics[index][i].setGainFaded(GAIN, START_FADE_TIME);
if(mIndexOfCurrentMusic != -1)
{
mMusics[mIndexOfCurrentMusic][i].stopFaded(STOP_FADE_TIME);
}
}
mIndexOfCurrentMusic = index;
}
public final void stopMusic()
{
if(mIndexOfCurrentMusic != -1)
{
for(int i = mCarCount - 1; i >= 0; i--)
{
mMusics[mIndexOfCurrentMusic][i].stopFaded(STOP_FADE_TIME);
}
}
mIndexOfCurrentMusic = -1;
}
}
La deuxième classe est la classe associée au coaster et permettant l'initialisation de la classe OnboardMusicTrain pour chaque train, mais aussi de gérer les trigger.
OnboardMusicCoaster :
Code:
import com.nolimitscoaster.*;
public class OnboardMusicCoaster extends Script implements TrackTriggerListener
{
//Constantes
private static final String Music1Train1Id = "Music1Train1"; //Id de la ressource, à définir dans l'éditeur
private static final String Music2Train1Id = "Music2Train1";
private static final String Music3Train1Id = "Music3Train1";
private static final String Music4Train1Id = "Music4Train1";
private static final String Music1Train2Id = "Music1Train2";
private static final String Music2Train2Id = "Music2Train2";
private static final String Music3Train2Id = "Music3Train2";
private static final String Music4Train2Id = "Music4Train2";
private static final String startMusic1TriggerName = "TestTrigger1";
private static final String startMusic2TriggerName = "TestTrigger2";
private static final String startMusic3TriggerName = "TestTrigger3";
private static final String startMusic4TriggerName = "TestTrigger4";
//Variables membres
private TrackTrigger startMusic1Trig;
private TrackTrigger startMusic2Trig;
private TrackTrigger startMusic3Trig;
private TrackTrigger startMusic4Trig;
private int mTrainCount;
private OnboardMusicTrain[] mMusicTrains;
//Initialisation
public bool onInit()
{
Coaster coaster = sim.getCoasterForEntityId(getParentEntityId());
if (coaster == null)
{
System.err.println("This script must be attached to a coaster");
return false;
}
startMusic1Trig = coaster.getTrackTrigger(startMusic1TriggerName);
if (startMusic1Trig == null)
{
System.err.println("TrackTrigger not found: '" + startMusic1TriggerName + "'");
return false;
}
startMusic1Trig.addTrackTriggerListener(this);
startMusic2Trig = coaster.getTrackTrigger(startMusic2TriggerName);
if (startMusic2Trig == null)
{
System.err.println("TrackTrigger not found: '" + startMusic2TriggerName + "'");
return false;
}
startMusic2Trig.addTrackTriggerListener(this);
startMusic3Trig = coaster.getTrackTrigger(startMusic3TriggerName);
if (startMusic3Trig == null)
{
System.err.println("TrackTrigger not found: '" + startMusic3TriggerName + "'");
return false;
}
startMusic3Trig.addTrackTriggerListener(this);
startMusic4Trig = coaster.getTrackTrigger(startMusic4TriggerName);
if (startMusic4Trig == null)
{
System.err.println("TrackTrigger not found: '" + startMusic4TriggerName + "'");
return false;
}
startMusic4Trig.addTrackTriggerListener(this);
mTrainCount = coaster.getTrainCount();
mMusicTrains = new OnboardMusicTrain[mTrainCount];
OnboardMusicTrain musicTrain;
Train train;
//Train 1
train = coaster.getTrainAt(0); //On récupère le premier train
musicTrain = new OnboardMusicTrain(train, 4); //On initialise sa classe OnboardMusicTrain qui contiendra 4 musiques
if(!musicTrain.SetMusic(0, Music1Train1Id)) return false; //Ajout de la première musique (index = 0)
if(!musicTrain.SetMusic(1, Music2Train1Id)) return false; //Ajout de la deuxième musique (index = 1)
if(!musicTrain.SetMusic(2, Music3Train1Id)) return false;
if(!musicTrain.SetMusic(3, Music4Train1Id)) return false;
mMusicTrains[0] = musicTrain;
//Train 2
train = coaster.getTrainAt(1); //On refait la même chose que pour le premier train avec le train n°2
musicTrain = new OnboardMusicTrain(train, 4);
if(!musicTrain.SetMusic(0, Music1Train2Id)) return false;
if(!musicTrain.SetMusic(1, Music2Train2Id)) return false;
if(!musicTrain.SetMusic(2, Music3Train2Id)) return false;
if(!musicTrain.SetMusic(3, Music4Train2Id)) return false;
mMusicTrains[1] = musicTrain;
return true;
}
//Mise à jour de la position des sons
public void onNextFrame(float tick)
{
for(int i = 0; i < mTrainCount; i++)
{
mMusicTrains[i].UpdatePosition();
}
}
public void onTrainEntering(TrackTrigger trigger, Train train)
{
OnboardMusicTrain musicTrain = null;
for(int i = 0; i < mTrainCount; i++)
{
if(mMusicTrains[i].getTrain() == train)
{
musicTrain = mMusicTrains[i];
break;
}
}
if (trigger == startMusic1Trig && musicTrain != null)
{
musicTrain.playMusic(0);
}
else if (trigger == startMusic2Trig && musicTrain != null)
{
musicTrain.playMusic(1);
}
else if (trigger == startMusic3Trig && musicTrain != null)
{
musicTrain.playMusic(2);
}
else if (trigger == startMusic4Trig && musicTrain != null)
{
musicTrain.playMusic(3);
}
}
public void onTrainLeaving(TrackTrigger trigger, Train train)
{
}
}
Alors dans le code je ne l'ai pas fait là, mais on peut rajouter un trigger qui ne gère que l'arrêt de la musique en cours. Il suffit pour celà d'initialiser un nouveau trigger dans la classe OnboardMusicCoaster et de rajouter ce bout de code dans la fonction onTrainEntering en dessous des autres :
Code:
if (trigger == stopMusicTrig && musicTrain != null)
{
musicTrain.stopMusic();
}