add cloud shadow - godrays
This commit is contained in:
@@ -221,13 +221,9 @@ func _gestione_movimento_treno(delta: float) -> void:
|
||||
treno_istanziato.rotate_y(PI)
|
||||
|
||||
if gruppo_camere:
|
||||
gruppo_camere.global_position = gruppo_camere.global_position.lerp(pos_centro, delta * 12.0)
|
||||
|
||||
# Usiamo orthonormalized() per pulire le micro-imperfezioni matematiche
|
||||
var rot_cam = gruppo_camere.global_basis.orthonormalized().get_rotation_quaternion()
|
||||
var rot_treno = treno_istanziato.global_basis.orthonormalized().get_rotation_quaternion()
|
||||
|
||||
gruppo_camere.global_basis = Basis(rot_cam.slerp(rot_treno, delta * 8.0))
|
||||
# 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)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
extends Node3D
|
||||
|
||||
|
||||
|
||||
@export_group("Luce Direzionale e Ambiente")
|
||||
@export var color_mattina: Color = Color(1.0, 0.9, 0.8, 1.0)
|
||||
@export var color_pomeriggio: Color = Color(1.0, 0.6, 0.2, 1.0)
|
||||
@@ -21,8 +23,11 @@ extends Node3D
|
||||
@export_range(0.0, 1.0) var energia_luce_notte: float = 0.3
|
||||
|
||||
@export_group("Materiali Extra")
|
||||
|
||||
@export var materiale_nebbia: ShaderMaterial
|
||||
@export var materiale_pioggia_gocce: StandardMaterial3D
|
||||
# --- NUOVA VARIABILE PER LE NUVOLE ---
|
||||
@export var materiale_nuvole: ShaderMaterial
|
||||
|
||||
@export_group("Meteo (Pioggia & Fulmini)")
|
||||
@export var colore_mood_pioggia: Color = Color(0.5, 0.6, 0.7, 1.0)
|
||||
@@ -46,7 +51,7 @@ extends Node3D
|
||||
|
||||
# --- NODI FULMINE ---
|
||||
@onready var luce_lampo: DirectionalLight3D = $LuceLampo
|
||||
@onready var sprite_fulmine: Sprite3D = $SpriteFulmine
|
||||
@onready var sprite_fulmine: Sprite3D = $SubViewportContainer/SubViewport/World/Camere/SpriteFulmine
|
||||
|
||||
var tween_giorno: Tween
|
||||
var is_raining: bool = false
|
||||
@@ -107,6 +112,10 @@ func _on_giornata_selezionata(index: int) -> void:
|
||||
tween_giorno = create_tween()
|
||||
tween_giorno.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
||||
tween_giorno.tween_property(self, "tempo_giorno", target_tempo, durata_transizione)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func _on_pioggia_toggled(toggled_on: bool) -> void:
|
||||
# Se l'utente clicca il bottone della pioggia a mano, spegni la cinematic mode
|
||||
@@ -117,6 +126,9 @@ func _on_pioggia_toggled(toggled_on: bool) -> void:
|
||||
is_raining = toggled_on
|
||||
if particelle_pioggia:
|
||||
particelle_pioggia.emitting = is_raining
|
||||
|
||||
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
# --- LOGICA EVENTI CASUALI CINEMATIC MODE ---
|
||||
@@ -124,7 +136,6 @@ func _process(delta: float) -> void:
|
||||
timer_cinematic_env -= delta
|
||||
if timer_cinematic_env <= 0.0:
|
||||
_genera_evento_meteo_casuale()
|
||||
# Reset timer con un po' di casualità per non renderlo troppo robotico
|
||||
timer_cinematic_env = randf_range(intervallo_eventi_meteo * 0.8, intervallo_eventi_meteo * 1.5)
|
||||
|
||||
# --- LOGICA NORMALE AMBIENTE ---
|
||||
@@ -141,6 +152,14 @@ func _process(delta: float) -> void:
|
||||
_resetta_timer_fulmine()
|
||||
else:
|
||||
intensita_pioggia = move_toward(intensita_pioggia, 0.0, delta * 0.5)
|
||||
|
||||
# --- LOGICA NUVOLE: SI ADDENSANO CON LA PIOGGIA ---
|
||||
if materiale_nuvole:
|
||||
# lerp fa una transizione fluida tra 0.4 (limpido) e 1.0 (coperto) in base all'intensità della pioggia
|
||||
var densita_attuale = lerp(0.4, 1.0, intensita_pioggia)
|
||||
materiale_nuvole.set_shader_parameter("cloud_density", densita_attuale)
|
||||
var sharpness_attuale = lerp(0.14, 0.0, intensita_pioggia)
|
||||
materiale_nuvole.set_shader_parameter("center_sharpness", sharpness_attuale)
|
||||
|
||||
if tempo_giorno <= 2.0:
|
||||
var t = tempo_giorno - 1.0
|
||||
@@ -187,39 +206,36 @@ func _process(delta: float) -> void:
|
||||
|
||||
# --- FUNZIONE GENERATORE CASUALE ---
|
||||
func _genera_evento_meteo_casuale() -> void:
|
||||
sto_cambiando_in_cinematic = true # Avvisiamo il codice che stiamo facendo modifiche "automatiche"
|
||||
sto_cambiando_in_cinematic = true
|
||||
|
||||
var scelta = randi() % 3
|
||||
|
||||
if scelta == 0:
|
||||
# Cambia orario
|
||||
var nuovo_orario = randi() % 3
|
||||
if menu_giornata:
|
||||
menu_giornata.selected = nuovo_orario
|
||||
_on_giornata_selezionata(nuovo_orario)
|
||||
|
||||
elif scelta == 1:
|
||||
# Cambia meteo (accende o spegne la pioggia)
|
||||
var piove = randf() > 0.5
|
||||
if bottone_pioggia:
|
||||
bottone_pioggia.set_pressed_no_signal(piove)
|
||||
_on_pioggia_toggled(piove)
|
||||
|
||||
elif scelta == 2:
|
||||
# Forza un fulmine (se non piove, fa iniziare a piovere per dare senso al fulmine!)
|
||||
if not is_raining:
|
||||
if bottone_pioggia:
|
||||
bottone_pioggia.set_pressed_no_signal(true)
|
||||
_on_pioggia_toggled(true)
|
||||
_scatena_fulmine()
|
||||
|
||||
sto_cambiando_in_cinematic = false # Fine modifiche automatiche
|
||||
sto_cambiando_in_cinematic = false
|
||||
|
||||
# --- FUNZIONI FULMINI ---
|
||||
|
||||
func _resetta_timer_fulmine() -> void:
|
||||
timer_prossimo_fulmine = randf_range(tempo_min_fulmine, tempo_max_fulmine)
|
||||
|
||||
# --- FUNZIONI FULMINI ---
|
||||
func _scatena_fulmine() -> void:
|
||||
if luce_lampo:
|
||||
var tween_luce = create_tween()
|
||||
@@ -235,9 +251,13 @@ func _scatena_fulmine() -> void:
|
||||
|
||||
for i in numero_scariche:
|
||||
if sprite_fulmine:
|
||||
var angolo_casuale = randf() * PI * 2.0
|
||||
var distanza = 20.0
|
||||
sprite_fulmine.position = Vector3(cos(angolo_casuale) * distanza, 20.0, sin(angolo_casuale) * distanza)
|
||||
var angolo_casuale = randf() * TAU
|
||||
var distanza = randf_range(10.0, 40.0)
|
||||
|
||||
# Ho abbassato la Y da 20.0 a 10.0. Se non lo vedi ancora, abbassala a 5.0!
|
||||
sprite_fulmine.position = Vector3(cos(angolo_casuale) * distanza, 10.0, sin(angolo_casuale) * distanza)
|
||||
|
||||
# VIA LA RIGA LOOK_AT! Ci pensa il Billboard dell'Inspector ora.
|
||||
|
||||
sprite_fulmine.modulate = colore_fulmine
|
||||
sprite_fulmine.modulate.a = 1.0
|
||||
@@ -246,8 +266,11 @@ func _scatena_fulmine() -> void:
|
||||
sprite_fulmine.scale = Vector3(s, s, s)
|
||||
|
||||
var tween_sprite = create_tween()
|
||||
tween_sprite.tween_interval(0.1)
|
||||
tween_sprite.tween_property(sprite_fulmine, "modulate:a", 0.0, 0.2)
|
||||
# Ora rimane visibile al 100% per 0.2 secondi (il doppio)
|
||||
tween_sprite.tween_interval(0.2)
|
||||
# Ora ci mette 0.4 secondi a svanire dolcemente (il doppio)
|
||||
tween_sprite.tween_property(sprite_fulmine, "modulate:a", 0.0, 0.4)
|
||||
|
||||
if numero_scariche > 1:
|
||||
await get_tree().create_timer(randf_range(0.05, 0.15)).timeout
|
||||
# --- FUNZIONI GOD RAYS ---
|
||||
|
||||
251
Scripts/generatore_bioma.gd
Normal file
251
Scripts/generatore_bioma.gd
Normal file
@@ -0,0 +1,251 @@
|
||||
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"
|
||||
1
Scripts/generatore_bioma.gd.uid
Normal file
1
Scripts/generatore_bioma.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c5xr1w2tvcxl1
|
||||
132
Scripts/generatore_mappa.gd
Normal file
132
Scripts/generatore_mappa.gd
Normal file
@@ -0,0 +1,132 @@
|
||||
extends Node3D
|
||||
|
||||
signal mappa_pronta
|
||||
|
||||
@export_group("Impostazioni Mappa")
|
||||
@export var dimensione_chunk: float = 10.0
|
||||
@export var lunghezza_percorso: int = 15
|
||||
@export var larghezza_bioma: int = 5
|
||||
@export var OFFSET_ROTATION: float = 0.0 # Regola qui se i pezzi nascono storti
|
||||
|
||||
@export_group("Cataloghi")
|
||||
@export var scena_dritto: PackedScene
|
||||
@export var scena_curva: PackedScene
|
||||
@export var catalogo_bioma: Array[PackedScene]
|
||||
|
||||
@export var path_treno: Path3D
|
||||
|
||||
var mappa_virtuale: Dictionary = {}
|
||||
|
||||
func _ready() -> void:
|
||||
mappa_virtuale.clear()
|
||||
if path_treno and path_treno.curve:
|
||||
path_treno.curve.clear_points()
|
||||
|
||||
if scena_dritto and scena_curva:
|
||||
_genera_tutto()
|
||||
else:
|
||||
print("MANCANO GLI ASSET NELL'INSPECTOR!")
|
||||
|
||||
func _genera_tutto() -> void:
|
||||
_genera_binari()
|
||||
_genera_bioma()
|
||||
emit_signal("mappa_pronta")
|
||||
|
||||
# --- FASE 1: I BINARI (Logica 3x3) ---
|
||||
func _genera_binari() -> void:
|
||||
var pos_corrente = Vector2i(0, 0)
|
||||
var dir_corrente = Vector2i(0, -1) # Inizia verso Nord
|
||||
|
||||
for i in range(lunghezza_percorso):
|
||||
var tipo = "dritto"
|
||||
if i > 2: tipo = "curva" if randf() > 0.6 else "dritto"
|
||||
|
||||
if tipo == "dritto":
|
||||
_piazza_dritto(pos_corrente, dir_corrente)
|
||||
pos_corrente += dir_corrente
|
||||
else:
|
||||
var verso_destra = randf() > 0.5
|
||||
var nuova_dir = Vector2i(-dir_corrente.y, dir_corrente.x) if verso_destra else Vector2i(dir_corrente.y, -dir_corrente.x)
|
||||
|
||||
# In un 3x3, la curva occupa:
|
||||
# 1. Cella ingresso (dove siamo)
|
||||
# 2. Cella centrale (pivot)
|
||||
# 3. Cella uscita
|
||||
var cella_ingresso = pos_corrente
|
||||
var cella_centro = pos_corrente + dir_corrente
|
||||
var cella_uscita = cella_centro + nuova_dir
|
||||
|
||||
_piazza_curva(cella_centro, dir_corrente, verso_destra)
|
||||
|
||||
# Occupiamo le celle nella mappa per il bioma
|
||||
mappa_virtuale[cella_ingresso] = "binario"
|
||||
mappa_virtuale[cella_centro] = "binario"
|
||||
mappa_virtuale[cella_uscita] = "binario"
|
||||
# Occupiamo anche l'angolo interno della L per sicurezza
|
||||
mappa_virtuale[cella_ingresso + nuova_dir] = "binario"
|
||||
|
||||
# Il prossimo pezzo parte dopo l'uscita
|
||||
pos_corrente = cella_uscita + nuova_dir
|
||||
dir_corrente = nuova_dir
|
||||
|
||||
func _piazza_dritto(pos: Vector2i, dir: Vector2i) -> void:
|
||||
var d = scena_dritto.instantiate()
|
||||
add_child(d)
|
||||
d.position = Vector3(pos.x * dimensione_chunk, 0, pos.y * dimensione_chunk)
|
||||
d.rotation.y = _get_angolo_da_dir(dir)
|
||||
mappa_virtuale[pos] = "binario"
|
||||
_aggiungi_punti_path(d)
|
||||
|
||||
func _piazza_curva(pos_centro: Vector2i, dir_ingresso: Vector2i, destra: bool) -> void:
|
||||
var c = scena_curva.instantiate()
|
||||
add_child(c)
|
||||
# Il pivot è al centro della 3x3, quindi lo piazziamo sulla cella centrale
|
||||
c.position = Vector3(pos_centro.x * dimensione_chunk, 0, pos_centro.y * dimensione_chunk)
|
||||
|
||||
# Rotazione basata sulla direzione da cui entriamo
|
||||
c.rotation.y = _get_angolo_da_dir(dir_ingresso)
|
||||
|
||||
if not destra:
|
||||
c.scale.x = -1 # Specchia per curva a sinistra
|
||||
# Se dopo lo specchio la curva guarda indietro, decommenta la riga sotto:
|
||||
# c.rotate_y(deg_to_rad(180))
|
||||
|
||||
_aggiungi_punti_path(c)
|
||||
|
||||
func _get_angolo_da_dir(dir: Vector2i) -> float:
|
||||
var ang = 0.0
|
||||
if dir == Vector2i(0, -1): ang = 0.0 # Nord
|
||||
elif dir == Vector2i(1, 0): ang = -PI/2.0 # Est
|
||||
elif dir == Vector2i(0, 1): ang = PI # Sud
|
||||
elif dir == Vector2i(-1, 0): ang = PI/2.0 # Ovest
|
||||
return ang + deg_to_rad(OFFSET_ROTATION)
|
||||
|
||||
func _aggiungi_punti_path(chunk: Node3D) -> void:
|
||||
if not path_treno: return
|
||||
for i in range(1, 10):
|
||||
var m = chunk.find_child("Punto_" + str(i), true, false)
|
||||
if m:
|
||||
path_treno.curve.add_point(path_treno.to_local(m.global_position))
|
||||
else: break
|
||||
|
||||
# --- FASE 2: IL BIOMA (Onda BFS) ---
|
||||
func _genera_bioma() -> void:
|
||||
var coda = []
|
||||
for p in mappa_virtuale.keys(): coda.append({"p": p, "d": 0})
|
||||
|
||||
while coda.size() > 0:
|
||||
var curr = coda.pop_front()
|
||||
if curr.d >= larghezza_bioma: continue
|
||||
|
||||
for off in [Vector2i(0,1), Vector2i(0,-1), Vector2i(1,0), Vector2i(-1,0)]:
|
||||
var v = curr.p + off
|
||||
if not mappa_virtuale.has(v):
|
||||
_piazza_bioma(v)
|
||||
coda.append({"p": v, "d": curr.d + 1})
|
||||
|
||||
func _piazza_bioma(pos: Vector2i) -> void:
|
||||
var b = catalogo_bioma.pick_random().instantiate()
|
||||
add_child(b)
|
||||
b.position = Vector3(pos.x * dimensione_chunk, 0, pos.y * dimensione_chunk)
|
||||
b.rotation.y = (randi() % 4) * (PI/2)
|
||||
mappa_virtuale[pos] = "bioma"
|
||||
1
Scripts/generatore_mappa.gd.uid
Normal file
1
Scripts/generatore_mappa.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://djnl28tvtgok0
|
||||
27
Scripts/info_chunk.gd
Normal file
27
Scripts/info_chunk.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
extends Node3D
|
||||
class_name InfoChunk
|
||||
|
||||
@export_enum("Bioma", "Binario_Dritto", "Binario_Curva") var tipo_chunk: int = 0
|
||||
|
||||
@export_group("Uscite Base (Senza Rotazione)")
|
||||
# Spunta queste caselle se il chunk ha un sentiero/binario che tocca quel bordo
|
||||
@export var nord: bool = false
|
||||
@export var est: bool = false
|
||||
@export var sud: bool = false
|
||||
@export var ovest: bool = false
|
||||
|
||||
# Calcola dove finiscono le uscite se ruotiamo il blocco
|
||||
func get_uscite_ruotate(scatti_90_gradi: int) -> Dictionary:
|
||||
var uscite_originali = [nord, est, sud, ovest]
|
||||
var uscite_calcolate = []
|
||||
|
||||
for i in range(4):
|
||||
# Sposta le uscite in senso orario
|
||||
uscite_calcolate.append(uscite_originali[(i - scatti_90_gradi + 4) % 4])
|
||||
|
||||
return {
|
||||
"nord": uscite_calcolate[0],
|
||||
"est": uscite_calcolate[1],
|
||||
"sud": uscite_calcolate[2],
|
||||
"ovest": uscite_calcolate[3]
|
||||
}
|
||||
1
Scripts/info_chunk.gd.uid
Normal file
1
Scripts/info_chunk.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://byluxssk112ca
|
||||
Reference in New Issue
Block a user