Ponte - Pali

This commit is contained in:
Matteo Sonaglioni
2026-03-30 20:22:00 +02:00
parent 1f56b8c5d8
commit 8faf4e91b5
43 changed files with 1542 additions and 282 deletions

View File

@@ -57,17 +57,6 @@ func _ready() -> void:
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)
@@ -80,6 +69,7 @@ func _costruisci_rotaie_da_zero() -> void:
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)
@@ -89,29 +79,15 @@ func _costruisci_rotaie_da_zero() -> void:
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)
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)
# 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 = []
@@ -284,40 +260,4 @@ 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)

View File

@@ -71,6 +71,7 @@ extends Node3D
@export var materiale_nuvole: ShaderMaterial
@export var nodo_polvere: ColorRect
@export var materiale_acqua: ShaderMaterial
@export var materiale_fili_luce: ShaderMaterial
@export_group("Meteo (Pioggia & Fulmini)")
@export var colore_mood_pioggia: Color = Color(0.5, 0.6, 0.7, 1.0)
@@ -105,6 +106,7 @@ extends Node3D
@export var quantita_vento: int = 100
@export var raggio_spawn_vento: float = 25.0
@export var altezza_spawn_vento: float = 5.0
@export_range(0.0, 5.0) var forza_vento_fili_base: float = 1.0
@export_group("Neve")
@export var bottone_neve: Button
@@ -323,6 +325,12 @@ func _process(delta: float) -> void:
materiale_acqua.set_shader_parameter("ripple_speed", ripple_speed)
materiale_acqua.set_shader_parameter("deep_water_color", final_acqua_deep)
# --- GESTIONE VENTO DEI FILI DELLA LUCE ---
if materiale_fili_luce:
# Interpoliamo tra la forza base (es. 1.0) e una bufera (5.0) in base alla pioggia
var vento_attuale = lerp(forza_vento_fili_base, 5.0, intensita_pioggia)
materiale_fili_luce.set_shader_parameter("forza_vento", vento_attuale)
var night_val = clamp(tempo_giorno - 2.0, 0.0, 1.0)

View File

@@ -10,6 +10,12 @@ extends Node3D
@export var dimensione_chunk: float = 20.0
@export var raggio_visivo: int = 3
@export var scala_distretti: float = 0.05
@export var materiale_filo_palo: ShaderMaterial # <--- NUOVO MATERIALE PER I FILI
@export_range(0.01, 1.0) var spessore_filo: float = 0.05
@export_range(0.0, 5.0) var forza_vento_fili: float = 1.0 # <--- SLIDER DEL VENTO
# Memoria per non doppiare i fili tra due chunk
var connessioni_pali: Dictionary = {}
var scacchiera: Dictionary = {}
var ultima_pos_griglia_treno: Vector2i = Vector2i(999999, 999999)
@@ -21,6 +27,7 @@ var dropdown_biomi: OptionButton
var lbl_bioma: Label
var lbl_distanza: Label
func _ready() -> void:
if lista_biomi.is_empty() or path_treno == null: return
@@ -35,7 +42,7 @@ func _ready() -> void:
generatore_altitudine.frequency = scala_distretti * 0.5
_crea_ui_gps()
_aggiorna_set_pieces() # Accende/Spegne i mega-templi all'avvio
_aggiorna_set_pieces()
print("✅ Generatore a Distretti Dinamici Pronto.")
func _crea_ui_gps() -> void:
@@ -81,17 +88,10 @@ func _crea_ui_gps() -> void:
_radar_bioma_treno()
# --- GESTIONE DEI MEGA-PEZZI (SET PIECES) ---
# --- GESTIONE DEI MEGA-PEZZI (SET PIECES) ---
func _aggiorna_set_pieces() -> void:
var set_pieces = get_tree().get_nodes_in_group("set_pieces")
print("\n--- CONTROLLO SET PIECES ---")
print("🔍 Trovati ", set_pieces.size(), " Set Pieces nel gruppo 'set_pieces'.")
for sp in set_pieces:
if not "bioma_esclusivo" in sp or sp.bioma_esclusivo == "":
print("⚠️ Il Set Piece '", sp.name, "' non ha un bioma_esclusivo impostato. Rimarrà sempre visibile.")
continue
var bioma_locale = ""
@@ -102,44 +102,35 @@ func _aggiorna_set_pieces() -> void:
var grid_z = roundi(sp.global_position.z / dimensione_chunk)
bioma_locale = _get_nome_bioma_procedurale(generatore_rumore.get_noise_2d(grid_x, grid_z))
print("👉 Analizzo: '", sp.name, "' | Vuole il bioma: [", sp.bioma_esclusivo, "] | Il bioma attuale qui è: [", bioma_locale, "]")
if bioma_locale == sp.bioma_esclusivo:
sp.show()
sp.process_mode = Node.PROCESS_MODE_INHERIT
print(" ✅ CORRISPONDENZA! Il tempio è ORA VISIBILE E SOLIDO.")
else:
sp.hide()
sp.process_mode = Node.PROCESS_MODE_DISABLED
print(" ❌ NIENTE CORRISPONDENZA! Il tempio è ORA UN FANTASMA INVISIBILE.")
print("----------------------------\n")
func _on_dropdown_biomi_item_selected(indice: int) -> void:
if indice == 0: bioma_manuale_attivo = null
else: bioma_manuale_attivo = lista_biomi[indice - 1]
_distruggi_e_rigenera_mondo()
func _distruggi_e_rigenera_mondo() -> void:
# 1. Spegne i templi vecchi e accende quelli nuovi PRIMA di pulire la memoria
_aggiorna_set_pieces()
# 2. Distrugge fisicamente tutti i modelli 3D dei biomi procedurali
for pos in scacchiera.keys():
var cella = scacchiera[pos]
if cella["tipo"] == "bioma":
if cella.has("nodo") and is_instance_valid(cella["nodo"]):
cella["nodo"].queue_free()
# 3. AMNESIA TOTALE: Svuotiamo l'intero dizionario (sia biomi che ostacoli vecchi)
scacchiera.clear()
# 4. Forziamo il treno a sparare i laser e ricreare la mappa al prossimo frame
connessioni_pali.clear()
ultima_pos_griglia_treno = Vector2i(999999, 999999)
_radar_bioma_treno()
ultima_pos_griglia_treno = Vector2i(999999, 999999)
_radar_bioma_treno()
func _physics_process(_delta: float) -> void:
if path_treno == null or path_treno.treno_istanziato == null: return
@@ -153,6 +144,10 @@ func _physics_process(_delta: float) -> void:
_genera_attorno_al_treno(pos_attuale)
_pulisci_chunk_lontani(pos_attuale)
_radar_bioma_treno()
# Aggiorna il vento dei fili
if materiale_filo_palo and materiale_filo_palo is ShaderMaterial:
materiale_filo_palo.set_shader_parameter("forza_vento", forza_vento_fili)
func _genera_attorno_al_treno(centro: Vector2i) -> void:
for x in range(-raggio_visivo, raggio_visivo + 1):
@@ -167,7 +162,6 @@ func _genera_attorno_al_treno(centro: Vector2i) -> void:
func _scegli_catalogo_per_cella(pos_griglia: Vector2i) -> Array[PackedScene]:
if bioma_manuale_attivo != null:
return bioma_manuale_attivo.chunk_disponibili
var valore = generatore_rumore.get_noise_2d(pos_griglia.x, pos_griglia.y)
var valore_normalizzato = (valore + 1.0) / 2.0
var indice = clamp(int(valore_normalizzato * lista_biomi.size()), 0, lista_biomi.size() - 1)
@@ -176,7 +170,6 @@ func _scegli_catalogo_per_cella(pos_griglia: Vector2i) -> Array[PackedScene]:
func _get_nome_bioma_procedurale(valore: float) -> String:
if bioma_manuale_attivo != null:
return bioma_manuale_attivo.nome_bioma
var valore_normalizzato = (valore + 1.0) / 2.0
var indice = clamp(int(valore_normalizzato * lista_biomi.size()), 0, lista_biomi.size() - 1)
return lista_biomi[indice].nome_bioma
@@ -198,6 +191,7 @@ func _registra_cella_con_laser(pos_griglia: Vector2i) -> bool:
var uscite_trovate = {"nord": false, "est": false, "sud": false, "ovest": false}
var altezze_trovate = {"nord": 0, "est": 0, "sud": 0, "ovest": 0}
# Risaliamo l'albero per trovare lo script InfoChunk
while nodo_corrente != null and nodo_corrente != get_tree().root:
if nodo_corrente.has_method("get_dati_ruotati"):
var scatti_rotazione = roundi(rad_to_deg(nodo_corrente.global_rotation.y) / -90.0)
@@ -207,7 +201,24 @@ func _registra_cella_con_laser(pos_griglia: Vector2i) -> bool:
break
nodo_corrente = nodo_corrente.get_parent()
scacchiera[pos_griglia] = {"tipo": "ostacolo", "uscite": uscite_trovate, "altezze": altezze_trovate}
# --- VERIFICA DEI PALI SUL PEZZO PRE-COSTRUITO ---
var ha_il_palo = false
if nodo_corrente != null and "ha_palo_luce" in nodo_corrente:
ha_il_palo = nodo_corrente.ha_palo_luce
scacchiera[pos_griglia] = {
"tipo": "ostacolo",
"uscite": uscite_trovate,
"altezze": altezze_trovate,
"nodo": nodo_corrente,
"ha_palo": ha_il_palo # Salviamo in memoria che questo binario ha i pali
}
# MAGIA: Se il laser ha scoperto un tuo binario pre-costruito con i pali,
# lo tratta come se fosse appena spawnato e lancia i fili verso i vicini!
if ha_il_palo:
_collega_pali_luce(pos_griglia, nodo_corrente)
return true
return false
@@ -279,28 +290,31 @@ func _piazza_bioma_compatibile(pos_griglia: Vector2i) -> void:
nuovo_chunk.position = Vector3(pos_griglia.x * dimensione_chunk, 0, pos_griglia.y * dimensione_chunk)
nuovo_chunk.rotation.y = scelto.rotazione * (-PI / 2.0)
scacchiera[pos_griglia] = {"tipo": "bioma", "uscite": scelto.dati["connessioni"], "altezze": scelto.dati["altezze"], "nodo": nuovo_chunk}
# --- SALVATAGGIO NELLA SCACCHIERA INCLUDENDO IL PALO ---
var ha_il_palo = "ha_palo_luce" in nuovo_chunk and nuovo_chunk.ha_palo_luce
scacchiera[pos_griglia] = {
"tipo": "bioma",
"uscite": scelto.dati["connessioni"],
"altezze": scelto.dati["altezze"],
"nodo": nuovo_chunk,
"ha_palo": ha_il_palo
}
# Se il chunk appena piazzato ha un palo, lanciamo i fili verso un vicino
if ha_il_palo:
_collega_pali_luce(pos_griglia, nuovo_chunk)
else:
push_warning("⚠️ MANCA UN PEZZO IN CATALOGO PER LA POSIZIONE " + str(pos_griglia) + "!")
var fmt_alt = func(req): return str(req) if req != -1 else "Libero"
var fmt_conn = func(req): return "" if req == 1 else ("No" if req == 0 else "Libero")
print("--- IDENTIKIT DEL PEZZO CHE TI MANCA ---")
print("Altezze richieste -> Nord: ", fmt_alt.call(req_alt_nord), " | Est: ", fmt_alt.call(req_alt_est), " | Sud: ", fmt_alt.call(req_alt_sud), " | Ovest: ", fmt_alt.call(req_alt_ovest))
print("----------------------------------------\n")
var backup = catalogo_zona[0].instantiate()
add_child(backup)
backup.position = Vector3(pos_griglia.x * dimensione_chunk, 0, pos_griglia.y * dimensione_chunk)
var altezze_sicure = {
"nord": req_alt_nord if req_alt_nord != -1 else altitudine_target,
"est": req_alt_est if req_alt_est != -1 else altitudine_target,
"sud": req_alt_sud if req_alt_sud != -1 else altitudine_target,
"ovest": req_alt_ovest if req_alt_ovest != -1 else altitudine_target
}
scacchiera[pos_griglia] = {"tipo": "bioma", "uscite": {"nord":false, "est":false, "sud":false, "ovest":false}, "altezze": altezze_sicure, "nodo": backup}
scacchiera[pos_griglia] = {"tipo": "bioma", "uscite": {"nord":false, "est":false, "sud":false, "ovest":false}, "altezze": altezze_sicure, "nodo": backup, "ha_palo": false}
func _richiede_connessione(pos_vicino: Vector2i, lato_richiesto: String) -> int:
if not scacchiera.has(pos_vicino):
@@ -316,12 +330,10 @@ func _richiede_altezza(pos_vicino: Vector2i, lato_richiesto: String) -> int:
func _radar_bioma_treno() -> void:
if path_treno == null or path_treno.curve == null or path_treno.treno_istanziato == null: return
if bioma_manuale_attivo != null:
if lbl_bioma: lbl_bioma.text = bioma_manuale_attivo.nome_bioma
if lbl_distanza: lbl_distanza.text = "Override manuale (Infinita)"
return
var pos_treno = path_treno.treno_istanziato.global_position
var grid_x = roundi(pos_treno.x / dimensione_chunk)
var grid_z = roundi(pos_treno.z / dimensione_chunk)
@@ -336,11 +348,9 @@ func _radar_bioma_treno() -> void:
var progresso_futuro = wrapf(progresso_attuale + (step * dimensione_chunk), 0.0, lunghezza_totale)
var pos_futura_locale = path_treno.curve.sample_baked(progresso_futuro, true)
var pos_futura_globale = path_treno.to_global(pos_futura_locale)
var f_x = roundi(pos_futura_globale.x / dimensione_chunk)
var f_z = roundi(pos_futura_globale.z / dimensione_chunk)
var bioma_futuro = _get_nome_bioma_procedurale(generatore_rumore.get_noise_2d(f_x, f_z))
if bioma_futuro != bioma_attuale:
distanza_cambio = step * dimensione_chunk
prossimo_bioma = bioma_futuro
@@ -371,3 +381,197 @@ func _pulisci_chunk_lontani(centro_attuale: Vector2i) -> void:
for pos in celle_da_rimuovere:
scacchiera.erase(pos)
# ==========================================================
# ============ NUOVE FUNZIONI FILI DELLA LUCE ==============
# ==========================================================
# --- 1. FUNZIONE SCUDO: Trova i pali anche se hai dimenticato di aggiornare l'Inspector ---
# --- 1. FUNZIONE SCUDO (Più sicura contro i nodi nulli) ---
func _ottieni_pali(chunk: Node3D, lato: String) -> Array[Node3D]:
var pali: Array[Node3D] = []
if lato == "sx":
if "attacchi_sx" in chunk and chunk.attacchi_sx != null:
for p in chunk.attacchi_sx:
if is_instance_valid(p): pali.append(p)
# Se l'array è vuoto, usa il vecchio nodo singolo
if pali.is_empty() and "nodo_attacco_sx" in chunk and is_instance_valid(chunk.get("nodo_attacco_sx")):
pali.append(chunk.get("nodo_attacco_sx"))
else:
if "attacchi_dx" in chunk and chunk.attacchi_dx != null:
for p in chunk.attacchi_dx:
if is_instance_valid(p): pali.append(p)
if pali.is_empty() and "nodo_attacco_dx" in chunk and is_instance_valid(chunk.get("nodo_attacco_dx")):
pali.append(chunk.get("nodo_attacco_dx"))
return pali
# --- 2. LA LOGICA DI COLLEGAMENTO (Raggio Ampio) ---
func _collega_pali_luce(pos_griglia_nuovo: Vector2i, chunk_nuovo: Node3D) -> void:
if chunk_nuovo is Node3D: chunk_nuovo.force_update_transform()
var sx_nuovi = _ottieni_pali(chunk_nuovo, "sx")
var dx_nuovi = _ottieni_pali(chunk_nuovo, "dx")
if sx_nuovi.is_empty() or dx_nuovi.is_empty(): return
var id_nuovo = chunk_nuovo.get_instance_id()
if not connessioni_pali.has(id_nuovo): connessioni_pali[id_nuovo] = 0
# Se ha già 2 fili, si ferma qui.
if connessioni_pali[id_nuovo] >= 2: return
var p_sx_mio_best = null; var p_dx_mio_best = null
var p_sx_tuo_best = null; var p_dx_tuo_best = null
var miglior_vicino = null
var miglior_distanza = 999999.0
# RAGGIO GIGANTE: Scansioniamo un'area 13x13 celle (circa 260 metri!)
# Questo garantisce che nessun palo venga MAI saltato, anche nelle curve più larghe.
var raggio_ricerca = 3
# FASE 1: Cerchiamo un palo "pulito" (con meno di 2 fili)
for x in range(-raggio_ricerca, raggio_ricerca + 1):
for z in range(-raggio_ricerca, raggio_ricerca + 1):
if x == 0 and z == 0: continue
var pos_vicino = pos_griglia_nuovo + Vector2i(x, z)
if scacchiera.has(pos_vicino) and scacchiera[pos_vicino].get("ha_palo", false):
var chunk_vicino = scacchiera[pos_vicino]["nodo"]
if not is_instance_valid(chunk_vicino) or chunk_vicino == chunk_nuovo: continue
var id_vicino = chunk_vicino.get_instance_id()
var conn_vicino = connessioni_pali.get(id_vicino, 0)
# Ignoriamo i pali già pieni
if conn_vicino >= 2: continue
if chunk_vicino is Node3D: chunk_vicino.force_update_transform()
var sx_vicini = _ottieni_pali(chunk_vicino, "sx")
var dx_vicini = _ottieni_pali(chunk_vicino, "dx")
if sx_vicini.is_empty() or dx_vicini.is_empty(): continue
for i_m in range(sx_nuovi.size()):
for i_t in range(sx_vicini.size()):
var c_mio = (sx_nuovi[i_m].global_position + dx_nuovi[i_m].global_position) / 2.0
var c_tuo = (sx_vicini[i_t].global_position + dx_vicini[i_t].global_position) / 2.0
var dist = c_mio.distance_to(c_tuo)
if dist < miglior_distanza:
miglior_distanza = dist
miglior_vicino = chunk_vicino
p_sx_mio_best = sx_nuovi[i_m]
p_dx_mio_best = dx_nuovi[i_m]
p_sx_tuo_best = sx_vicini[i_t]
p_dx_tuo_best = dx_vicini[i_t]
# FASE 2 (Estrema Razio): Se c'è un buco enorme e non troviamo pali "puliti",
# ci leghiamo a QUALSIASI palo nel raggio di 260m pur di non rimanere isolati.
if miglior_vicino == null:
for x in range(-raggio_ricerca, raggio_ricerca + 1):
for z in range(-raggio_ricerca, raggio_ricerca + 1):
if x == 0 and z == 0: continue
var pos_vicino = pos_griglia_nuovo + Vector2i(x, z)
if scacchiera.has(pos_vicino) and scacchiera[pos_vicino].get("ha_palo", false):
var chunk_vicino = scacchiera[pos_vicino]["nodo"]
if not is_instance_valid(chunk_vicino) or chunk_vicino == chunk_nuovo: continue
if chunk_vicino is Node3D: chunk_vicino.force_update_transform()
var sx_vicini = _ottieni_pali(chunk_vicino, "sx")
var dx_vicini = _ottieni_pali(chunk_vicino, "dx")
if sx_vicini.is_empty() or dx_vicini.is_empty(): continue
for i_m in range(sx_nuovi.size()):
for i_t in range(sx_vicini.size()):
var c_mio = (sx_nuovi[i_m].global_position + dx_nuovi[i_m].global_position) / 2.0
var c_tuo = (sx_vicini[i_t].global_position + dx_vicini[i_t].global_position) / 2.0
var dist = c_mio.distance_to(c_tuo)
if dist < miglior_distanza:
miglior_distanza = dist
miglior_vicino = chunk_vicino
p_sx_mio_best = sx_nuovi[i_m]
p_dx_mio_best = dx_nuovi[i_m]
p_sx_tuo_best = sx_vicini[i_t]
p_dx_tuo_best = dx_vicini[i_t]
# CREAZIONE DEL COLLEGAMENTO
# Abbiamo allungato la tolleranza a 8 chunk (160 metri) per permettere fili lunghissimi se necessari!
var max_dist = dimensione_chunk * 8.0
if miglior_vicino != null and miglior_distanza < max_dist:
var dist_dritto = p_sx_mio_best.global_position.distance_to(p_sx_tuo_best.global_position) + p_dx_mio_best.global_position.distance_to(p_dx_tuo_best.global_position)
var dist_incrocio = p_sx_mio_best.global_position.distance_to(p_dx_tuo_best.global_position) + p_dx_mio_best.global_position.distance_to(p_sx_tuo_best.global_position)
if dist_dritto <= dist_incrocio:
_disegna_parabola(p_sx_mio_best.global_position, p_sx_tuo_best.global_position, chunk_nuovo)
_disegna_parabola(p_dx_mio_best.global_position, p_dx_tuo_best.global_position, chunk_nuovo)
else:
_disegna_parabola(p_sx_mio_best.global_position, p_dx_tuo_best.global_position, chunk_nuovo)
_disegna_parabola(p_dx_mio_best.global_position, p_sx_tuo_best.global_position, chunk_nuovo)
connessioni_pali[id_nuovo] += 1
var id_vicino = miglior_vicino.get_instance_id()
if not connessioni_pali.has(id_vicino): connessioni_pali[id_vicino] = 0
connessioni_pali[id_vicino] += 1
func _disegna_parabola(p1: Vector3, p2: Vector3, genitore: Node3D) -> void:
var segmenti = 15
var abbassamento = 1.5
var punti_curva = []
var sag_factors = [] # Salva quanto è "al centro" ogni punto
for i in range(segmenti + 1):
var t = float(i) / float(segmenti)
var pos_globale = p1.lerp(p2, t)
var gravita = abbassamento * (1.0 - pow(2.0 * t - 1.0, 2.0))
pos_globale.y -= gravita
punti_curva.append(genitore.to_local(pos_globale))
# Curva del vento: 0 agli estremi, 1.0 al centro spaccato
sag_factors.append(sin(t * PI))
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_TRIANGLES)
var lati = 4
var raggio = spessore_filo / 2.0
for i in range(punti_curva.size() - 1):
var p_corrente = punti_curva[i]
var p_prossimo = punti_curva[i+1]
var sag_corrente = sag_factors[i]
var sag_prossimo = sag_factors[i+1]
var dir = (p_prossimo - p_corrente).normalized()
var up = Vector3.UP
var right = dir.cross(up).normalized()
if right.length_squared() < 0.01:
right = dir.cross(Vector3.RIGHT).normalized()
up = right.cross(dir).normalized()
for s in range(lati):
var ang1 = (float(s) / lati) * TAU
var ang2 = (float((s + 1) % lati) / lati) * TAU
var offset1 = (right * cos(ang1) + up * sin(ang1)) * raggio
var offset2 = (right * cos(ang2) + up * sin(ang2)) * raggio
# Diciamo al colore del vertice quanto può muoversi con il vento!
st.set_color(Color(sag_corrente, 0, 0, 1))
st.add_vertex(p_corrente + offset1)
st.set_color(Color(sag_corrente, 0, 0, 1))
st.add_vertex(p_corrente + offset2)
st.set_color(Color(sag_prossimo, 0, 0, 1))
st.add_vertex(p_prossimo + offset1)
st.set_color(Color(sag_corrente, 0, 0, 1))
st.add_vertex(p_corrente + offset2)
st.set_color(Color(sag_prossimo, 0, 0, 1))
st.add_vertex(p_prossimo + offset2)
st.set_color(Color(sag_prossimo, 0, 0, 1))
st.add_vertex(p_prossimo + offset1)
var nodo_filo = MeshInstance3D.new()
nodo_filo.mesh = st.commit()
if materiale_filo_palo: nodo_filo.material_override = materiale_filo_palo
genitore.add_child(nodo_filo)

View File

@@ -4,7 +4,7 @@ class_name InfoChunk
@export_enum("Bioma", "Binario_Dritto", "Binario_Curva") var tipo_chunk: int = 0
@export_group("Regole Set Piece (Pezzi Unici)")
@export var bioma_esclusivo: String = "" # Es: scrivi "Foresta"
@export var bioma_esclusivo: String = ""
@export_group("Uscite Base (Senza Rotazione)")
@export var nord: bool = false
@@ -18,15 +18,16 @@ class_name InfoChunk
@export var altezza_sud: int = 0
@export var altezza_ovest: int = 0
# --- NUOVA AGGIUNTA AUTOMATICA ---
@export_group("Palo della Luce")
@export var ha_palo_luce: bool = false
@export var attacchi_sx: Array[Node3D] # Array di Marker3D per i fili sinistri
@export var attacchi_dx: Array[Node3D] # Array di Marker3D per i fili destri
func _ready() -> void:
# Se hai scritto un bioma nell'Inspector, il pezzo capisce di essere
# un pezzo speciale e si aggiunge al gruppo dei fantasmi da solo!
if bioma_esclusivo != "":
add_to_group("set_pieces")
# ... qui sotto continua la tua normale funzione get_dati_ruotati() ...
func get_dati_ruotati(scatti_90_gradi: int) -> Dictionary:
var uscite_originali = [nord, est, sud, ovest]
var altezze_originali = [altezza_nord, altezza_est, altezza_sud, altezza_ovest]