简单建立ui
This commit is contained in:
parent
0e68c6e666
commit
c154b11ed2
|
|
@ -0,0 +1,108 @@
|
|||
# scripts/settings/SettingsModel.gd
|
||||
extends Node
|
||||
class_name SettingsModel
|
||||
|
||||
## ===============================
|
||||
## Dependencies
|
||||
## ===============================
|
||||
const SettingsSchema = preload("res://__settings/SettingSchema.gd")
|
||||
const SettingsStorage = preload("res://__settings/SettingStorage.gd")
|
||||
|
||||
## ===============================
|
||||
## Signals
|
||||
## ===============================
|
||||
signal setting_changed(section: String, key: String, value)
|
||||
signal settings_applied
|
||||
signal settings_reverted
|
||||
|
||||
## ===============================
|
||||
## Internal State
|
||||
## ===============================
|
||||
var _data_committed : Dictionary = {} # 已生效 / 已保存
|
||||
var _data_working : Dictionary = {} # UI 正在修改
|
||||
var _storage := SettingsStorage.new()
|
||||
|
||||
## ===============================
|
||||
## Lifecycle
|
||||
## ===============================
|
||||
func _ready() -> void:
|
||||
_load()
|
||||
|
||||
## ===============================
|
||||
## Public API (Read)
|
||||
## ===============================
|
||||
func get_setting(section: String, key: String) -> Variant:
|
||||
return _data_working.get(section, {}).get(key)
|
||||
|
||||
func get_section(section: String) -> Dictionary:
|
||||
return _data_working.get(section, {}).duplicate(true)
|
||||
|
||||
## ===============================
|
||||
## Public API (Write - Working Only)
|
||||
## ===============================
|
||||
func set_setting(section: String, key: String, value: Variant) -> void:
|
||||
if not _data_working.has(section):
|
||||
_data_working[section] = {}
|
||||
|
||||
_data_working[section][key] = value
|
||||
emit_signal("setting_changed", section, key, value)
|
||||
|
||||
## ===============================
|
||||
## Typed Getters
|
||||
## ===============================
|
||||
func get_bool(section: String, key: String) -> bool:
|
||||
var value = get_setting(section, key)
|
||||
return value if typeof(value) == TYPE_BOOL else false
|
||||
|
||||
func get_int(section: String, key: String) -> int:
|
||||
var value = get_setting(section, key)
|
||||
return value if typeof(value) == TYPE_INT else 0
|
||||
|
||||
func get_float(section: String, key: String) -> float:
|
||||
var value = get_setting(section, key)
|
||||
if typeof(value) == TYPE_FLOAT or typeof(value) == TYPE_INT:
|
||||
return float(value)
|
||||
return 0.0
|
||||
|
||||
func get_string(section: String, key: String) -> String:
|
||||
var value = get_setting(section, key)
|
||||
return value if typeof(value) == TYPE_STRING else ""
|
||||
|
||||
## ===============================
|
||||
## Transaction Control
|
||||
## ===============================
|
||||
func apply() -> void:
|
||||
_data_committed = _data_working.duplicate(true)
|
||||
|
||||
for section in _data_committed.keys():
|
||||
for key in _data_committed[section].keys():
|
||||
_storage.set_value(section, key, _data_committed[section][key])
|
||||
|
||||
_storage.save()
|
||||
emit_signal("settings_applied")
|
||||
|
||||
func revert() -> void:
|
||||
_data_working = _data_committed.duplicate(true)
|
||||
emit_signal("settings_reverted")
|
||||
|
||||
func has_unsaved_changes() -> bool:
|
||||
return _data_working != _data_committed
|
||||
|
||||
## ===============================
|
||||
## Internal
|
||||
## ===============================
|
||||
func _load() -> void:
|
||||
_storage.load()
|
||||
|
||||
# 1. Load defaults
|
||||
_data_committed = SettingsSchema.defaults().duplicate(true)
|
||||
|
||||
# 2. Override with saved values
|
||||
for section in _data_committed.keys():
|
||||
for key in _data_committed[section].keys():
|
||||
var default_value = _data_committed[section][key]
|
||||
var value = _storage.get_value(section, key, default_value)
|
||||
_data_committed[section][key] = value
|
||||
|
||||
# 3. Init working copy
|
||||
_data_working = _data_committed.duplicate(true)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cmyknlur1bk2d
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
class_name SettingSchema
|
||||
extends RefCounted
|
||||
|
||||
## ===============================
|
||||
## 默认设置定义
|
||||
## ===============================
|
||||
static func defaults() -> Dictionary:
|
||||
return {
|
||||
"audio": {
|
||||
"master_volume": 1.0,
|
||||
"music_volume": 0.8,
|
||||
"sfx_volume": 0.8,
|
||||
},
|
||||
"graphics": {
|
||||
"quality": 2, # 0=low,1=mid,2=high
|
||||
"fullscreen": true,
|
||||
},
|
||||
"input": {
|
||||
# 这里只是占位,后面可扩展
|
||||
"mouse_sensitivity": 1.0,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://i1nipeyuught
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# scripts/settings/SettingsStorage.gd
|
||||
extends RefCounted
|
||||
class_name SettingsStorage
|
||||
|
||||
const FILE_PATH := "user://settings.cfg"
|
||||
|
||||
var _config := ConfigFile.new()
|
||||
|
||||
func load() -> void:
|
||||
_config.load(FILE_PATH)
|
||||
|
||||
func save() -> void:
|
||||
_config.save(FILE_PATH)
|
||||
|
||||
func has(section: String, key: String) -> bool:
|
||||
return _config.has_section_key(section, key)
|
||||
|
||||
func get_value(section: String, key: String, default):
|
||||
return _config.get_value(section, key, default)
|
||||
|
||||
func set_value(section: String, key: String, value) -> void:
|
||||
_config.set_value(section, key, value)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bmnwylphnuio7
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
extends RefCounted
|
||||
class_name InputSchema
|
||||
|
||||
static func defaults() -> Dictionary:
|
||||
return {
|
||||
"move_left": [
|
||||
_key(KEY_A),
|
||||
_key(KEY_LEFT),
|
||||
],
|
||||
"move_right": [
|
||||
_key(KEY_D),
|
||||
_key(KEY_RIGHT),
|
||||
],
|
||||
"jump": [
|
||||
_key(KEY_SPACE),
|
||||
],
|
||||
"attack": [
|
||||
_mouse(MOUSE_BUTTON_LEFT),
|
||||
],
|
||||
}
|
||||
|
||||
## ===============================
|
||||
## Helpers (序列化友好)
|
||||
## ===============================
|
||||
static func _key(keycode: int) -> Dictionary:
|
||||
return {
|
||||
"type": "key",
|
||||
"keycode": keycode,
|
||||
}
|
||||
|
||||
static func _mouse(button: int) -> Dictionary:
|
||||
return {
|
||||
"type": "mouse",
|
||||
"button": button,
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cdf7xcwgtd7jb
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
extends Node
|
||||
class_name InputSettingsModel
|
||||
|
||||
## ===============================
|
||||
## Dependencies
|
||||
## ===============================
|
||||
const InputSchema = preload("res://__settings/input/InputSchema.gd")
|
||||
const SettingsStorage = preload("res://__settings/SettingStorage.gd")
|
||||
|
||||
## ===============================
|
||||
## Signals
|
||||
## ===============================
|
||||
signal binding_changed(action: String)
|
||||
signal bindings_applied
|
||||
signal bindings_reverted
|
||||
|
||||
## ===============================
|
||||
## Internal State
|
||||
## ===============================
|
||||
var _bindings_committed : Dictionary = {}
|
||||
var _bindings_working : Dictionary = {}
|
||||
var _storage := SettingsStorage.new()
|
||||
|
||||
const SECTION := "input"
|
||||
|
||||
## ===============================
|
||||
## Lifecycle
|
||||
## ===============================
|
||||
func _ready() -> void:
|
||||
_load()
|
||||
|
||||
## ===============================
|
||||
## Public API (Read)
|
||||
## ===============================
|
||||
func get_bindings(action: String) -> Array:
|
||||
return _bindings_working.get(action, []).duplicate(true)
|
||||
|
||||
func get_all_bindings() -> Dictionary:
|
||||
return _bindings_working.duplicate(true)
|
||||
|
||||
## ===============================
|
||||
## Public API (Write)
|
||||
## ===============================
|
||||
func set_bindings(action: String, bindings: Array) -> void:
|
||||
_bindings_working[action] = bindings
|
||||
emit_signal("binding_changed", action)
|
||||
|
||||
func add_binding(action: String, binding: Dictionary) -> void:
|
||||
if not _bindings_working.has(action):
|
||||
_bindings_working[action] = []
|
||||
_bindings_working[action].append(binding)
|
||||
emit_signal("binding_changed", action)
|
||||
|
||||
func clear_bindings(action: String) -> void:
|
||||
_bindings_working[action] = []
|
||||
emit_signal("binding_changed", action)
|
||||
|
||||
## ===============================
|
||||
## Transaction
|
||||
## ===============================
|
||||
func apply() -> void:
|
||||
_bindings_committed = _bindings_working.duplicate(true)
|
||||
_save_to_storage()
|
||||
_apply_to_input_map()
|
||||
emit_signal("bindings_applied")
|
||||
|
||||
func revert() -> void:
|
||||
_bindings_working = _bindings_committed.duplicate(true)
|
||||
emit_signal("bindings_reverted")
|
||||
|
||||
func has_unsaved_changes() -> bool:
|
||||
return _bindings_working != _bindings_committed
|
||||
|
||||
## ===============================
|
||||
## Internal
|
||||
## ===============================
|
||||
func _load() -> void:
|
||||
_storage.load()
|
||||
|
||||
# 1. defaults
|
||||
_bindings_committed = InputSchema.defaults().duplicate(true)
|
||||
|
||||
# 2. override from storage
|
||||
for action in _bindings_committed.keys():
|
||||
var saved = _storage.get_value(SECTION, action, null)
|
||||
if saved != null:
|
||||
_bindings_committed[action] = saved
|
||||
|
||||
_bindings_working = _bindings_committed.duplicate(true)
|
||||
|
||||
# 3. apply to engine at startup
|
||||
_apply_to_input_map()
|
||||
|
||||
func _save_to_storage() -> void:
|
||||
for action in _bindings_committed.keys():
|
||||
_storage.set_value(SECTION, action, _bindings_committed[action])
|
||||
_storage.save()
|
||||
|
||||
func _apply_to_input_map() -> void:
|
||||
for action in _bindings_committed.keys():
|
||||
if not InputMap.has_action(action):
|
||||
InputMap.add_action(action)
|
||||
|
||||
InputMap.action_erase_events(action)
|
||||
|
||||
for binding in _bindings_committed[action]:
|
||||
var event = _binding_to_event(binding)
|
||||
if event:
|
||||
InputMap.action_add_event(action, event)
|
||||
|
||||
func _binding_to_event(binding: Dictionary) -> InputEvent:
|
||||
match binding.get("type"):
|
||||
"key":
|
||||
var e := InputEventKey.new()
|
||||
e.keycode = binding.get("keycode", 0)
|
||||
return e
|
||||
"mouse":
|
||||
var e := InputEventMouseButton.new()
|
||||
e.button_index = binding.get("button", 0)
|
||||
return e
|
||||
return null
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dytq5bvr0l2rq
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
|
|
@ -0,0 +1,40 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cacik4t6grtq8"
|
||||
path="res://.godot/imported/未命名作品(4).png-151765b68adadae09c88456ac264362b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://_asset/ksw/未命名作品(4).png"
|
||||
dest_files=["res://.godot/imported/未命名作品(4).png-151765b68adadae09c88456ac264362b.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
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
[gd_resource type="TileSet" load_steps=5 format=3 uid="uid://cup1q1upvp18h"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://dd622t4mw5vva" path="res://_asset/ksw/basicTile01.png" id="2_mucy5"]
|
||||
[ext_resource type="Texture2D" uid="uid://cwet2kw1mngmf" path="res://_asset/ksw/basicTile02.png" id="3_u6jqb"]
|
||||
[ext_resource type="Texture2D" uid="uid://dufe0liirugbw" path="res://_asset/ksw/basicTile02.png" id="3_u6jqb"]
|
||||
|
||||
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_u6jqb"]
|
||||
texture = ExtResource("2_mucy5")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
extends Control
|
||||
|
||||
@onready var b_setting: Button = %B_Setting
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://d1gf5wcjkwong
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://b4ojkr2fq8xjm"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://b4ojkr2fq8xjm"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d1gf5wcjkwong" path="res://_ui/main_menu/main_menu.gd" id="1_102h7"]
|
||||
[ext_resource type="Texture2D" uid="uid://c673bap4b12fx" path="res://icon.svg" id="1_j8fyu"]
|
||||
|
||||
[node name="MainMenu" type="Control"]
|
||||
|
|
@ -9,6 +10,7 @@ anchor_right = 1.0
|
|||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_102h7")
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="."]
|
||||
layout_mode = 1
|
||||
|
|
@ -51,6 +53,12 @@ layout_mode = 2
|
|||
text = "Continue
|
||||
"
|
||||
|
||||
[node name="B_Setting" type="Button" parent="MC_Options/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Setting
|
||||
"
|
||||
|
||||
[node name="B_Option" type="Button" parent="MC_Options/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Option"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
[gd_scene format=3 uid="uid://dlxtqk6hbqu1"]
|
||||
|
||||
[node name="AudioSettingPanel" type="MarginContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
custom_minimum_size = Vector2(400, 0)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
|
|
@ -37,6 +37,7 @@ enabled=PackedStringArray("res://addons/reedcamera/plugin.cfg", "res://addons/re
|
|||
[file_customization]
|
||||
|
||||
folder_colors={
|
||||
"res://__settings/": "red",
|
||||
"res://_shared/": "pink",
|
||||
"res://_tileset/": "green"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue