Files
my-world/core/settings.gd
T
aibrashandClaude Sonnet 5.5 2d347d132b Геймпад Xbox, меню паузы с настройками, новый хаб с музыкой
- Геймпад: раскладка под паркур и гонки, обзор правым стиком, навигация по меню (A/B/крестовина)
- Меню паузы (Esc/Start): выход в хаб, настройки (мышь, стик, FOV, громкость, инверсия), справка по управлению
- Хаб 48x32x10 м: колонны, окна с городом, голограмма, лавки; музыка «Local Forecast - Elevator» (Kevin MacLeod, CC-BY)
- Тесты: pause_test, pad_menu_test, hub_tour; README обновлён

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 18:36:50 +05:00

148 lines
6.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node
# Автолоад «Settings»: пользовательские настройки (мышь, стик, FOV, громкость) и раскладка геймпада Xbox.
# Геймпад добавляется в InputMap кодом (а не в project.godot): раскладка собрана в одном месте и видна целиком.
# Сохраняется в user://settings.cfg, но только когда игрок что-то менял (save()).
#
# Раскладка под паркур и гонки (правый большой палец всегда остаётся на стике обзора):
# левый стик — движение, правый стик — обзор
# A / LB — прыжок (подтягивание, прыжок от стены, двойной прыжок) RT / L3 — спринт (держать)
# X / RB — рывок B — присед (держать); RT + B на бегу — подкат
# LT / R3 — зум Y — «готов» (гонка) / забег заново (Parkour)
# Back — таблица лидеров крестовина вниз (держать) — сдаться в гонке
# Start — пауза
signal changed
const PATH := "user://settings.cfg"
const DEFAULT_FOV := 60.0
const STICK_DEADZONE := 0.22
const STICK_LOOK_SPEED := 3.6 # рад/с при полном отклонении стика и множителе 1.0 (~205°/с)
var mouse_sens := 1.0 # множитель к player.MOUSE_SENSITIVITY
var stick_sens := 1.0 # множитель к STICK_LOOK_SPEED
var fov := DEFAULT_FOV # базовое поле зрения
var volume := 1.0 # общая громкость 0..1
var invert_y := false # инверсия вертикали (мышь и стик)
var gamepad_used := false # игрок трогал геймпад (для подсказок)
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
_setup_gamepad()
load_settings()
apply()
func _input(event: InputEvent) -> void:
if event is InputEventJoypadButton or (event is InputEventJoypadMotion and absf(event.axis_value) > 0.5):
gamepad_used = true
elif event is InputEventKey or event is InputEventMouseButton:
gamepad_used = false
# ---------- сохранение ----------
func load_settings() -> void:
var cfg := ConfigFile.new()
if cfg.load(PATH) != OK:
return
mouse_sens = clampf(float(cfg.get_value("input", "mouse_sens", mouse_sens)), 0.2, 3.0)
stick_sens = clampf(float(cfg.get_value("input", "stick_sens", stick_sens)), 0.3, 2.5)
invert_y = bool(cfg.get_value("input", "invert_y", invert_y))
fov = clampf(float(cfg.get_value("video", "fov", fov)), 60.0, 100.0)
volume = clampf(float(cfg.get_value("audio", "volume", volume)), 0.0, 1.0)
func save() -> void:
var cfg := ConfigFile.new()
cfg.set_value("input", "mouse_sens", mouse_sens)
cfg.set_value("input", "stick_sens", stick_sens)
cfg.set_value("input", "invert_y", invert_y)
cfg.set_value("video", "fov", fov)
cfg.set_value("audio", "volume", volume)
cfg.save(PATH)
func apply() -> void:
var bus := AudioServer.get_bus_index("Master")
AudioServer.set_bus_mute(bus, volume <= 0.001)
AudioServer.set_bus_volume_db(bus, linear_to_db(maxf(volume, 0.001)))
changed.emit()
func reset_defaults() -> void:
mouse_sens = 1.0
stick_sens = 1.0
fov = DEFAULT_FOV
volume = 1.0
invert_y = false
apply()
# ---------- геймпад ----------
func _setup_gamepad() -> void:
# Стики: двигаем и смотрим
_axis("move_left", JOY_AXIS_LEFT_X, -1.0)
_axis("move_right", JOY_AXIS_LEFT_X, 1.0)
_axis("move_forward", JOY_AXIS_LEFT_Y, -1.0)
_axis("move_back", JOY_AXIS_LEFT_Y, 1.0)
for a in ["move_left", "move_right", "move_forward", "move_back"]:
InputMap.action_set_deadzone(a, STICK_DEADZONE)
_new_action("look_left", STICK_DEADZONE)
_new_action("look_right", STICK_DEADZONE)
_new_action("look_up", STICK_DEADZONE)
_new_action("look_down", STICK_DEADZONE)
_axis("look_left", JOY_AXIS_RIGHT_X, -1.0)
_axis("look_right", JOY_AXIS_RIGHT_X, 1.0)
_axis("look_up", JOY_AXIS_RIGHT_Y, -1.0)
_axis("look_down", JOY_AXIS_RIGHT_Y, 1.0)
# Действия
_button("jump", JOY_BUTTON_A)
_button("jump", JOY_BUTTON_LEFT_SHOULDER) # прыжок на плече: правый палец не уходит со стика обзора
_axis("sprint", JOY_AXIS_TRIGGER_RIGHT, 1.0)
_button("sprint", JOY_BUTTON_LEFT_STICK)
_button("crouch", JOY_BUTTON_B)
_button("dash", JOY_BUTTON_X)
_button("dash", JOY_BUTTON_RIGHT_SHOULDER)
_new_action("zoom", 0.3)
_axis("zoom", JOY_AXIS_TRIGGER_LEFT, 1.0)
_button("zoom", JOY_BUTTON_RIGHT_STICK)
_button("ready", JOY_BUTTON_Y)
_button("leaderboard", JOY_BUTTON_BACK)
_button("giveup", JOY_BUTTON_DPAD_DOWN)
# Навигация по меню: A — выбрать, B — назад (в этом проекте у ui_accept/ui_cancel кнопок геймпада нет)
_button_once("ui_accept", JOY_BUTTON_A)
_button_once("ui_cancel", JOY_BUTTON_B)
_button_once("ui_up", JOY_BUTTON_DPAD_UP)
_button_once("ui_down", JOY_BUTTON_DPAD_DOWN)
_button_once("ui_left", JOY_BUTTON_DPAD_LEFT)
_button_once("ui_right", JOY_BUTTON_DPAD_RIGHT)
# Пауза: Esc и Start
_new_action("pause", 0.5)
var esc := InputEventKey.new()
esc.physical_keycode = KEY_ESCAPE
InputMap.action_add_event("pause", esc)
_button("pause", JOY_BUTTON_START)
func _new_action(action: String, deadzone: float) -> void:
if not InputMap.has_action(action):
InputMap.add_action(action, deadzone)
func _axis(action: String, axis: JoyAxis, value: float) -> void:
_new_action(action, 0.5)
var e := InputEventJoypadMotion.new()
e.axis = axis
e.axis_value = value
InputMap.action_add_event(action, e)
func _button_once(action: String, button: JoyButton) -> void:
for e in InputMap.action_get_events(action):
if e is InputEventJoypadButton and e.button_index == button:
return
_button(action, button)
func _button(action: String, button: JoyButton) -> void:
_new_action(action, 0.5)
var e := InputEventJoypadButton.new()
e.button_index = button
InputMap.action_add_event(action, e)