clean
This commit is contained in:
43
Scripts/GodrayBurst.gd
Normal file
43
Scripts/GodrayBurst.gd
Normal file
@@ -0,0 +1,43 @@
|
||||
extends MeshInstance3D
|
||||
|
||||
@export var life_time: float = 8.0 # Quanto dura l'intera animazione di movimento/intensità in secondi
|
||||
# --- NUOVI PARAMETRI PER L'APPARIZIONE MORBIDA ---
|
||||
@export var fade_in_time: float = 4.0 # Quanti secondi ci mette ad apparire dolcemente
|
||||
@export var max_base_alpha: float = 1.0 # Il valore massimo a cui arriva l'alpha (se 1.0 è troppo forte, abbassalo qui)
|
||||
|
||||
func _ready():
|
||||
# Duplichiamo il materiale per renderlo unico per questo specifico raggio
|
||||
var mat = get_active_material(0).duplicate()
|
||||
set_surface_override_material(0, mat)
|
||||
|
||||
add_to_group("camere")
|
||||
|
||||
# IMPORTANTE: Impostiamo subito l'alpha a 0 prima che il gioco faccia il primo frame,
|
||||
# così evitiamo il fastidioso "pop" visivo iniziale.
|
||||
mat.set_shader_parameter("base_alpha", 0.0)
|
||||
|
||||
# Avvia le animazioni
|
||||
animate_godray(mat)
|
||||
|
||||
func animate_godray(mat: ShaderMaterial):
|
||||
# --- 1. NUOVA ANIMAZIONE: FADE IN DEL BASE ALPHA ---
|
||||
var tween_alpha = create_tween()
|
||||
# In fade_in_time secondi (es. 2), porta base_alpha da 0.0 a max_base_alpha (es. 1.0)
|
||||
tween_alpha.tween_property(mat, "shader_parameter/base_alpha", max_base_alpha, fade_in_time).from(0.0)
|
||||
|
||||
|
||||
# --- 2. VECCHIE ANIMAZIONI: INTENSITA' E BORDI ---
|
||||
var tween_intensity = create_tween()
|
||||
# Imposta il valore iniziale a 1.0 e scende a 0.2
|
||||
tween_intensity.tween_property(mat, "shader_parameter/intensity_multiplier", 0.2, life_time * 0.3).from(1.0)
|
||||
# Sale a 0.5
|
||||
tween_intensity.tween_property(mat, "shader_parameter/intensity_multiplier", 0.5, life_time * 0.3)
|
||||
# Scende a 0.0 (che lo fa sparire dolcemente alla fine)
|
||||
tween_intensity.tween_property(mat, "shader_parameter/intensity_multiplier", 0.0, life_time * 0.4)
|
||||
|
||||
# Quando l'intensità arriva a 0 alla fine del suo ciclo vitale, elimina questo godray
|
||||
tween_intensity.tween_callback(queue_free)
|
||||
|
||||
var tween_edge = create_tween()
|
||||
tween_edge.tween_property(mat, "shader_parameter/edge_fade_power", 0.5, life_time * 0.5).from(2.0)
|
||||
tween_edge.tween_property(mat, "shader_parameter/edge_fade_power", 2.0, life_time * 0.5)
|
||||
1
Scripts/GodrayBurst.gd.uid
Normal file
1
Scripts/GodrayBurst.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://duu1t8cjm12oi
|
||||
@@ -1,47 +0,0 @@
|
||||
@tool
|
||||
extends MultiMeshInstance3D
|
||||
|
||||
@export var mesh_volume: MeshInstance3D : # Trascina qui il tuo volume low poly
|
||||
set(val):
|
||||
mesh_volume = val
|
||||
generate_leaves()
|
||||
|
||||
@export var scale_multiplier: float = 1.5 # Per rendere i piani grandi come in foto
|
||||
|
||||
func generate_leaves():
|
||||
if not mesh_volume or not mesh_volume.mesh:
|
||||
return
|
||||
|
||||
var mdt = MeshDataTool.new()
|
||||
mdt.create_from_surface(mesh_volume.mesh, 0)
|
||||
|
||||
var face_count = mdt.get_face_count()
|
||||
|
||||
# Inizializza il MultiMesh
|
||||
multimesh.instance_count = face_count
|
||||
|
||||
for i in range(face_count):
|
||||
# 1. Trova il centro della faccia
|
||||
var v1 = mdt.get_vertex(mdt.get_face_vertex(i, 0))
|
||||
var v2 = mdt.get_vertex(mdt.get_face_vertex(i, 1))
|
||||
var v3 = mdt.get_vertex(mdt.get_face_vertex(i, 2))
|
||||
var center = (v1 + v2 + v3) / 3.0
|
||||
|
||||
# 2. Ottieni la normale della faccia per orientare il piano
|
||||
var normal = mdt.get_face_normal(i)
|
||||
|
||||
# 3. Crea la trasformazione
|
||||
# Usiamo 'look_at' per far sì che il piano sia parallelo alla faccia
|
||||
var pos = center
|
||||
var target = pos + normal
|
||||
var xform = Transform3D().looking_at(normal, Vector3.UP)
|
||||
|
||||
# Applichiamo posizione e scala
|
||||
xform.origin = pos
|
||||
xform = xform.scaled(Vector3.ONE * scale_multiplier)
|
||||
|
||||
# 4. Applica al MultiMesh
|
||||
multimesh.set_instance_transform(i, xform)
|
||||
|
||||
# Opzionale: nascondi il volume originale se vuoi vedere solo i piani
|
||||
# mesh_volume.visible = false
|
||||
@@ -1 +0,0 @@
|
||||
uid://dxgc5kjl1048
|
||||
@@ -1,121 +0,0 @@
|
||||
extends Path3D
|
||||
|
||||
@export_group("Impostazioni Treno")
|
||||
@export var velocita_treno: float = 6.0
|
||||
@export var in_movimento: bool = true
|
||||
|
||||
@export_group("Costruzione Rotaie")
|
||||
@export var distanza_traversine: float = 1.0 # Ogni quanti metri mettere un asse di legno
|
||||
|
||||
var nodo_treno: PathFollow3D
|
||||
|
||||
func _ready() -> void:
|
||||
# Controlla se hai disegnato il percorso
|
||||
if curve == null or curve.get_baked_length() == 0:
|
||||
print("ATTENZIONE: Devi prima disegnare i punti del Path3D!")
|
||||
return
|
||||
|
||||
_costruisci_rotaie_da_zero()
|
||||
_costruisci_treno_da_zero()
|
||||
|
||||
func _costruisci_rotaie_da_zero() -> void:
|
||||
# 1. Creiamo i materiali (Colori) per le rotaie
|
||||
var mat_legno = StandardMaterial3D.new()
|
||||
mat_legno.albedo_color = Color(0.35, 0.2, 0.1) # Marrone scuro
|
||||
|
||||
var mat_ferro = StandardMaterial3D.new()
|
||||
mat_ferro.albedo_color = Color(0.6, 0.6, 0.65) # Grigio metallico
|
||||
mat_ferro.metallic = 0.8
|
||||
|
||||
# 2. Creiamo le forme geometriche base (Box)
|
||||
var mesh_traversina = BoxMesh.new()
|
||||
mesh_traversina.size = Vector3(1.8, 0.1, 0.3)
|
||||
|
||||
var mesh_binario = BoxMesh.new()
|
||||
# La lunghezza del binario è uguale alla distanza tra le traversine per connettersi perfettamente
|
||||
mesh_binario.size = Vector3(0.1, 0.15, distanza_traversine + 0.05)
|
||||
|
||||
# 3. Calcoliamo quanti pezzi servono
|
||||
var lunghezza_totale = curve.get_baked_length()
|
||||
var numero_pezzi = int(lunghezza_totale / distanza_traversine)
|
||||
|
||||
# 4. Piazziamo i pezzi lungo la curva
|
||||
for i in range(numero_pezzi):
|
||||
var distanza = i * distanza_traversine
|
||||
var transform_punto = curve.sample_baked_with_rotation(distanza, true, true)
|
||||
|
||||
# Nodo "Pezzo" che fa da raggruppamento
|
||||
var pezzo_binario = Node3D.new()
|
||||
pezzo_binario.transform = transform_punto
|
||||
add_child(pezzo_binario)
|
||||
|
||||
# Creiamo la traversina in legno
|
||||
var traversina = MeshInstance3D.new()
|
||||
traversina.mesh = mesh_traversina
|
||||
traversina.material_override = mat_legno
|
||||
pezzo_binario.add_child(traversina)
|
||||
|
||||
# Creiamo il binario sinistro
|
||||
var binario_sx = MeshInstance3D.new()
|
||||
binario_sx.mesh = mesh_binario
|
||||
binario_sx.material_override = mat_ferro
|
||||
binario_sx.position = Vector3(-0.6, 0.1, 0) # Spostato a sinistra e leggermente in alto
|
||||
pezzo_binario.add_child(binario_sx)
|
||||
|
||||
# Creiamo il binario destro
|
||||
var binario_dx = MeshInstance3D.new()
|
||||
binario_dx.mesh = mesh_binario
|
||||
binario_dx.material_override = mat_ferro
|
||||
binario_dx.position = Vector3(0.6, 0.1, 0) # Spostato a destra e leggermente in alto
|
||||
pezzo_binario.add_child(binario_dx)
|
||||
|
||||
|
||||
func _costruisci_treno_da_zero() -> void:
|
||||
# 1. Creiamo il PathFollow che gestisce il movimento
|
||||
nodo_treno = PathFollow3D.new()
|
||||
nodo_treno.rotation_mode = PathFollow3D.ROTATION_Y # IMPORTANTE: Evita che il treno si inclini di lato
|
||||
nodo_treno.cubic_interp = false # Rende la velocità costante ed elimina i tremolii
|
||||
nodo_treno.loop = true
|
||||
add_child(nodo_treno)
|
||||
|
||||
# 2. Materiali del treno
|
||||
var mat_carrozzeria = StandardMaterial3D.new()
|
||||
mat_carrozzeria.albedo_color = Color(0.8, 0.15, 0.15) # Rosso acceso
|
||||
|
||||
var mat_vetro = StandardMaterial3D.new()
|
||||
mat_vetro.albedo_color = Color(0.2, 0.8, 1.0) # Azzurro
|
||||
|
||||
# 3. Costruiamo la Base del treno
|
||||
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) # Alzato per stare sopra le rotaie
|
||||
nodo_treno.add_child(base_treno)
|
||||
|
||||
# 4. Costruiamo la Cabina del macchinista
|
||||
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) # Messa dietro e in alto
|
||||
nodo_treno.add_child(cabina)
|
||||
|
||||
# 5. Costruiamo la Ciminiera (davanti)
|
||||
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)
|
||||
nodo_treno.add_child(ciminiera)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
# Se in movimento, fa avanzare automaticamente il nodo_treno lungo la curva
|
||||
if in_movimento and nodo_treno:
|
||||
nodo_treno.progress += velocita_treno * delta
|
||||
@@ -1 +0,0 @@
|
||||
uid://c2ec8k6lbx5cb
|
||||
@@ -1,8 +0,0 @@
|
||||
extends GPUParticles3D
|
||||
|
||||
func _ready() -> void:
|
||||
# Quando spawna, emette le particelle
|
||||
emitting = true
|
||||
# Si autodistrugge dopo che le particelle sono svanite
|
||||
await get_tree().create_timer(lifetime + 0.5).timeout
|
||||
queue_free()
|
||||
@@ -1 +0,0 @@
|
||||
uid://c1wwiocqnv0qs
|
||||
@@ -1,132 +0,0 @@
|
||||
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 +0,0 @@
|
||||
uid://djnl28tvtgok0
|
||||
@@ -1,10 +0,0 @@
|
||||
extends PathFollow3D
|
||||
|
||||
@export var velocita_treno: float = 5.0
|
||||
@export var in_movimento: bool = true
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if in_movimento:
|
||||
# 'progress' è una variabile nativa di PathFollow3D
|
||||
# Aumentandola, il nodo si sposta lungo la curva in automatico!
|
||||
progress += velocita_treno * delta
|
||||
@@ -1 +0,0 @@
|
||||
uid://bvn3yskdmvcuj
|
||||
@@ -1,62 +0,0 @@
|
||||
@tool
|
||||
extends MultiMeshInstance3D
|
||||
|
||||
# Trascina qui la MeshInstance3D che rappresenta il volume della tua chioma
|
||||
@export var mesh_volume: MeshInstance3D
|
||||
|
||||
# Clicca su questa casella nell'Inspector per generare le foglie
|
||||
@export var genera_foglie: bool = false:
|
||||
set(val):
|
||||
if val:
|
||||
popola_chioma()
|
||||
genera_foglie = false # Resetta il pulsante
|
||||
|
||||
# Scala delle singole foglie
|
||||
@export var scala_foglie: Vector3 = Vector3(1, 1, 1)
|
||||
|
||||
func popola_chioma():
|
||||
if not mesh_volume or not mesh_volume.mesh:
|
||||
print("Errore: Assegna una MeshInstance3D valida a 'Mesh Volume'.")
|
||||
return
|
||||
|
||||
if not multimesh:
|
||||
print("Errore: Il nodo MultiMeshInstance3D non ha una risorsa MultiMesh assegnata.")
|
||||
return
|
||||
|
||||
# Assicurati che il formato sia 3D per posizioni, rotazioni e scale
|
||||
multimesh.transform_format = MultiMesh.TRANSFORM_3D
|
||||
|
||||
var mdt = MeshDataTool.new()
|
||||
# Crea i dati dalla prima superficie della mesh (indice 0)
|
||||
mdt.create_from_surface(mesh_volume.mesh, 0)
|
||||
|
||||
var numero_facce = mdt.get_face_count()
|
||||
multimesh.instance_count = numero_facce
|
||||
|
||||
print("Generazione di ", numero_facce, " foglie...")
|
||||
|
||||
for i in range(numero_facce):
|
||||
# Ottieni i tre vertici che formano la faccia
|
||||
var v1 = mdt.get_vertex(mdt.get_face_vertex(i, 0))
|
||||
var v2 = mdt.get_vertex(mdt.get_face_vertex(i, 1))
|
||||
var v3 = mdt.get_vertex(mdt.get_face_vertex(i, 2))
|
||||
|
||||
# Calcola il centro della faccia
|
||||
var centro_faccia = (v1 + v2 + v3) / 3.0
|
||||
|
||||
# Crea una trasformazione con posizione, rotazione casuale e scala
|
||||
var transform = Transform3D()
|
||||
transform.origin = centro_faccia
|
||||
|
||||
# Rotazione casuale per un look naturale
|
||||
transform = transform.rotated(Vector3.UP, randf() * TAU) # Rotazione attorno all'asse Y
|
||||
transform = transform.rotated(Vector3.RIGHT, randf() * TAU) # Rotazione attorno all'asse X
|
||||
transform = transform.rotated(Vector3.FORWARD, randf() * TAU) # Rotazione attorno all'asse Z
|
||||
|
||||
# Applica la scala
|
||||
transform = transform.scaled(scala_foglie)
|
||||
|
||||
# Imposta la trasformazione per questa istanza nel MultiMesh
|
||||
multimesh.set_instance_transform(i, transform)
|
||||
|
||||
print("Foglie generate con successo!")
|
||||
@@ -1 +0,0 @@
|
||||
uid://bj181l5u1b81x
|
||||
Reference in New Issue
Block a user