diff --git a/scripts/hearts_display.gd b/scripts/hearts_display.gd new file mode 100644 index 0000000..dc66a8e --- /dev/null +++ b/scripts/hearts_display.gd @@ -0,0 +1,64 @@ +extends Node2D +## Mostra i cuori della modalità Survival: 4 cuori, pieni o vuoti. + +const MAX_LIVES := 4 +const HEART_GAP := 44.0 +const FILLED_COLOR := Color("#e0566e") +const EMPTY_COLOR := Color("#aaa49a") +const OUTLINE_COLOR := Color("#633725") + + +var lives := MAX_LIVES + + +func _ready() -> void: + queue_redraw() + + +func set_lives(v: int) -> void: + lives = clampi(v, 0, MAX_LIVES) + queue_redraw() + + +func _draw() -> void: + for i in MAX_LIVES: + var filled := i < lives + _draw_heart(Vector2(i * HEART_GAP, 0.0), FILLED_COLOR if filled else EMPTY_COLOR, filled) + + +func _draw_heart(origin: Vector2, color: Color, filled: bool) -> void: + var points := _heart_points(origin) + var shadow := PackedVector2Array() + for point in points: + shadow.append(point + Vector2(0.0, 3.0)) + draw_colored_polygon(shadow, Color(0.18, 0.10, 0.07, 0.24)) + draw_colored_polygon(points, color) + var outline := points.duplicate() + outline.append(points[0]) + draw_polyline(outline, OUTLINE_COLOR, 2.5, true) + + # Piccolo riflesso da pallina smaltata, coerente con gli altri elementi HUD. + var shine_alpha := 0.72 if filled else 0.38 + draw_circle(origin + Vector2(10.5, 9.0), 3.4, Color(1.0, 0.94, 0.91, shine_alpha)) + + +func _heart_points(origin: Vector2) -> PackedVector2Array: + # Quattro curve cubiche formano un cuore pieno di 36x35 px. + var points := PackedVector2Array() + var segments := [ + [Vector2(18, 34), Vector2(15, 30), Vector2(2, 22), Vector2(2, 11)], + [Vector2(2, 11), Vector2(2, 3), Vector2(12, 0), Vector2(18, 7)], + [Vector2(18, 7), Vector2(24, 0), Vector2(34, 3), Vector2(34, 11)], + [Vector2(34, 11), Vector2(34, 22), Vector2(21, 30), Vector2(18, 34)], + ] + for segment in segments: + for step in range(8): + var t := float(step) / 8.0 + points.append(origin + _cubic(segment[0], segment[1], segment[2], segment[3], t)) + points.append(origin + Vector2(18, 34)) + return points + + +func _cubic(a: Vector2, b: Vector2, c: Vector2, d: Vector2, t: float) -> Vector2: + var u := 1.0 - t + return u * u * u * a + 3.0 * u * u * t * b + 3.0 * u * t * t * c + t * t * t * d diff --git a/scripts/hearts_display.gd.uid b/scripts/hearts_display.gd.uid new file mode 100644 index 0000000..077fc54 --- /dev/null +++ b/scripts/hearts_display.gd.uid @@ -0,0 +1 @@ +uid://x0ialp40fqlk diff --git a/scripts/main.gd b/scripts/main.gd index 900f708..4b28116 100644 --- a/scripts/main.gd +++ b/scripts/main.gd @@ -43,6 +43,7 @@ var balls := {} # color_name -> Ball var target_color := "" # bersaglio corrente (vuoto = nessun bersaglio) var score := 0 var combo := 0.0 # float: decade col ritardo di reazione +var lives := 4 # cuori (modalità Survival) var elapsed := 0.0 var window_timer := 0.0 var window_time := Settings.start_time @@ -62,6 +63,9 @@ var sound_error: AudioStreamWAV var sound_timeout: AudioStreamWAV var sound_milestone: AudioStreamWAV var sound_victory: AudioStreamWAV +var sound_defeat: AudioStreamWAV +var sound_lose_heart: AudioStreamWAV +var hearts: Node2D var victory_layer: CanvasLayer var victory_shown := false var ball_sounds := {} # color_name -> AudioStreamWAV (tono pentatonico) @@ -91,7 +95,7 @@ func _process(delta: float) -> void: elapsed += delta if target_color == "": return # in attesa che una pallina torni a casa: nessun countdown - if Settings.zen_mode: + if Settings.game_mode == 1: # modalità Zen: nessun countdown né decay return # modalità zen: nessun countdown né decay (niente pressione) # il combo decade in proporzione al tempo che aspetto prima di cliccare if combo > 0.0: @@ -199,6 +203,13 @@ func _build_ui() -> void: combo_label.add_theme_color_override("font_color", ink) layer.add_child(combo_label) + # cuori della modalità Survival (visibili solo in quella modalità) + hearts = load("res://scripts/hearts_display.gd").new() + # Fascia libera sotto BERSAGLIO: resta lontana da target, Opzioni e combo. + hearts.position = Vector2(121, 99) + hearts.visible = false + layer.add_child(hearts) + # pulsante Opzioni var opts_btn := Button.new() opts_btn.text = "Opzioni" @@ -256,6 +267,9 @@ func _init_audio() -> void: sound_milestone = _create_soft_arpeggio([523.25, 659.25, 783.99, 1046.5], 0.12) # audio di vittoria: arpeggio ascendente luminoso ma morbido (sensory-friendly) sound_victory = _create_soft_arpeggio([523.25, 659.25, 783.99, 1046.5, 1318.51, 1567.98], 0.16) + # audio di sconfitta (discendente, morbido) e di cuore perso + sound_defeat = _create_soft_arpeggio([392.0, 329.63, 261.63], 0.18) + sound_lose_heart = _create_tone(330.0, 0.15, 0.2) # tono pentatonico per ogni pallina colorata for cn in BALL_NOTES: ball_sounds[cn] = _create_tone(BALL_NOTES[cn], 0.2, 0.3) @@ -348,6 +362,10 @@ func _new_game() -> void: window_timer = 0.0 window_time = Settings.start_time next_milestone = 100 + lives = 4 + if hearts: + hearts.set_lives(lives) + hearts.visible = Settings.game_mode == 2 for b in balls.values(): b.reset() _pick_target() @@ -389,6 +407,8 @@ func _handle_click(pos: Vector2) -> void: else: combo = 0.0 _update_hud() + if Settings.game_mode == 2: + _lose_life() # survival: l'errore costa un cuore func _on_timeout() -> void: @@ -401,6 +421,8 @@ func _on_timeout() -> void: window_timer = 0.0 _pick_target() _update_hud() + if Settings.game_mode == 2: + _lose_life() # survival: il timeout costa un cuore func _on_ball_returned() -> void: @@ -468,10 +490,34 @@ func _update_hud() -> void: # ---------------------------------------------- feedback alle milestone func _check_victory() -> void: + if Settings.game_mode == 2: + return # survival: endless, ignora il target punteggio if not victory_shown and score >= Settings.target_score: _on_victory() +func _lose_life() -> void: + if victory_shown: + return + lives -= 1 + _play_sound(sound_lose_heart) + if hearts: + hearts.set_lives(maxi(lives, 0)) + if lives <= 0: + _on_game_over() + + +func _on_game_over() -> void: + if victory_shown: + return + victory_shown = true + # ferma la musica e riproduce l'audio di sconfitta + bgm.stop() + _play_sound(sound_defeat) + get_tree().paused = true + victory_layer.show_game_over(score) + + func _on_victory() -> void: if victory_shown: return diff --git a/scripts/options_menu.gd b/scripts/options_menu.gd index 93de120..01d1271 100644 --- a/scripts/options_menu.gd +++ b/scripts/options_menu.gd @@ -4,8 +4,9 @@ extends CanvasLayer ## scena applicando i nuovi valori. var rows := {} # key -> {slider, spin} -var zen_cb: CheckButton +var mode_option: OptionButton var gentle_cb: CheckButton +var survival_cb: CheckButton func _ready() -> void: @@ -62,13 +63,33 @@ func _build() -> void: for e in entries: rows[e[0]] = _build_row(vb, e[0], e[1], e[2], e[3], e[4]) - # opzioni accessibilità / neurodivergenza - zen_cb = CheckButton.new() - zen_cb.text = "Modalità Zen (senza tempo)" - zen_cb.button_pressed = Settings.zen_mode - zen_cb.toggled.connect(func(on: bool): Settings.zen_mode = on) - vb.add_child(zen_cb) + # modalità di gioco (mutuamente esclusive) + var mode_separator := HSeparator.new() + mode_separator.add_theme_constant_override("separation", 5) + vb.add_child(mode_separator) + var mrow := HBoxContainer.new() + mrow.custom_minimum_size.y = 44 + mrow.add_theme_constant_override("separation", 12) + mrow.alignment = BoxContainer.ALIGNMENT_CENTER + vb.add_child(mrow) + var mlbl := Label.new() + mlbl.text = "Modalità di gioco:" + mlbl.custom_minimum_size.x = 230 + mlbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + mlbl.add_theme_font_size_override("font_size", 18) + mrow.add_child(mlbl) + mode_option = OptionButton.new() + mode_option.custom_minimum_size.x = 300 + mode_option.custom_minimum_size.y = 40 + mode_option.add_theme_font_size_override("font_size", 17) + mode_option.add_item("Classica (a punteggio)") + mode_option.add_item("Zen (senza tempo)") + mode_option.add_item("Survival (a vite)") + mode_option.select(Settings.game_mode) + mode_option.item_selected.connect(func(idx: int): Settings.game_mode = idx) + mrow.add_child(mode_option) + # opzioni accessibilità / neurodivergenza gentle_cb = CheckButton.new() gentle_cb.text = "Errori gentili (combo -1)" gentle_cb.button_pressed = Settings.gentle_errors @@ -137,8 +158,8 @@ func show_menu() -> void: var val: float = Settings.get(key) rows[key].slider.value = val rows[key].spin.value = val - if zen_cb: - zen_cb.button_pressed = Settings.zen_mode + if mode_option: + mode_option.select(Settings.game_mode) if gentle_cb: gentle_cb.button_pressed = Settings.gentle_errors visible = true @@ -162,8 +183,8 @@ func _on_reset() -> void: var val: float = Settings.get(key) rows[key].slider.value = val rows[key].spin.value = val - if zen_cb: - zen_cb.button_pressed = Settings.zen_mode + if mode_option: + mode_option.select(Settings.game_mode) if gentle_cb: gentle_cb.button_pressed = Settings.gentle_errors diff --git a/scripts/settings.gd b/scripts/settings.gd index ff1afd3..7bd4010 100644 --- a/scripts/settings.gd +++ b/scripts/settings.gd @@ -4,7 +4,7 @@ extends Node ## al riavvio della scena. const PATH := "user://settings.cfg" -const VERSION := 5 # incrementa quando cambiano i default, per resettare i file vecchi +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 @@ -16,9 +16,10 @@ 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 -var zen_mode := false # modalità senza tempo (niente countdown né decay) func _ready() -> void: @@ -40,12 +41,12 @@ func load_settings() -> void: 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) - zen_mode = cfg.get_value("accessibility", "zen_mode", zen_mode) func save_settings() -> void: @@ -56,12 +57,12 @@ func save_settings() -> void: 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.set_value("accessibility", "zen_mode", zen_mode) cfg.save(PATH) @@ -71,9 +72,9 @@ func reset_defaults() -> void: 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 - zen_mode = false diff --git a/scripts/victory_overlay.gd b/scripts/victory_overlay.gd index 6022093..f39dd7e 100644 --- a/scripts/victory_overlay.gd +++ b/scripts/victory_overlay.gd @@ -11,6 +11,7 @@ const BRASS_LIGHT := Color("#f6d77a") var title_label: Label var score_label: Label +var subtitle_label: Label var _card: Control var _reset_button: Button @@ -132,13 +133,13 @@ func _build() -> void: title_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER vb.add_child(title_label) - var subtitle := Label.new() - subtitle.text = "Hai raggiunto il punteggio target!" - subtitle.add_theme_font_override("font", DISPLAY_FONT) - subtitle.add_theme_font_size_override("font_size", 23) - subtitle.add_theme_color_override("font_color", INK) - subtitle.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - vb.add_child(subtitle) + subtitle_label = Label.new() + subtitle_label.text = "Hai raggiunto il punteggio target!" + subtitle_label.add_theme_font_override("font", DISPLAY_FONT) + subtitle_label.add_theme_font_size_override("font_size", 23) + subtitle_label.add_theme_color_override("font_color", INK) + subtitle_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + vb.add_child(subtitle_label) var score_plaque := PanelContainer.new() score_plaque.add_theme_stylebox_override("panel", _flat_style(Color("#f7e6bc"), Color("#9d6b29"), 3, 14)) @@ -180,6 +181,20 @@ func _button_style(color: Color, border: Color, width: int) -> StyleBoxFlat: func show_victory(score: int) -> void: + show_end("victory", score) + + +func show_game_over(score: int) -> void: + show_end("gameover", score) + + +func show_end(kind: String, score: int) -> void: + var victory := kind == "victory" + title_label.text = "VITTORIA!" if victory else "GAME OVER" + title_label.add_theme_color_override("font_color", + Color("#ffe08a") if victory else Color("#f0b4b4")) + subtitle_label.text = "Hai raggiunto il punteggio target!" if victory else \ + "Hai perso tutti i cuori... Ritenta!" score_label.text = "Punteggio: %d" % score visible = true _card.modulate.a = 0.0 diff --git a/verification/01-base.png b/verification/01-base.png new file mode 100644 index 0000000..c16a85d Binary files /dev/null and b/verification/01-base.png differ diff --git a/verification/01-base.png.import b/verification/01-base.png.import new file mode 100644 index 0000000..c808e93 --- /dev/null +++ b/verification/01-base.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://pnxvvowelvxa" +path="res://.godot/imported/01-base.png-8f76b0be0bab160c3f472a5c3cba153e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://verification/01-base.png" +dest_files=["res://.godot/imported/01-base.png-8f76b0be0bab160c3f472a5c3cba153e.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 diff --git a/verification/02-lock-dialog.png b/verification/02-lock-dialog.png new file mode 100644 index 0000000..7ac9f89 Binary files /dev/null and b/verification/02-lock-dialog.png differ diff --git a/verification/02-lock-dialog.png.import b/verification/02-lock-dialog.png.import new file mode 100644 index 0000000..d80b379 --- /dev/null +++ b/verification/02-lock-dialog.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b1gnf3fktq15" +path="res://.godot/imported/02-lock-dialog.png-e9cae089c54853c79a38ae73ee57ed72.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://verification/02-lock-dialog.png" +dest_files=["res://.godot/imported/02-lock-dialog.png-e9cae089c54853c79a38ae73ee57ed72.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 diff --git a/verification/03-options-unlocked.png b/verification/03-options-unlocked.png new file mode 100644 index 0000000..977a9be Binary files /dev/null and b/verification/03-options-unlocked.png differ diff --git a/verification/03-options-unlocked.png.import b/verification/03-options-unlocked.png.import new file mode 100644 index 0000000..561715a --- /dev/null +++ b/verification/03-options-unlocked.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://do6rvjgk4sver" +path="res://.godot/imported/03-options-unlocked.png-c5d4f59fb45c67c40634d4412ef46b95.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://verification/03-options-unlocked.png" +dest_files=["res://.godot/imported/03-options-unlocked.png-c5d4f59fb45c67c40634d4412ef46b95.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 diff --git a/verification/04-survival-hearts.png b/verification/04-survival-hearts.png new file mode 100644 index 0000000..fd46d53 Binary files /dev/null and b/verification/04-survival-hearts.png differ diff --git a/verification/04-survival-hearts.png.import b/verification/04-survival-hearts.png.import new file mode 100644 index 0000000..95dbc7d --- /dev/null +++ b/verification/04-survival-hearts.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cu6j5b4hod33b" +path="res://.godot/imported/04-survival-hearts.png-182ece3ef37b8bcc11c34ba3305bf365.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://verification/04-survival-hearts.png" +dest_files=["res://.godot/imported/04-survival-hearts.png-182ece3ef37b8bcc11c34ba3305bf365.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 diff --git a/verification/05-options-mode-selector.png b/verification/05-options-mode-selector.png new file mode 100644 index 0000000..e62e1c5 Binary files /dev/null and b/verification/05-options-mode-selector.png differ diff --git a/verification/05-options-mode-selector.png.import b/verification/05-options-mode-selector.png.import new file mode 100644 index 0000000..fb5b023 --- /dev/null +++ b/verification/05-options-mode-selector.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://2rdadbuks4x1" +path="res://.godot/imported/05-options-mode-selector.png-ede8e28430a9cba46e2d636801e4b77e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://verification/05-options-mode-selector.png" +dest_files=["res://.godot/imported/05-options-mode-selector.png-ede8e28430a9cba46e2d636801e4b77e.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 diff --git a/verification/check.png b/verification/check.png new file mode 100644 index 0000000..53c7d48 Binary files /dev/null and b/verification/check.png differ diff --git a/verification/check.png.import b/verification/check.png.import new file mode 100644 index 0000000..1ca9875 --- /dev/null +++ b/verification/check.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cy7tdroiuiyox" +path="res://.godot/imported/check.png-986079f3804b54058bf1eacd42e341a6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://verification/check.png" +dest_files=["res://.godot/imported/check.png-986079f3804b54058bf1eacd42e341a6.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