Files
tgcc-artest/Scripts/Binari.gd
Matteo Sonaglioni 8faf4e91b5 Ponte - Pali
2026-03-30 20:22:00 +02:00

264 lines
9.4 KiB
GDScript

extends Path3D
@export_group("Impostazioni Treno")
@export var velocita_treno: float = 6.0
@export var in_movimento: bool = true
@export var modello_treno: PackedScene
@export var distanza_assi: float = 3.0
@export var larghezza_binari: float = 1.2
@export var gruppo_camere: Node3D
@export_group("Costruzione Rotaie")
@export var distanza_traversine: float = 1.0
@export var modello_traversina: PackedScene
@export_group("Controlli Manuali")
@export var velocita_max: float = 15.0
@export var velocita_min: float = -5.0
@export var accelerazione_manuale: float = 5.0
@export_group("Fermate (Stazioni)")
@export var abilita_fermate: bool = true
@export var tempo_di_sosta: float = 4.0
@export var distanza_frenata: float = 15.0
@export var tempo_ripartenza: float = 3.0
@export var scena_fuochi: PackedScene
var colori_fuochi: Array[Color] = [
Color(1.0, 0.2, 0.2), # Rosso vivo
Color(0.2, 1.0, 0.2), # Verde lime
Color(0.3, 0.5, 1.0), # Blu cielo
Color(1.0, 0.8, 0.1), # Oro
Color(0.8, 0.2, 1.0), # Viola
Color(0.1, 1.0, 0.9) # Ciano
]
@export_group("Movimento e Oscillazione")
@export_range(0.0, 1.0) var intensita_oscillazione_base: float = 0.5
var treno_istanziato: Node3D
var progresso_treno: float = 0.0
var tempo_oscillazione: float = 0.0
var offsets_fermate: Array[float] = []
var posizioni_fermate: Array[Vector3] = []
var fermata_in_corso: bool = false
var indice_prossima_fermata: int = 0
var moltiplicatore_stazione: float = 1.0
var in_ripartenza: bool = false
var tween_ripartenza: Tween
func _ready() -> void:
if curve != null and curve.get_baked_length() > 0:
_costruisci_rotaie_da_zero()
_costruisci_treno()
_calcola_fermate()
else:
print("ATTENZIONE: Devi prima disegnare i punti del Path3D!")
func _costruisci_rotaie_da_zero() -> void:
var lunghezza_totale = curve.get_baked_length()
var numero_pezzi = int(lunghezza_totale / distanza_traversine)
for i in range(numero_pezzi):
var distanza = i * distanza_traversine
var pezzo_binario = Node3D.new()
add_child(pezzo_binario)
var pos_attuale_locale = curve.sample_baked(distanza, true)
var distanza_avanti = distanza + 0.1
var pos_avanti_locale = Vector3.ZERO
# Calcola la posizione successiva per orientare correttamente il pezzo
if distanza_avanti > lunghezza_totale:
var pos_dietro = curve.sample_baked(distanza - 0.1, true)
pos_avanti_locale = pos_attuale_locale + (pos_attuale_locale - pos_dietro)
else:
pos_avanti_locale = curve.sample_baked(distanza_avanti, true)
pezzo_binario.position = pos_attuale_locale
var globale_attuale = to_global(pos_attuale_locale)
var globale_avanti = to_global(pos_avanti_locale)
# Ruota il pezzo affinché segua la curva
if globale_attuale.distance_to(globale_avanti) > 0.001:
pezzo_binario.look_at(globale_avanti, Vector3.UP)
# Inserisce ESCLUSIVAMENTE il tuo modello (che contiene traversine e rotaie)
if modello_traversina:
var pezzo_custom = modello_traversina.instantiate()
pezzo_binario.add_child(pezzo_custom)
func _calcola_fermate() -> void:
var fermate_temp = []
for figlio in get_children():
if figlio is Marker3D:
var offset = curve.get_closest_offset(figlio.position)
fermate_temp.append({
"offset": offset,
"posizione": figlio.global_position
})
fermate_temp.sort_custom(func(a, b): return a["offset"] < b["offset"])
for dati in fermate_temp:
offsets_fermate.append(dati["offset"])
posizioni_fermate.append(dati["posizione"])
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and not event.echo:
if event.keycode == KEY_T:
_teletrasporta_prossima_fermata()
elif event.keycode == KEY_F:
_test_fuochi_manuale()
func _test_fuochi_manuale() -> void:
if scena_fuochi == null or treno_istanziato == null: return
print("Lancio fuochi d'artificio di test!")
var num_fuochi = randi_range(5, 8)
for i in range(num_fuochi):
var fuoco_root = scena_fuochi.instantiate()
get_tree().current_scene.add_child(fuoco_root)
var offset_x = randf_range(-6.0, 6.0)
var offset_z = randf_range(-6.0, 6.0)
fuoco_root.global_position = treno_istanziato.global_position + Vector3(offset_x, 0.5, offset_z)
if fuoco_root.has_method("imposta_colore"):
fuoco_root.imposta_colore(colori_fuochi.pick_random())
if fuoco_root.has_method("accendi"):
fuoco_root.accendi()
await get_tree().create_timer(randf_range(0.2, 0.6)).timeout
func _teletrasporta_prossima_fermata() -> void:
if offsets_fermate.size() == 0 or fermata_in_corso or in_ripartenza:
return
var target_offset = offsets_fermate[indice_prossima_fermata]
progresso_treno = target_offset
_esegui_fermata(velocita_treno >= 0)
func _physics_process(delta: float) -> void:
_gestione_input_movimento(delta)
_gestione_movimento_treno(delta)
func _gestione_input_movimento(delta: float) -> void:
if not in_movimento: return
if Input.is_action_pressed("ui_up"):
velocita_treno += accelerazione_manuale * delta
elif Input.is_action_pressed("ui_down"):
velocita_treno -= accelerazione_manuale * delta
velocita_treno = clamp(velocita_treno, velocita_min, velocita_max)
func _gestione_movimento_treno(delta: float) -> void:
if in_movimento and treno_istanziato and curve:
var lunghezza_totale = curve.get_baked_length()
if lunghezza_totale <= 0: return
if not fermata_in_corso:
var vecchio_progresso = progresso_treno
if abilita_fermate and offsets_fermate.size() > 0 and not in_ripartenza:
var target_offset = offsets_fermate[indice_prossima_fermata]
var dist = target_offset - progresso_treno
dist = wrapf(dist + lunghezza_totale / 2.0, 0.0, lunghezza_totale) - lunghezza_totale / 2.0
if abs(dist) < distanza_frenata and sign(dist) == sign(velocita_treno):
var t = abs(dist) / distanza_frenata
moltiplicatore_stazione = max(smoothstep(0.0, 1.0, t), 0.05)
else:
moltiplicatore_stazione = 1.0
var velocita_attuale = velocita_treno * moltiplicatore_stazione
progresso_treno += velocita_attuale * delta
if abilita_fermate and offsets_fermate.size() > 0:
var target_offset = offsets_fermate[indice_prossima_fermata]
var superato_avanti = (velocita_attuale > 0 and vecchio_progresso < target_offset and progresso_treno >= target_offset)
var superato_indietro = (velocita_attuale < 0 and vecchio_progresso > target_offset and progresso_treno <= target_offset)
if superato_avanti or superato_indietro:
progresso_treno = target_offset
_esegui_fermata(velocita_attuale > 0)
if progresso_treno > lunghezza_totale:
progresso_treno -= lunghezza_totale
if offsets_fermate.size() > 0: indice_prossima_fermata = 0
elif progresso_treno < 0:
progresso_treno += lunghezza_totale
if offsets_fermate.size() > 0: indice_prossima_fermata = offsets_fermate.size() - 1
var pos_centro = to_global(curve.sample_baked(progresso_treno, true))
var prog_davanti = wrapf(progresso_treno + 2.0, 0.0, lunghezza_totale)
var pos_davanti = to_global(curve.sample_baked(prog_davanti, true))
if pos_centro.distance_to(pos_davanti) > 0.01:
treno_istanziato.global_position = pos_centro
treno_istanziato.look_at(pos_davanti, Vector3.UP)
treno_istanziato.rotate_y(PI)
if gruppo_camere:
# Nessun ritardo, nessuna molla: posizione e rotazione sono incollate a quelle del treno!
gruppo_camere.global_position = pos_centro
gruppo_camere.global_basis = treno_istanziato.global_basis
if not fermata_in_corso:
var vel_reale = abs(velocita_treno * moltiplicatore_stazione)
tempo_oscillazione += delta * vel_reale * 2.0
var ampiezza_z = 0.006 * intensita_oscillazione_base
var ampiezza_x = 0.004 * intensita_oscillazione_base
treno_istanziato.rotation.z += sin(tempo_oscillazione) * ampiezza_z
treno_istanziato.rotation.x += cos(tempo_oscillazione * 0.8) * ampiezza_x
func _esegui_fermata(andando_avanti: bool = true) -> void:
fermata_in_corso = true
moltiplicatore_stazione = 0.0
var indice_stazione_attuale = indice_prossima_fermata
if andando_avanti:
indice_prossima_fermata += 1
if indice_prossima_fermata >= offsets_fermate.size():
indice_prossima_fermata = 0
else:
indice_prossima_fermata -= 1
if indice_prossima_fermata < 0:
indice_prossima_fermata = offsets_fermate.size() - 1
if scena_fuochi != null:
var posizione_marker = posizioni_fermate[indice_stazione_attuale]
var num_fuochi = randi_range(5, 8)
for i in range(num_fuochi):
var fuoco_root = scena_fuochi.instantiate()
get_tree().current_scene.add_child(fuoco_root)
var offset_x = randf_range(-5.0, 5.0)
var offset_z = randf_range(-5.0, 5.0)
fuoco_root.global_position = posizione_marker + Vector3(offset_x, 0.5, offset_z)
if fuoco_root.has_method("imposta_colore"):
fuoco_root.imposta_colore(colori_fuochi.pick_random())
if fuoco_root.has_method("accendi"):
fuoco_root.accendi()
await get_tree().create_timer(randf_range(0.3, 0.8)).timeout
await get_tree().create_timer(tempo_di_sosta).timeout
fermata_in_corso = false
in_ripartenza = true
if tween_ripartenza and tween_ripartenza.is_valid():
tween_ripartenza.kill()
tween_ripartenza = create_tween()
tween_ripartenza.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
tween_ripartenza.tween_property(self, "moltiplicatore_stazione", 1.0, tempo_ripartenza)
tween_ripartenza.tween_callback(func(): in_ripartenza = false)
func _costruisci_treno() -> void:
if modello_treno != null:
treno_istanziato = modello_treno.instantiate()
add_child(treno_istanziato)