324 lines
11 KiB
GDScript
324 lines
11 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 mat_legno = StandardMaterial3D.new()
|
|
mat_legno.albedo_color = Color(0.35, 0.2, 0.1)
|
|
var mat_ferro = StandardMaterial3D.new()
|
|
mat_ferro.albedo_color = Color(0.6, 0.6, 0.65)
|
|
mat_ferro.metallic = 0.8
|
|
|
|
var mesh_traversina_default = BoxMesh.new()
|
|
mesh_traversina_default.size = Vector3(larghezza_binari + 0.6, 0.1, 0.3)
|
|
var mesh_binario = BoxMesh.new()
|
|
mesh_binario.size = Vector3(0.1, 0.15, distanza_traversine + 0.05)
|
|
|
|
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
|
|
|
|
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)
|
|
if globale_attuale.distance_to(globale_avanti) > 0.001:
|
|
pezzo_binario.look_at(globale_avanti, Vector3.UP)
|
|
|
|
if modello_traversina != null:
|
|
var traversina_custom = modello_traversina.instantiate()
|
|
pezzo_binario.add_child(traversina_custom)
|
|
else:
|
|
var traversina = MeshInstance3D.new()
|
|
traversina.mesh = mesh_traversina_default
|
|
traversina.material_override = mat_legno
|
|
pezzo_binario.add_child(traversina)
|
|
|
|
var binario_sx = MeshInstance3D.new()
|
|
binario_sx.mesh = mesh_binario
|
|
binario_sx.material_override = mat_ferro
|
|
binario_sx.position = Vector3(-larghezza_binari / 2.0, 0.1, 0)
|
|
pezzo_binario.add_child(binario_sx)
|
|
|
|
var binario_dx = MeshInstance3D.new()
|
|
binario_dx.mesh = mesh_binario
|
|
binario_dx.material_override = mat_ferro
|
|
binario_dx.position = Vector3(larghezza_binari / 2.0, 0.1, 0)
|
|
pezzo_binario.add_child(binario_dx)
|
|
|
|
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)
|
|
else:
|
|
_costruisci_trenino_default()
|
|
|
|
func _costruisci_trenino_default() -> void:
|
|
treno_istanziato = Node3D.new()
|
|
add_child(treno_istanziato)
|
|
|
|
var mat_carrozzeria = StandardMaterial3D.new()
|
|
mat_carrozzeria.albedo_color = Color(0.8, 0.15, 0.15)
|
|
var mat_vetro = StandardMaterial3D.new()
|
|
mat_vetro.albedo_color = Color(0.2, 0.8, 1.0)
|
|
|
|
var base_treno = MeshInstance3D.new()
|
|
var mesh_base = BoxMesh.new()
|
|
mesh_base.size = Vector3(1.4, 0.8, 3.0)
|
|
base_treno.mesh = mesh_base
|
|
base_treno.material_override = mat_carrozzeria
|
|
base_treno.position = Vector3(0, 0.6, 0)
|
|
treno_istanziato.add_child(base_treno)
|
|
|
|
var cabina = MeshInstance3D.new()
|
|
var mesh_cabina = BoxMesh.new()
|
|
mesh_cabina.size = Vector3(1.4, 1.0, 1.2)
|
|
cabina.mesh = mesh_cabina
|
|
cabina.material_override = mat_vetro
|
|
cabina.position = Vector3(0, 1.5, -0.8)
|
|
treno_istanziato.add_child(cabina)
|
|
|
|
var ciminiera = MeshInstance3D.new()
|
|
var mesh_ciminiera = CylinderMesh.new()
|
|
mesh_ciminiera.top_radius = 0.2
|
|
mesh_ciminiera.bottom_radius = 0.3
|
|
mesh_ciminiera.height = 0.8
|
|
ciminiera.mesh = mesh_ciminiera
|
|
ciminiera.material_override = mat_carrozzeria
|
|
ciminiera.position = Vector3(0, 1.2, 1.0)
|
|
treno_istanziato.add_child(ciminiera)
|