first commit
This commit is contained in:
330
Scripts/Binari.gd
Normal file
330
Scripts/Binari.gd
Normal file
@@ -0,0 +1,330 @@
|
||||
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("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
|
||||
|
||||
@export_group("Costruzione Rotaie")
|
||||
@export var distanza_traversine: float = 1.0
|
||||
@export var modello_traversina: PackedScene
|
||||
|
||||
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 _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)
|
||||
# 1. POSIZIONA
|
||||
fuoco_root.global_position = treno_istanziato.global_position + Vector3(offset_x, 0.5, offset_z)
|
||||
|
||||
# 2. COLORA E ACCENDI
|
||||
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
|
||||
|
||||
# 1. Il centro matematico perfetto e incontrovertibile del treno
|
||||
var pos_centro = to_global(curve.sample_baked(progresso_treno, true))
|
||||
|
||||
# 2. Il punto in cui deve guardare (abbastanza lontano per non vibrare)
|
||||
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:
|
||||
# Posizionamento esatto, zero vibrazioni laterali
|
||||
treno_istanziato.global_position = pos_centro
|
||||
treno_istanziato.look_at(pos_davanti, Vector3.UP)
|
||||
treno_istanziato.rotate_y(PI)
|
||||
|
||||
if gruppo_camere:
|
||||
# La telecamera segue il punto perfetto
|
||||
gruppo_camere.global_position = gruppo_camere.global_position.lerp(pos_centro, delta * 12.0)
|
||||
|
||||
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)
|
||||
|
||||
# 1. POSIZIONA
|
||||
fuoco_root.global_position = posizione_marker + Vector3(offset_x, 0.5, offset_z)
|
||||
|
||||
# 2. COLORA E ACCENDI
|
||||
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_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 _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)
|
||||
Reference in New Issue
Block a user