初始化仓库
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
## 全局游戏状态(Autoload 单例)。
|
||||
## 负责场景间参数传递与会话状态管理,不持有游戏内数据。
|
||||
extends Node
|
||||
|
||||
## 进入游戏的方式。
|
||||
enum GameMode { NEW_GAME, LOAD_GAME }
|
||||
|
||||
## 当前进入游戏的方式。
|
||||
var mode: GameMode = GameMode.NEW_GAME
|
||||
## 当前存档组 ID(两级存档第一级,SaveSystem 分配)。
|
||||
var profile_id: int = 0
|
||||
## 要加载的槽位文件名(仅 LOAD_GAME 时有效,如 "auto"/"slot_1754734800")。
|
||||
var save_slot: String = ""
|
||||
|
||||
# 游戏内时间(12 月 × 30 天 = 360 天/年),实际推进由 TimeSystem 负责
|
||||
var year: int = 1 # 年
|
||||
var month: int = 1 # 月(1-12)
|
||||
var day: int = 1 # 日(1-30)
|
||||
|
||||
## 请求开始新游戏。
|
||||
## @param pid: 新存档组 ID(主菜单创建)
|
||||
func request_new_game(pid: int) -> void:
|
||||
mode = GameMode.NEW_GAME
|
||||
profile_id = pid
|
||||
save_slot = ""
|
||||
year = 1
|
||||
month = 1
|
||||
day = 1
|
||||
|
||||
## 请求加载指定存档。
|
||||
## @param pid: 存档组 ID
|
||||
## @param slot_name: 槽位文件名(不含 .json)
|
||||
func request_load_game(pid: int, slot_name: String) -> void:
|
||||
mode = GameMode.LOAD_GAME
|
||||
profile_id = pid
|
||||
save_slot = slot_name
|
||||
@@ -0,0 +1 @@
|
||||
uid://c0o83k384x3wp
|
||||
@@ -0,0 +1,7 @@
|
||||
[gd_scene format=3 uid="uid://c1exffg84ojqx"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://q1b6t22ej3ej" path="res://src/UI/Panels/MainMenu/MainMenu.tscn" id="1_g6xmk"]
|
||||
|
||||
[node name="MainGame" type="Node" unique_id=42551660]
|
||||
|
||||
[node name="MainMenu" parent="." unique_id=285750365 instance=ExtResource("1_g6xmk")]
|
||||
@@ -0,0 +1,21 @@
|
||||
## 用户设置(Autoload 单例)。
|
||||
## 负责个人偏好设置的持久化,保存于 user:// 目录,与游戏存档分离。
|
||||
extends Node
|
||||
|
||||
## 设置文件的保存路径。
|
||||
const SAVE_PATH := "user://settings.cfg"
|
||||
|
||||
## 新游戏开局时的默认流速档位索引(1 = 5x)。
|
||||
var default_speed_index := 1
|
||||
|
||||
## 从磁盘加载设置(不存在则保持默认值)。
|
||||
func load_settings() -> void:
|
||||
var cfg := ConfigFile.new()
|
||||
if cfg.load(SAVE_PATH) == OK:
|
||||
default_speed_index = cfg.get_value("time", "speed_index", 1)
|
||||
|
||||
## 将当前设置写入磁盘。
|
||||
func save_settings() -> void:
|
||||
var cfg := ConfigFile.new()
|
||||
cfg.set_value("time", "speed_index", default_speed_index)
|
||||
cfg.save(SAVE_PATH)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dpnjkyle57umm
|
||||
@@ -0,0 +1,139 @@
|
||||
## 全局时间系统(Autoload 单例)。
|
||||
## 负责游戏时间的推进与播报,仅在世界场景中运行。
|
||||
## 历法:12 月 × 30 日 = 360 日/年。
|
||||
extends Node
|
||||
|
||||
## 每当推进一日后发出。
|
||||
## @param year: 当前年份
|
||||
## @param month: 当前月份(1-12)
|
||||
## @param day: 当前日(1-30)
|
||||
signal day_passed(year: int, month: int, day: int)
|
||||
## 每当进入新月份时发出(同一天内 day_passed 之后)。
|
||||
## @param year: 当前年份
|
||||
## @param month: 当前月份(1-12)
|
||||
signal month_passed(year: int, month: int)
|
||||
## 每当进入新年份时发出(同一天内 month_passed 之后)。
|
||||
## @param year: 当前年份
|
||||
signal year_passed(year: int)
|
||||
## 时间流速档位变化时发出。
|
||||
## @param speed_index: 新档位在 SPEEDS 中的索引
|
||||
signal speed_changed(speed_index: int)
|
||||
## 暂停状态变化时发出。
|
||||
## @param paused: 是否已暂停
|
||||
signal pause_changed(paused: bool)
|
||||
|
||||
## 可选的时间流速倍率档位。
|
||||
const SPEEDS := [1.0, 5.0, 20.0]
|
||||
## 每月的天数。
|
||||
const DAYS_PER_MONTH := 30
|
||||
## 每年的月数。
|
||||
const MONTHS_PER_YEAR := 12
|
||||
## 现实世界每 1 天对应的时长(秒)。
|
||||
const DAY_LENGTH := 0.5
|
||||
|
||||
## 当前流速档位在 SPEEDS 中的索引。
|
||||
var speed_index := 0
|
||||
## 当前流速倍率(与 SPEEDS[speed_index] 保持一致)。
|
||||
var speed := 1.0
|
||||
## 是否暂停时间推进。
|
||||
var paused := false
|
||||
## 已累积的现实时间(秒),未满 1 天。
|
||||
var _elapsed := 0.0
|
||||
|
||||
## 每帧累积时间,满一天推进日期(仅游戏世界场景内)。
|
||||
func _process(delta: float) -> void:
|
||||
if paused or not _is_in_game():
|
||||
return
|
||||
_elapsed += delta * speed
|
||||
if _elapsed >= DAY_LENGTH:
|
||||
_elapsed -= DAY_LENGTH
|
||||
_advance()
|
||||
|
||||
|
||||
## 判断当前场景是否为游戏世界场景(主菜单/存档界面不推进时间)。
|
||||
## 通过 "game_scene" 分组识别,而非场景名。
|
||||
func _is_in_game() -> bool:
|
||||
var scene := get_tree().current_scene
|
||||
return scene != null and scene.is_in_group("game_scene")
|
||||
|
||||
|
||||
## 推进一日并广播对应信号,跨月/跨年时补发 month_passed / year_passed。
|
||||
func _advance() -> void:
|
||||
var new_month := false
|
||||
var new_year := false
|
||||
GameState.day += 1
|
||||
if GameState.day > DAYS_PER_MONTH:
|
||||
GameState.day = 1
|
||||
GameState.month += 1
|
||||
new_month = true
|
||||
if GameState.month > MONTHS_PER_YEAR:
|
||||
GameState.month = 1
|
||||
GameState.year += 1
|
||||
new_year = true
|
||||
day_passed.emit(GameState.year, GameState.month, GameState.day)
|
||||
if new_month:
|
||||
month_passed.emit(GameState.year, GameState.month)
|
||||
if new_year:
|
||||
year_passed.emit(GameState.year)
|
||||
|
||||
|
||||
## 循环切换下一档流速,返回新倍率。
|
||||
func cycle_speed() -> float:
|
||||
speed_index = (speed_index + 1) % SPEEDS.size()
|
||||
speed = SPEEDS[speed_index]
|
||||
speed_changed.emit(speed_index)
|
||||
return speed
|
||||
|
||||
|
||||
## 应用用户设置中的默认流速档位(新游戏开局调用)。
|
||||
func apply_default_speed() -> void:
|
||||
set_speed_index(Settings.default_speed_index)
|
||||
|
||||
|
||||
## 直接设置流速档位(越界自动钳制)。
|
||||
## @param index: 目标档位索引
|
||||
func set_speed_index(index: int) -> void:
|
||||
speed_index = clampi(index, 0, SPEEDS.size() - 1)
|
||||
speed = SPEEDS[speed_index]
|
||||
speed_changed.emit(speed_index)
|
||||
|
||||
|
||||
## 切换暂停状态,返回切换后的暂停状态。
|
||||
func toggle_pause() -> bool:
|
||||
paused = not paused
|
||||
pause_changed.emit(paused)
|
||||
return paused
|
||||
|
||||
|
||||
## 显式设置暂停状态(幂等,状态未变化时不发信号)。
|
||||
## @param value: 目标暂停状态
|
||||
func set_paused(value: bool) -> void:
|
||||
if paused == value:
|
||||
return
|
||||
paused = value
|
||||
pause_changed.emit(paused)
|
||||
|
||||
|
||||
## 当前流速的显示文本,如 "x5"。
|
||||
func get_speed_label() -> String:
|
||||
return "x%d" % int(speed)
|
||||
|
||||
|
||||
## 当前日期数组 [年, 月, 日]。
|
||||
func get_current_date() -> Array:
|
||||
return [GameState.year, GameState.month, GameState.day]
|
||||
|
||||
|
||||
## 当前日期文本,如 "3年 5月 12日"。
|
||||
func get_date_text() -> String:
|
||||
return "%d年 %d月 %d日" % [GameState.year, GameState.month, GameState.day]
|
||||
|
||||
|
||||
## 直接设置日期(供读档/测试使用)。
|
||||
## @param y: 年
|
||||
## @param m: 月(1-12)
|
||||
## @param d: 日(1-30)
|
||||
func set_date(y: int, m: int, d: int) -> void:
|
||||
GameState.year = y
|
||||
GameState.month = m
|
||||
GameState.day = d
|
||||
@@ -0,0 +1 @@
|
||||
uid://b8f8t2phmhq2e
|
||||
@@ -0,0 +1,28 @@
|
||||
extends Control
|
||||
|
||||
func _ready() -> void:
|
||||
pass
|
||||
|
||||
func _on_MainMenu_NewGame_ButtonUp() -> void:
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_MainMenu_LoadGame_ButtonUp() -> void:
|
||||
$Menu.hide()
|
||||
$SavePannel.show()
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_MainMenu_Settings_ButtonUp() -> void:
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_MainMenu_Exit_ButtonUp() -> void:
|
||||
get_tree().quit()
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_SavePannel_Esc_pressed() -> void:
|
||||
$SavePannel.hide()
|
||||
$Menu.show()
|
||||
pass # Replace with function body.
|
||||
@@ -0,0 +1 @@
|
||||
uid://re0q67p6ppnv
|
||||
@@ -0,0 +1,74 @@
|
||||
[gd_scene format=3 uid="uid://q1b6t22ej3ej"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://yosl3o8yjyks" path="res://assets/sprites/ui/图片大门.png" id="1_hrti0"]
|
||||
[ext_resource type="Script" uid="uid://re0q67p6ppnv" path="res://src/UI/Panels/MainMenu/MainMenu.gd" id="1_wrf65"]
|
||||
[ext_resource type="Theme" uid="uid://b3cyleh82wiq4" path="res://resources/mainmenu_button_theme.tres" id="2_cwvg5"]
|
||||
[ext_resource type="PackedScene" uid="uid://cqdytnp2v07v" path="res://src/UI/Panels/SavePannel.tscn" id="4_q7typ"]
|
||||
|
||||
[node name="MainMenu" type="Control" unique_id=285750365]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_wrf65")
|
||||
|
||||
[node name="BG" type="TextureRect" parent="." unique_id=1279813992]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
texture = ExtResource("1_hrti0")
|
||||
expand_mode = 2
|
||||
|
||||
[node name="Menu" type="CenterContainer" parent="." unique_id=684900922]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Menu" unique_id=313362564]
|
||||
custom_minimum_size = Vector2(400, 0)
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="ButtonNewGame" type="Button" parent="Menu/VBoxContainer" unique_id=1170524877]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource("2_cwvg5")
|
||||
text = "新游戏"
|
||||
|
||||
[node name="ButtonLoadGame" type="Button" parent="Menu/VBoxContainer" unique_id=145977970]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource("2_cwvg5")
|
||||
text = "加载游戏"
|
||||
|
||||
[node name="ButtonSettings" type="Button" parent="Menu/VBoxContainer" unique_id=1526312497]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource("2_cwvg5")
|
||||
text = "设置"
|
||||
|
||||
[node name="ButtonExit" type="Button" parent="Menu/VBoxContainer" unique_id=1558322531]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource("2_cwvg5")
|
||||
text = "退出"
|
||||
|
||||
[node name="SavePannel" parent="." unique_id=1536921001 instance=ExtResource("4_q7typ")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[connection signal="button_up" from="Menu/VBoxContainer/ButtonNewGame" to="." method="_on_MainMenu_NewGame_ButtonUp"]
|
||||
[connection signal="button_up" from="Menu/VBoxContainer/ButtonLoadGame" to="." method="_on_MainMenu_LoadGame_ButtonUp"]
|
||||
[connection signal="button_up" from="Menu/VBoxContainer/ButtonSettings" to="." method="_on_MainMenu_Settings_ButtonUp"]
|
||||
[connection signal="button_up" from="Menu/VBoxContainer/ButtonExit" to="." method="_on_MainMenu_Exit_ButtonUp"]
|
||||
[connection signal="save_panel_esc_pressed" from="SavePannel" to="." method="_on_SavePannel_Esc_pressed"]
|
||||
@@ -0,0 +1,33 @@
|
||||
## 存档面板(挂载于 SavePanel.tscn)。
|
||||
## 两级浏览:左侧存档组列表 → 右侧该组槽位列表。
|
||||
## 存档模式(游戏内):点"新建存档"每次创建新槽位;读档模式(主菜单):点槽位读档。
|
||||
extends Panel
|
||||
|
||||
## 面板模式。
|
||||
enum Mode { SAVE, LOAD }
|
||||
|
||||
## 请求关闭面板(返回上级界面)。
|
||||
signal save_panel_esc_pressed
|
||||
|
||||
## 槽位条目场景。
|
||||
const SAVE_SLOT_SCENE := preload("res://src/UI/Panels/SaveSlot.tscn")
|
||||
|
||||
#@onready var title_label: Label = %TitleLabel
|
||||
#@onready var group_container: VBoxContainer = %GroupContainer
|
||||
#@onready var slot_list: VBoxContainer = %SlotList
|
||||
#@onready var new_slot_button: Button = %Button_NewSlot
|
||||
|
||||
## 当前模式。
|
||||
var mode: Mode = Mode.LOAD
|
||||
## 当前浏览的存档组 ID。
|
||||
#var _current_profile: int = 0
|
||||
### 打开面板前的暂停状态(存档模式关闭时恢复)。
|
||||
#var _was_paused := false
|
||||
|
||||
func _on_SavePanel_Esc_ButtonUp() -> void:
|
||||
save_panel_esc_pressed.emit()
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_SavePanel_NewSlot_ButtonUp() -> void:
|
||||
pass # Replace with function body.
|
||||
@@ -0,0 +1 @@
|
||||
uid://dhh02xtieoq2s
|
||||
@@ -0,0 +1,72 @@
|
||||
[gd_scene format=3 uid="uid://cqdytnp2v07v"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dhh02xtieoq2s" path="res://src/UI/Panels/SavePannel.gd" id="1_lyly3"]
|
||||
[ext_resource type="Theme" uid="uid://btnjeju2d47x8" path="res://resources/save_menu_button_theme.tres" id="2_bgsuy"]
|
||||
[ext_resource type="LabelSettings" uid="uid://bn06sljdiloor" path="res://resources/save_menu_label_settings.tres" id="2_i6d4q"]
|
||||
|
||||
[node name="SavePannel" type="Panel" unique_id=1536921001]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_lyly3")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=56335316]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer" unique_id=718817298]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="VBoxContainer/HBoxContainer" unique_id=2128647553]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
text = "选择存档"
|
||||
label_settings = ExtResource("2_i6d4q")
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Spacer" type="Control" parent="VBoxContainer/HBoxContainer" unique_id=187185831]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 5.0
|
||||
|
||||
[node name="Button_NewSlot" type="Button" parent="VBoxContainer/HBoxContainer" unique_id=657984753]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme = ExtResource("2_bgsuy")
|
||||
text = "新建存档"
|
||||
|
||||
[node name="Button_Esc" type="Button" parent="VBoxContainer/HBoxContainer" unique_id=272892241]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme = ExtResource("2_bgsuy")
|
||||
text = "返回"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer" unique_id=520657017]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
size_flags_stretch_ratio = 15.0
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/ScrollContainer" unique_id=1858690088]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="GroupContainer" type="VBoxContainer" parent="VBoxContainer/ScrollContainer/HBoxContainer" unique_id=1215509679]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="SaveSlotList" type="VBoxContainer" parent="VBoxContainer/ScrollContainer/HBoxContainer" unique_id=1157397953]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[connection signal="button_up" from="VBoxContainer/HBoxContainer/Button_NewSlot" to="." method="_on_SavePanel_NewSlot_ButtonUp"]
|
||||
[connection signal="button_up" from="VBoxContainer/HBoxContainer/Button_Esc" to="." method="_on_SavePanel_Esc_ButtonUp"]
|
||||
@@ -0,0 +1 @@
|
||||
extends Panel
|
||||
@@ -0,0 +1 @@
|
||||
uid://b3kck4qod545u
|
||||
@@ -0,0 +1,55 @@
|
||||
[gd_scene format=3 uid="uid://d1fw0ofrshjir"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b3kck4qod545u" path="res://src/UI/Panels/SaveSlot.gd" id="1_gsy4a"]
|
||||
[ext_resource type="LabelSettings" uid="uid://bn06sljdiloor" path="res://resources/save_menu_label_settings.tres" id="2_lm8et"]
|
||||
[ext_resource type="Theme" uid="uid://btnjeju2d47x8" path="res://resources/save_menu_button_theme.tres" id="2_m8lv8"]
|
||||
|
||||
[node name="SaveSlot" type="Panel" unique_id=815772812]
|
||||
anchors_preset = 14
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_gsy4a")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=1394744552]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="SlotIndexLabel" type="Label" parent="HBoxContainer" unique_id=1779842797]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
label_settings = ExtResource("2_lm8et")
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer" unique_id=1166688104]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 15.0
|
||||
|
||||
[node name="SaveNameLabel" type="Label" parent="HBoxContainer/VBoxContainer" unique_id=391910928]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="SaveSlotInfo" type="Label" parent="HBoxContainer/VBoxContainer" unique_id=125642674]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ButtonDelete" type="Button" parent="HBoxContainer" unique_id=250829961]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme = ExtResource("2_m8lv8")
|
||||
text = "删除"
|
||||
|
||||
[node name="ButtonLoad" type="Button" parent="HBoxContainer" unique_id=1197277104]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme = ExtResource("2_m8lv8")
|
||||
text = "▶"
|
||||
Reference in New Issue
Block a user