252 lines
9.8 KiB
GDScript
252 lines
9.8 KiB
GDScript
extends Node3D
|
|
|
|
@export_group("Riferimenti Base")
|
|
@export var path_treno: Path3D
|
|
|
|
@export_group("I 3 Biomi Principali")
|
|
@export var bioma_campagna: Array[PackedScene]
|
|
@export var bioma_foresta: Array[PackedScene]
|
|
@export var bioma_altro: Array[PackedScene]
|
|
|
|
@export_group("Impostazioni Griglia e Aree")
|
|
@export var dimensione_chunk: float = 20.0
|
|
@export var raggio_visivo: int = 3
|
|
@export var scala_distretti: float = 0.05
|
|
|
|
var scacchiera: Dictionary = {}
|
|
var ultima_pos_griglia_treno: Vector2i = Vector2i(999999, 999999)
|
|
var generatore_rumore: FastNoiseLite
|
|
|
|
var usa_terzo_bioma: bool = true
|
|
|
|
# --- VARIABILI PER L'INTERFACCIA A SCHERMO ---
|
|
var lbl_bioma: Label
|
|
var lbl_distanza: Label
|
|
|
|
func _ready() -> void:
|
|
if bioma_campagna.is_empty() or path_treno == null:
|
|
print("❌ ERRORE: Assegna almeno il 'Bioma Campagna' e il 'Path Treno' nell'Inspector!")
|
|
return
|
|
|
|
generatore_rumore = FastNoiseLite.new()
|
|
generatore_rumore.noise_type = FastNoiseLite.TYPE_PERLIN
|
|
generatore_rumore.seed = randi()
|
|
generatore_rumore.frequency = scala_distretti
|
|
|
|
# Creiamo l'interfaccia a schermo!
|
|
_crea_ui_gps()
|
|
|
|
print("✅ Generatore a Distretti Dinamici Pronto.")
|
|
print("Premere il tasto 'B' per abilitare/disabilitare il terzo bioma.")
|
|
|
|
# --- NUOVA FUNZIONE: CREA LE SCRITTE A SCHERMO ---
|
|
# --- NUOVA FUNZIONE: CREA LE SCRITTE A SCHERMO (CORRETTA) ---
|
|
# --- NUOVA FUNZIONE: CREA LE SCRITTE A SCHERMO ---
|
|
func _crea_ui_gps() -> void:
|
|
var canvas = CanvasLayer.new()
|
|
canvas.layer = 10
|
|
add_child(canvas)
|
|
|
|
var margin = MarginContainer.new()
|
|
margin.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
margin.add_theme_constant_override("margin_top", 20)
|
|
margin.add_theme_constant_override("margin_right", 20)
|
|
canvas.add_child(margin)
|
|
|
|
var vbox = VBoxContainer.new()
|
|
vbox.size_flags_horizontal = Control.SIZE_SHRINK_END
|
|
margin.add_child(vbox)
|
|
|
|
# --- SCRITTA BIOMA ATTUALE (Titolo) ---
|
|
lbl_bioma = Label.new()
|
|
lbl_bioma.add_theme_font_size_override("font_size", 10) # <--- QUI CAMBI LA GRANDEZZA (Prima era 26)
|
|
lbl_bioma.add_theme_color_override("font_color", Color(1, 0.9, 0.4))
|
|
lbl_bioma.add_theme_color_override("font_outline_color", Color.BLACK)
|
|
lbl_bioma.add_theme_constant_override("outline_size", 3) # Ho ridotto anche il bordo nero per non impastare il testo piccolo
|
|
lbl_bioma.text = "📍 Avvio GPS..."
|
|
vbox.add_child(lbl_bioma)
|
|
|
|
# --- SCRITTA METRI MANCANTI (Sottotitolo) ---
|
|
lbl_distanza = Label.new()
|
|
lbl_distanza.add_theme_font_size_override("font_size", 8) # <--- QUI CAMBI LA GRANDEZZA (Prima era 20)
|
|
lbl_distanza.add_theme_color_override("font_outline_color", Color.BLACK)
|
|
lbl_distanza.add_theme_constant_override("outline_size", 3) # Bordo ridotto proporzionalmente
|
|
lbl_distanza.text = "Calcolo tragitto..."
|
|
vbox.add_child(lbl_distanza)
|
|
|
|
_radar_bioma_treno()
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event is InputEventKey and event.pressed and not event.echo:
|
|
if event.keycode == KEY_B:
|
|
usa_terzo_bioma = !usa_terzo_bioma
|
|
# E forziamo un aggiornamento del radar per aggiornare le scritte subito
|
|
_radar_bioma_treno()
|
|
|
|
func _physics_process(_delta: float) -> void:
|
|
if path_treno == null or path_treno.treno_istanziato == null: 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)
|
|
var pos_attuale = Vector2i(grid_x, grid_z)
|
|
|
|
if pos_attuale != ultima_pos_griglia_treno:
|
|
ultima_pos_griglia_treno = pos_attuale
|
|
_genera_attorno_al_treno(pos_attuale)
|
|
|
|
# Il treno ha fatto 20 metri (ha cambiato cella), quindi aggiorniamo il GPS a schermo!
|
|
_radar_bioma_treno()
|
|
|
|
func _genera_attorno_al_treno(centro: Vector2i) -> void:
|
|
for x in range(-raggio_visivo, raggio_visivo + 1):
|
|
for z in range(-raggio_visivo, raggio_visivo + 1):
|
|
var pos_griglia = centro + Vector2i(x, z)
|
|
|
|
if not scacchiera.has(pos_griglia):
|
|
var ce_ostacolo = _registra_cella_con_laser(pos_griglia)
|
|
if not ce_ostacolo:
|
|
_piazza_bioma_compatibile(pos_griglia)
|
|
|
|
func _scegli_catalogo_per_cella(pos_griglia: Vector2i) -> Array[PackedScene]:
|
|
var valore = generatore_rumore.get_noise_2d(pos_griglia.x, pos_griglia.y)
|
|
var nome_bioma_scelto = _get_nome_bioma(valore)
|
|
|
|
var catalogo_scelto: Array[PackedScene] = []
|
|
|
|
if nome_bioma_scelto == "Campagna": catalogo_scelto = bioma_campagna
|
|
elif nome_bioma_scelto == "Campagna-Foresta": catalogo_scelto = bioma_campagna if randf() > 0.5 else bioma_foresta
|
|
elif nome_bioma_scelto == "Foresta": catalogo_scelto = bioma_foresta
|
|
elif nome_bioma_scelto == "Foresta-Altro": catalogo_scelto = bioma_foresta if randf() > 0.5 else bioma_altro
|
|
else: catalogo_scelto = bioma_altro
|
|
|
|
if catalogo_scelto.is_empty():
|
|
catalogo_scelto = bioma_campagna
|
|
|
|
return catalogo_scelto
|
|
|
|
func _registra_cella_con_laser(pos_griglia: Vector2i) -> bool:
|
|
if scacchiera.has(pos_griglia): return true
|
|
|
|
var pos_mondo = Vector3(pos_griglia.x * dimensione_chunk, 0, pos_griglia.y * dimensione_chunk)
|
|
var space_state = get_world_3d().direct_space_state
|
|
var origine_raggio = Vector3(pos_mondo.x, 50.0, pos_mondo.z)
|
|
var fine_raggio = Vector3(pos_mondo.x, -10.0, pos_mondo.z)
|
|
|
|
var query = PhysicsRayQueryParameters3D.create(origine_raggio, fine_raggio)
|
|
var result = space_state.intersect_ray(query)
|
|
|
|
if result.size() > 0:
|
|
var collider = result["collider"]
|
|
var nodo_corrente = collider
|
|
var uscite_trovate = {"nord": false, "est": false, "sud": false, "ovest": false}
|
|
|
|
while nodo_corrente != null and nodo_corrente != get_tree().root:
|
|
if nodo_corrente.has_method("get_uscite_ruotate"):
|
|
var scatti_rotazione = roundi(rad_to_deg(nodo_corrente.global_rotation.y) / -90.0)
|
|
uscite_trovate = nodo_corrente.get_uscite_ruotate(scatti_rotazione)
|
|
break
|
|
nodo_corrente = nodo_corrente.get_parent()
|
|
|
|
scacchiera[pos_griglia] = {"tipo": "ostacolo", "uscite": uscite_trovate}
|
|
return true
|
|
|
|
return false
|
|
|
|
func _piazza_bioma_compatibile(pos_griglia: Vector2i) -> void:
|
|
var req_nord = _richiede_connessione(pos_griglia + Vector2i(0, -1), "sud")
|
|
var req_est = _richiede_connessione(pos_griglia + Vector2i(1, 0), "ovest")
|
|
var req_sud = _richiede_connessione(pos_griglia + Vector2i(0, 1), "nord")
|
|
var req_ovest = _richiede_connessione(pos_griglia + Vector2i(-1, 0), "est")
|
|
|
|
var catalogo_zona = _scegli_catalogo_per_cella(pos_griglia)
|
|
var candidati = []
|
|
|
|
for scena in catalogo_zona:
|
|
var test_chunk = scena.instantiate()
|
|
|
|
if test_chunk.has_method("get_uscite_ruotate"):
|
|
for rot in range(4):
|
|
var u = test_chunk.get_uscite_ruotate(rot)
|
|
|
|
var match_n = (req_nord == -1) or ((req_nord == 1) == u["nord"])
|
|
var match_e = (req_est == -1) or ((req_est == 1) == u["est"])
|
|
var match_s = (req_sud == -1) or ((req_sud == 1) == u["sud"])
|
|
var match_o = (req_ovest == -1) or ((req_ovest == 1) == u["ovest"])
|
|
|
|
if match_n and match_e and match_s and match_o:
|
|
candidati.append({"scena": scena, "rotazione": rot, "uscite": u})
|
|
|
|
test_chunk.queue_free()
|
|
|
|
if candidati.size() > 0:
|
|
var scelto = candidati.pick_random()
|
|
var nuovo_chunk = scelto.scena.instantiate()
|
|
add_child(nuovo_chunk)
|
|
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.uscite}
|
|
else:
|
|
var backup = catalogo_zona[0].instantiate()
|
|
add_child(backup)
|
|
backup.position = Vector3(pos_griglia.x * dimensione_chunk, 0, pos_griglia.y * dimensione_chunk)
|
|
scacchiera[pos_griglia] = {"tipo": "bioma", "uscite": {"nord":false, "est":false, "sud":false, "ovest":false}}
|
|
|
|
func _richiede_connessione(pos_vicino: Vector2i, lato_richiesto: String) -> int:
|
|
if not scacchiera.has(pos_vicino): _registra_cella_con_laser(pos_vicino)
|
|
if scacchiera.has(pos_vicino):
|
|
return 1 if scacchiera[pos_vicino]["uscite"][lato_richiesto] else 0
|
|
return -1
|
|
|
|
func _get_nome_bioma(valore: float) -> String:
|
|
if valore < -0.4: return "Campagna"
|
|
elif valore < -0.15: return "Campagna-Foresta"
|
|
|
|
if not usa_terzo_bioma: return "Foresta"
|
|
|
|
if valore < 0.15: return "Foresta"
|
|
elif valore < 0.4: return "Foresta-Altro"
|
|
else: return "Altro (Deserto/Neve)"
|
|
|
|
# --- AGGIORNAMENTO GPS A SCHERMO ---
|
|
# --- AGGIORNAMENTO GPS A SCHERMO ---
|
|
func _radar_bioma_treno() -> void:
|
|
# SICUREZZA: Controlliamo che il treno esista davvero prima di leggerne la posizione!
|
|
if path_treno == null or path_treno.curve == null or path_treno.treno_istanziato == null:
|
|
return
|
|
|
|
var pos_treno = path_treno.treno_istanziato.global_position
|
|
var grid_x = roundi(pos_treno.x / dimensione_chunk)
|
|
# ... il resto del codice rimane identico ...
|
|
var grid_z = roundi(pos_treno.z / dimensione_chunk)
|
|
var valore_attuale = generatore_rumore.get_noise_2d(grid_x, grid_z)
|
|
var bioma_attuale = _get_nome_bioma(valore_attuale)
|
|
|
|
var progresso_attuale = path_treno.progresso_treno
|
|
var lunghezza_totale = path_treno.curve.get_baked_length()
|
|
var distanza_cambio = 0.0
|
|
var prossimo_bioma = ""
|
|
|
|
for step in range(1, 31):
|
|
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 valore_futuro = generatore_rumore.get_noise_2d(f_x, f_z)
|
|
var bioma_futuro = _get_nome_bioma(valore_futuro)
|
|
|
|
if bioma_futuro != bioma_attuale:
|
|
distanza_cambio = step * dimensione_chunk
|
|
prossimo_bioma = bioma_futuro
|
|
break
|
|
|
|
# MODIFICA: Invece di usare print, aggiorniamo l'interfaccia a schermo!
|
|
if lbl_bioma and lbl_distanza:
|
|
lbl_bioma.text = bioma_attuale
|
|
if prossimo_bioma != "":
|
|
lbl_distanza.text = str(distanza_cambio) + "m ➔ " + prossimo_bioma
|
|
else:
|
|
lbl_distanza.text = "Nessun cambio nei prossimi 600m"
|