Refactor Godot architecture into AppShell, modular menus and game domains
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://cja6yryyc2swh"
|
||||
path="res://.godot/imported/NotoSerifDisplay-CondensedExtraBold.ttf-e11f32cef921919fe1a1f689f5bd0dee.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://shared/assets/fonts/NotoSerifDisplay-CondensedExtraBold.ttf"
|
||||
dest_files=["res://.godot/imported/NotoSerifDisplay-CondensedExtraBold.ttf-e11f32cef921919fe1a1f689f5bd0dee.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=3
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b8b7jc0pcxwjk"
|
||||
path="res://.godot/imported/wood_board_rounded.png-35308896ac2addc0f5df2dae13ed6a0c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://shared/assets/textures/wood_board_rounded.png"
|
||||
dest_files=["res://.godot/imported/wood_board_rounded.png-35308896ac2addc0f5df2dae13ed6a0c.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@@ -0,0 +1,58 @@
|
||||
class_name AudioFactory
|
||||
extends RefCounted
|
||||
## Factory condivisa per suoni procedurali morbidi e sensory-friendly.
|
||||
|
||||
|
||||
static func create_tone(freq: float, duration: float, amp: float = 0.3) -> AudioStreamWAV:
|
||||
var sample_rate := 22050
|
||||
var num_samples := int(sample_rate * duration)
|
||||
var data := PackedByteArray()
|
||||
data.resize(num_samples)
|
||||
var attack := int(sample_rate * 0.01)
|
||||
for i in num_samples:
|
||||
var t := float(i) / sample_rate
|
||||
var env := 1.0
|
||||
if i < attack:
|
||||
env = float(i) / attack
|
||||
env *= exp(-3.0 * t / duration)
|
||||
var value := int(clampf(sin(t * freq * TAU) * env * amp * 127.0, -128.0, 127.0))
|
||||
data[i] = value & 0xff
|
||||
var stream := AudioStreamWAV.new()
|
||||
stream.format = AudioStreamWAV.FORMAT_8_BITS
|
||||
stream.mix_rate = sample_rate
|
||||
stream.data = data
|
||||
return stream
|
||||
|
||||
|
||||
static func create_arpeggio(freqs: Array[float], note_duration: float = 0.12, amp: float = 0.3) -> AudioStreamWAV:
|
||||
var sample_rate := 22050
|
||||
var samples_per_note := int(sample_rate * note_duration)
|
||||
var data := PackedByteArray()
|
||||
data.resize(samples_per_note * freqs.size())
|
||||
var index := 0
|
||||
var attack := int(sample_rate * 0.01)
|
||||
for freq in freqs:
|
||||
for i in samples_per_note:
|
||||
var t := float(i) / sample_rate
|
||||
var env := 1.0
|
||||
if i < attack:
|
||||
env = float(i) / attack
|
||||
env *= exp(-3.0 * t / note_duration)
|
||||
var value := int(clampf(sin(t * freq * TAU) * env * amp * 127.0, -128.0, 127.0))
|
||||
data[index] = value & 0xff
|
||||
index += 1
|
||||
var stream := AudioStreamWAV.new()
|
||||
stream.format = AudioStreamWAV.FORMAT_8_BITS
|
||||
stream.mix_rate = sample_rate
|
||||
stream.data = data
|
||||
return stream
|
||||
|
||||
|
||||
static func play_once(parent: Node, stream: AudioStream, volume_db: float = 0.0) -> AudioStreamPlayer:
|
||||
var player := AudioStreamPlayer.new()
|
||||
player.stream = stream
|
||||
player.volume_db = volume_db
|
||||
parent.add_child(player)
|
||||
player.finished.connect(player.queue_free)
|
||||
player.play()
|
||||
return player
|
||||
@@ -0,0 +1 @@
|
||||
uid://b8mwlvhphs2ks
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 510 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://btu7j7kp70h1p"
|
||||
path="res://.godot/imported/boot_splash.png-fdbf73098cc225d48e7dceea23cbdbf2.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://shared/branding/boot_splash.png"
|
||||
dest_files=["res://.godot/imported/boot_splash.png-fdbf73098cc225d48e7dceea23cbdbf2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ctskih3vqn5pg"
|
||||
path="res://.godot/imported/upendi_avatar.png-77772ece5e9cc1c14b5946e6ff8015ce.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://shared/branding/upendi_avatar.png"
|
||||
dest_files=["res://.godot/imported/upendi_avatar.png-77772ece5e9cc1c14b5946e6ff8015ce.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 798 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dwn12ta3hlsap"
|
||||
path="res://.godot/imported/upendi_logo.png-97057ee5f00f659c881acb6eec561519.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://shared/branding/upendi_logo.png"
|
||||
dest_files=["res://.godot/imported/upendi_logo.png-97057ee5f00f659c881acb6eec561519.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bd4rmhhbbm2a2"
|
||||
path="res://.godot/imported/upendi_logo_transparent.png-e2029c17c7caf7864f2ea5b8b99f6857.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://shared/branding/upendi_logo_transparent.png"
|
||||
dest_files=["res://.godot/imported/upendi_logo_transparent.png-e2029c17c7caf7864f2ea5b8b99f6857.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@@ -0,0 +1,80 @@
|
||||
extends Node
|
||||
## Singleton Settings: valori di calibrazione del gameplay, caricati/salvati
|
||||
## in user://settings.cfg. Modificati dal menù di configurazione e applicati
|
||||
## al riavvio della scena.
|
||||
|
||||
const PATH := "user://settings.cfg"
|
||||
const VERSION := 6 # incrementa quando cambiano i default, per resettare i file vecchi
|
||||
var version := VERSION
|
||||
|
||||
var start_time := 4.5 # tempo iniziale (s) tra un ordine e l'altro
|
||||
var min_time := 0.8 # tempo minimo (velocità massima)
|
||||
var score_ramp := 8000.0 # punteggio per difficoltà piena (velocità massima)
|
||||
var points_per_combo := 1 # punti per ogni lancio corretto (lineare, default 1)
|
||||
var target_score := 1000 # punteggio da raggiungere per la vittoria
|
||||
var max_combo := 5.0 # combo massimo di default (configurabile)
|
||||
var combo_decay_threshold := 0.0 # combo sopra cui inizia il decay (0 = da subito)
|
||||
var combo_decay_rate := 0.15 # combo persi al secondo per unità sopra la soglia
|
||||
var difficulty_decay_rate := 0.3 # decay aggiuntivo legato alla difficoltà
|
||||
# Modalità di gioco (mutuamente esclusive): 0=Classica (a punteggio), 1=Zen, 2=Survival
|
||||
var game_mode := 0
|
||||
# Accessibilità / neurodivergenza
|
||||
var gentle_errors := true # errore: combo -1 invece di azzerare
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
load_settings()
|
||||
|
||||
|
||||
func load_settings() -> void:
|
||||
var cfg := ConfigFile.new()
|
||||
if cfg.load(PATH) != OK:
|
||||
return # usa i default
|
||||
version = cfg.get_value("meta", "version", 0)
|
||||
if version < VERSION:
|
||||
# file di impostazioni vecchio: applica i nuovi default e risalva
|
||||
reset_defaults()
|
||||
save_settings()
|
||||
return
|
||||
start_time = cfg.get_value("gameplay", "start_time", start_time)
|
||||
min_time = cfg.get_value("gameplay", "min_time", min_time)
|
||||
score_ramp = cfg.get_value("gameplay", "score_ramp", score_ramp)
|
||||
points_per_combo = cfg.get_value("gameplay", "points_per_combo", points_per_combo)
|
||||
target_score = cfg.get_value("gameplay", "target_score", target_score)
|
||||
game_mode = cfg.get_value("gameplay", "game_mode", game_mode)
|
||||
max_combo = cfg.get_value("gameplay", "max_combo", max_combo)
|
||||
combo_decay_threshold = cfg.get_value("gameplay", "combo_decay_threshold", combo_decay_threshold)
|
||||
combo_decay_rate = cfg.get_value("gameplay", "combo_decay_rate", combo_decay_rate)
|
||||
difficulty_decay_rate = cfg.get_value("gameplay", "difficulty_decay_rate", difficulty_decay_rate)
|
||||
gentle_errors = cfg.get_value("accessibility", "gentle_errors", gentle_errors)
|
||||
|
||||
|
||||
func save_settings() -> void:
|
||||
var cfg := ConfigFile.new()
|
||||
cfg.set_value("meta", "version", VERSION)
|
||||
cfg.set_value("gameplay", "start_time", start_time)
|
||||
cfg.set_value("gameplay", "min_time", min_time)
|
||||
cfg.set_value("gameplay", "score_ramp", score_ramp)
|
||||
cfg.set_value("gameplay", "points_per_combo", points_per_combo)
|
||||
cfg.set_value("gameplay", "target_score", target_score)
|
||||
cfg.set_value("gameplay", "game_mode", game_mode)
|
||||
cfg.set_value("gameplay", "max_combo", max_combo)
|
||||
cfg.set_value("gameplay", "combo_decay_threshold", combo_decay_threshold)
|
||||
cfg.set_value("gameplay", "combo_decay_rate", combo_decay_rate)
|
||||
cfg.set_value("gameplay", "difficulty_decay_rate", difficulty_decay_rate)
|
||||
cfg.set_value("accessibility", "gentle_errors", gentle_errors)
|
||||
cfg.save(PATH)
|
||||
|
||||
|
||||
func reset_defaults() -> void:
|
||||
start_time = 4.5
|
||||
min_time = 0.8
|
||||
score_ramp = 8000.0
|
||||
points_per_combo = 1
|
||||
target_score = 1000
|
||||
game_mode = 0
|
||||
max_combo = 5.0
|
||||
combo_decay_threshold = 0.0
|
||||
combo_decay_rate = 0.15
|
||||
difficulty_decay_rate = 0.3
|
||||
gentle_errors = true
|
||||
@@ -0,0 +1 @@
|
||||
uid://tvu3ae4txaud
|
||||
@@ -0,0 +1,17 @@
|
||||
class_name BrassStuds
|
||||
extends Control
|
||||
## Quattro borchie decorative agli angoli del controllo.
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var positions := [Vector2(22, 22), Vector2(size.x - 22, 22), Vector2(22, size.y - 22), Vector2(size.x - 22, size.y - 22)]
|
||||
for position in positions:
|
||||
draw_circle(position + Vector2(1.5, 2.5), 8.0, Color(0.12, 0.05, 0.02, 0.45))
|
||||
draw_circle(position, 8.0, Color("#b17b24"))
|
||||
draw_circle(position - Vector2(2, 2), 4.5, CircusTheme.BRASS_LIGHT)
|
||||
draw_line(position - Vector2(3, 0), position + Vector2(3, 0), Color("#765018"), 1.5, true)
|
||||
@@ -0,0 +1 @@
|
||||
uid://biuj6k801px5u
|
||||
@@ -0,0 +1,36 @@
|
||||
class_name CircusTheme
|
||||
extends RefCounted
|
||||
## Palette e StyleBox comuni agli overlay circensi.
|
||||
|
||||
const FONT := preload("res://shared/assets/fonts/NotoSerifDisplay-CondensedExtraBold.ttf")
|
||||
const WOOD_TEXTURE := preload("res://shared/assets/textures/wood_board_rounded.png")
|
||||
const INK := Color("#482615")
|
||||
const BRASS := Color("#d5a83f")
|
||||
const BRASS_LIGHT := Color("#f6d77a")
|
||||
|
||||
|
||||
static func flat_style(color: Color, border: Color, width: int, radius: int) -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = color
|
||||
style.border_color = border
|
||||
style.set_border_width_all(width)
|
||||
style.set_corner_radius_all(radius)
|
||||
return style
|
||||
|
||||
|
||||
static func wood_style() -> StyleBoxTexture:
|
||||
var style := StyleBoxTexture.new()
|
||||
style.texture = WOOD_TEXTURE
|
||||
style.texture_margin_left = 35.0
|
||||
style.texture_margin_right = 35.0
|
||||
style.texture_margin_top = 35.0
|
||||
style.texture_margin_bottom = 35.0
|
||||
return style
|
||||
|
||||
|
||||
static func button_style(color: Color, border: Color, width: int, radius: int = 14) -> StyleBoxFlat:
|
||||
var style := flat_style(color, border, width, radius)
|
||||
style.shadow_color = Color(0.14, 0.05, 0.02, 0.48)
|
||||
style.shadow_size = 6
|
||||
style.shadow_offset = Vector2(0, 4)
|
||||
return style
|
||||
@@ -0,0 +1 @@
|
||||
uid://cir4lpc4uim1b
|
||||
@@ -0,0 +1,22 @@
|
||||
class_name CircusTrim
|
||||
extends Control
|
||||
## Filo di bandierine decorativo riutilizzabile.
|
||||
|
||||
@export var flag_count := 11
|
||||
@export var span := 440.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var colors := [Color("#a9403e"), Color("#d5a83f"), Color("#397b76")]
|
||||
var start_x := (size.x - span) * 0.5
|
||||
draw_line(Vector2(start_x - 10, 8), Vector2(start_x + span + 10, 8), Color("#63361f"), 3.0, true)
|
||||
for index in flag_count:
|
||||
var x := start_x + index * (span / float(flag_count - 1)) - 16.0
|
||||
var points := PackedVector2Array([Vector2(x, 7), Vector2(x + 32, 7), Vector2(x + 16, 31)])
|
||||
draw_colored_polygon(points, colors[index % colors.size()])
|
||||
draw_polyline(PackedVector2Array([points[0], points[1], points[2], points[0]]), Color("#6b341c"), 1.5, true)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cinfcyv6v0h2y
|
||||
Reference in New Issue
Block a user