Semáforo unificado de tres posiciones
Contenido |
La señal |
Esta señal añade
a la anterior la complejidad, mínima por otra parte, de que
tiene tres estados posibles. Su complejidad, no obstante, supera
a las señales mecánicas implimentadas en las rutas estandar de
MSTS, que sólo poseen dos estados.
El semáforo se presenta como un brazo rojo con franja blanca, que gira alrededor de un eje horizontal mostrando tres posiciones: con el brazo totalmente horizontal para la indicación de alto, con el brazo inclinado 45º para la indicación de anuncio de parada, y totalmente vertical para la indicación de vía libre. De noche presenta una luz roja en posición de alto, una luz amarilla en posición de anuncio de parada y una luz verde en posición de vía libre.
Dia | Noche | ||||
Parada | Anuncio de Parada |
Vía Libre | Parada | Anuncio de Parada |
Vía Libre |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Modelado |
Todos los modelos de señales deben tener un objeto con el nombre SIGNAL que determina el soporte de la señal, o perte fija de la misma, y uno o más objetos móviles denominados HEAD1, HEAD2, etc... En el presente caso sólo tendremos un objeto móvil que será el brazo propiamente.
La siguente imagen muestra en rojo el objeto SIGNAL (vista frontal y lateral) que conforma el mástil o soporte de la señal.
Como ya indicamos en la descripción de la Pantalla Principal, hay que resaltar dos puntos importantes:
La cara frontal de la señal, la que se muestra al maquinista, se debe modelar situada hacia la parte posterior del eje Z (hacia atrás) pues esta es la posición "natural" de la señal y así lo interpreta el Route Editor para determinar hacia que lado de la misma han de actuar las indicaciones en el juego, por tanto modelaremos teniendo en cuenta que en la vista "frontal" del editor 3D observaremos la señal desde el loado contrario al que lo hará el maquinista.
La posición del eje del objeto SIGNAL determina la colocación de la señal en el mundo del Route Editor. Por tanto, éste deberá estar a una altura 0 (o la señal aparecerá hundida en el suelo, o flotando) y procuraremos desplazarlo lateralmente 2,5 metros (la entrevía de MSTS es de 5 metros) pues el citado eje de SIGNAL se sitúa por defecto en el centro de la vía.
La siguiente imagen muestra en rojo el objeto HEAD1, siempre desde la vista frontal, al cual animaremos con tres frames: 0, 1, 2 y 3, de las cuales las tres primeras representarán las tres indicaciones de la señal: parada, anuncio de parada y via libre, y la última la haremos coincidente con la primera. Esto define los tres movimientos de transición de la señal. El eje del objeto HEAD1 lo situaremos en el punto de giro de la parte móvil de la señal. La señal se muestra desde la vista frontal del editor, y por tanto se observa desde su lado posterior:
![]() Frame 0 |
![]() Frame 1 |
![]() Frame 2 |
Podemos proceder a compilar la señal así modelada y le daremos nombre, por ejemplo ESRNSemUnif.s.
El archivo sigcfg.dat |
Las señales a usar en una ruta, como elementos interactivos que son, no se definen en el archivo .ref de la misma, si no que están descritas en el archivo sigcfg.dat.
La descripción específica de cada sección de este archivo se describe en el siguiente documento:
Descripción del contenido del archivo sigcfg.dat
Para la señal que estamos tratando, en las secciones afectadas se deberá incluir:
Sección LightTextures
LightTextures ( 1 LightTex ( "ltex" "SigLight.ace" 0 0 1 1 ) ) |
Definimos que la textura de la luz de la
señal será SigLight.ace, que es la textura por defecto
que traen las rutas del juego para un foco redondo (se puede
observar en la imagen al lado), y le daremos el nombre simbólico
ltex para referenciarla más adelante en otras secciones.
Esta textura deberá incluirse en el directorio TEXTURES de la
ruta.
Aunque aqí no se muestran , podría haber otras
texturas en la sección.
Sección LightsTab
Remarcamos en negrita las entradas necesarias para esta señal, que corresponden a les colores rojo, con nombre simbólico Red Light, y blanco, con nombre simbólico White Light. El resto de colores se muestran como ejemplo de los más usuales:
LightsTab ( 5 LightsTabEntry ( "Red Light" colour ( 255 255 40 40 ) ) LightsTabEntry ( "Amber Light" colour ( 255 255 200 0 ) ) LightsTabEntry ( "Green Light" colour ( 255 0 255 0 ) ) LightsTabEntry ( "White Light" colour ( 255 230 255 255 ) ) LightsTabEntry ( "Violet Light" colour ( 255 128 128 255 ) ) ) |
Los tonos de color pueden modificarse si se considera oportuno.
Sección LightsTab
Remarcamos en negrita las entradas necesarias para esta señal. Tengase en cuenta que pueden existir otras entradas SignalType en el archivo, y por tanto, el valor de SignalTypes deberá ser el total de estas entradas:
SignalTypes ( 1 SignalType ( "ESRNSemHome" SignalFnType ( NORMAL ) SignalLightTex ( "ltex" ) SemaphoreInfo ( 0.5 ) SignalFlags ( SEMAPHORE ) SignalLights ( 3 SignalLight ( 0 "Red Light" Position ( -0.148 -0.050 0.02 ) Radius ( 0.10 ) SignalFlags ( SEMAPHORE_CHANGE ) ) SignalLight ( 1 "Amber Light" Position ( -0.148 -0.050 0.02 ) Radius ( 0.10 ) SignalFlags ( SEMAPHORE_CHANGE ) ) SignalLight ( 2 "Green Light" Position ( -0.148 -0.050 0.02 ) Radius ( 0.10 ) SignalFlags ( SEMAPHORE_CHANGE ) ) ) SignalDrawStates ( 3 SignalDrawState ( 0 "Parada" DrawLights ( 1 DrawLight ( 0 ) ) SemaphorePos ( 0 ) ) SignalDrawState ( 1 "Anuncio" DrawLights ( 1 DrawLight ( 1 ) ) SemaphorePos ( 1 ) ) SignalDrawState ( 2 "Libre" DrawLights ( 1 DrawLight ( 2 ) ) SemaphorePos ( 2 ) ) ) SignalAspects ( 3 SignalAspect ( STOP "Parada" SpeedKPH ( 0 ) ) SignalAspect ( APPROACH_2 "Anuncio" SpeedKPH ( 30 ) ) SignalAspect ( CLEAR_2 "Libre" ) ) SignalNumClearAhead ( 2 ) ) ) |
A la cabeza de esta señal la hemos llamado ESRNSemHome (la podríamos llamar como quisieramos). El parámetro de SemaphoreInfo no está documentado, pero en las señales mecánicas del juego se observa que llevan este valor.
En SignalLights hemos definido tres luces para esta señal: les definimos su color, posición relativa respecto al objeto HEAD1, y su radio.
En SignalDrawStates definimos tres posiciones para la señal: Parada, Anuncio y Libre (podemos denominar cada posición como queramos). A cada posición le asignamos cuantas luces deberán iluminarse y cuales, así como la posición del objeto HEAD1 que corresponderá con el frame de la animación de dicho objeto en el editor 3D.
En SignalAspects determinamos que la señal tendrá tres aspectos posibles y los relacionaremos con los valores estandar (STOP, APPROACH_2 y CLEAR_2) y las posiciones antes definidas (Parada, Anuncio y Libre). En este caso, al aspecto correspondiente a Anuncio, le delimitamos la velocidad máxima (30 Km/h) que restringirá el siguiente sector si se sobrepasa la señal en esta posición, independientemente del límite de velocidad que esté prefijado en la ruta. Al aspecto Libre no le fijamos ningún límite de velocidad, con lo que prevalecerá el que tenga determinado la ruta. Al aspecto Parada le hemos fijado un límite de velocidad de 0 Km/h, aunque es irrelevante, dado que si intentamos sobrepasar la señal, el juego dará por terminada la actividad pues el aspecto STOP es irrebasable.
Finalmente, en SignalNumClearAhead damos el número de sectores libres que debe tener la señal a continuación para dar la indicación de vía libre, en nuestro caso dos, puesto que con un sólo sector libre daremos la indicación de Anuncio de Parada.
Sección SignalShapes
Remarcamos en negrita las entradas necesarias para esta señal. Tengase en cuenta que pueden existir otras entradas SignalShape en el archivo, y por tanto, el valor de SignalShapes deberá ser el total de estas entradas:
SignalShapes ( 1 SignalShape ( "ESRNSemUnif.s" "ESRN Semaforo Principal" SignalSubObjs ( 1 SignalSubObj ( 0 "HEAD1" "Brazo 1" SigSubType ( SIGNAL_HEAD ) SignalFlags ( OPTIONAL DEFAULT ) SigSubSType ( "ESRNSemHome" ) ) ) ) ) |
Aquí relacionamos el modelo de la señal (archivo ESRNSemUnif.s) con la definición de la cabeza de señal que hemos realizado. El texto "ESRN Semaforo Principal" es el que aparecerá en el Route Editor cuando tengamos que seleccionar esta señal.
A la señal le referenciamos un sub-objeto, pues tiene una sola cabeza o brazo.
A esta cabeza le definimos que es el objeto HEAD1 en el modelo, y que en el Route Editor, dentro de las propiedades de la señal, dicha cabeza aparecerá como "Brazo 1". Así mismo le damos los valores de tipo de señal y flags.
Por último, determinamos que esta cabeza se corresponde con la definición ESRNSemHome de la sección anterior, y que por tanto actuará según el scripts ESRNSemHome del archivo de scripts.
Sección SicriptFiles
ScriptFiles ( ScriptFile ( sigscr.dat ) ) |
En esta última sección, nos limitamos a informar que los scripts necesarios (ESRNSemHome en el presente caso) están en el archivo sigscr.dat.
El archivo sigscr.dat |
El archivo de scripts contiene los diferentes scripts para todas las cabezas o brazos de las señales definidas en el archivo sigcfg.dat.
La descripción específica de la estructura de este archivo y las funciones disponibles para escribir un script se describe en el siguiente documento:
Descripción del contenido del archivo sigscr.dat
Para la señal que estamos tratando, bastará con un script para su única cabeza que se muestra a continuación:
SCRIPT ESRNSemHome // Semaforo Principal 3 estados // Declaración de funciones y variables extern float enabled; extern float block_state (); extern float route_set (); extern float next_sig_lr (); extern float state; extern float def_draw_state (); extern float draw_state; float next_state; // Establecer estado if (!enabled || block_state() !=# BLOCK_CLEAR || !route_set()) { state = SIGASP_STOP; } else { next_state = next_sig_lr (SIGFN_NORMAL); if (next_state ==# SIGASP_STOP || next_state ==# SIGASP_RESTRICTING || next_state ==# SIGASP_STOP_AND_PROCEED) { state = SIGASP_APPROACH_2; } else { state = SIGASP_CLEAR_2; } } // Cambiar estado draw_state = def_draw_state (state); |
Su funcionamiento es muy simple. En él descubrimos, ademas de las líneas de comentarios encabezadas por un doble slash (//), cuatro partes:
Inicio del scripts y nombre:
SCRIPT ESRNSemHome
Declaración de funciones
y variables usadas:
extern float enabled;
extern float block_state ();
extern float route_set ();
extern float state;
extern float def_draw_state ();
extern float draw_state;
También definimos una variable
auxiliar del script para almacenar el estado de la
siguiente señal
float next_state;
Lógica de funcionamiento de la señal:
if
(!enabled ||
Si está desactivada en el Route Editor
block_state()
!=# BLOCK_CLEAR ||
o el bloque siguiente a la señal no está
libre
!route_set())
o la señal tiene asignada una ruta concreta
donde actúa y ésta no está establecida por las agujas
que siguen a la señal, entonces...
{
state =
SIGASP_STOP;
establecer en la variable state el estado de Parada (SIGASP_STOP)
}
else
en caso contrario
{
next_state
= next_sig_lr (SIGFN_NORMAL);
almacenamos el estado de la siguiente señal
en next_state
if (next_state
==# SIGASP_STOP ||
next_state
==# SIGASP_RESTRICTING ||
next_state
==# SIGASP_STOP_AND_PROCEED)
si la siguiente señal está en alguna
indicación de Parada (absoluta con o sin rebase
autorizado o temporal)
{
state
= SIGASP_APPROACH_2;
establecer en la variable state el estado de Anuncio
de Parada (SIGASP_APPROACH_2)
}
en caso contrario
{
state =
SIGASP_CLEAR_2;
establecer en la variable state el estado de Via
Libre (SIGASP_CLEAR_2)
}
Cambio del estado de la señal almacenado
en la variable state:
draw_state =
def_draw_state (state);