添加代码

This commit is contained in:
milimoe 2025-04-14 21:54:29 +08:00
parent e2b95e4a0d
commit 3869861355
Signed by: milimoe
GPG Key ID: 05D280912DA6C69E
62 changed files with 5420 additions and 1 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Godot 4+ specific ignores
.godot/
/android/
assets/
.vs/

28
FunGame-Godot.csproj Normal file
View File

@ -0,0 +1,28 @@
<Project Sdk="Godot.NET.Sdk/4.4.1">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net8.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
<RootNamespace>Milimoe.GodotGame</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;IDE0130</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ExportDebug|AnyCPU'">
<NoWarn>1701;1702;IDE0130</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ExportRelease|AnyCPU'">
<NoWarn>1701;1702;IDE0130</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="novels\**" />
<EmbeddedResource Remove="novels\**" />
</ItemGroup>
<ItemGroup>
<None Include="scripts\.editorconfig" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FunGame.Core\FunGame.Core.csproj" />
</ItemGroup>
</Project>

33
FunGame-Godot.sln Normal file
View File

@ -0,0 +1,33 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35527.113 d17.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunGame-Godot", "FunGame-Godot.csproj", "{11453713-5BCC-49E5-829F-10A8AD8438AA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunGame.Core", "..\FunGame.Core\FunGame.Core.csproj", "{3566E2B2-160C-435E-871D-A9B9C158096C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{11453713-5BCC-49E5-829F-10A8AD8438AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11453713-5BCC-49E5-829F-10A8AD8438AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11453713-5BCC-49E5-829F-10A8AD8438AA}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{11453713-5BCC-49E5-829F-10A8AD8438AA}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{11453713-5BCC-49E5-829F-10A8AD8438AA}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{11453713-5BCC-49E5-829F-10A8AD8438AA}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
{3566E2B2-160C-435E-871D-A9B9C158096C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3566E2B2-160C-435E-871D-A9B9C158096C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3566E2B2-160C-435E-871D-A9B9C158096C}.ExportDebug|Any CPU.ActiveCfg = Debug|Any CPU
{3566E2B2-160C-435E-871D-A9B9C158096C}.ExportDebug|Any CPU.Build.0 = Debug|Any CPU
{3566E2B2-160C-435E-871D-A9B9C158096C}.ExportRelease|Any CPU.ActiveCfg = Release|Any CPU
{3566E2B2-160C-435E-871D-A9B9C158096C}.ExportRelease|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1 +1,3 @@
# FunGame.Godot
FunGame Godot 版源代码,不包含素材包文件。

278
export_presets.cfg Normal file
View File

@ -0,0 +1,278 @@
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../Build-Release/FunGame-Godot.exe"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.0.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=true
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PackedStringArray()
application/modify_resources=false
application/icon="res://icon.svg"
application/console_wrapper_icon=""
application/icon_interpolation=4
application/file_version=""
application/product_version=""
application/company_name="Milimoe"
application/product_name="FunGame"
application/file_description=""
application/copyright="Milimoe"
application/trademarks=""
application/export_angle=0
application/export_d3d12=0
application/d3d12_agility_sdk_multiarch=true
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
$settings = New-ScheduledTaskSettingsSet
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
Start-ScheduledTask -TaskName godot_remote_debug
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false
[preset.1]
name="Android"
platform="Android"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../Build-Release/FunGame-Godot.apk"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.1.options]
custom_template/debug=""
custom_template/release=""
gradle_build/use_gradle_build=false
gradle_build/gradle_build_directory=""
gradle_build/android_source_template=""
gradle_build/compress_native_libraries=false
gradle_build/export_format=0
gradle_build/min_sdk=""
gradle_build/target_sdk=""
architectures/armeabi-v7a=false
architectures/arm64-v8a=true
architectures/x86=false
architectures/x86_64=false
version/code=1
version/name="FunGame"
package/unique_name="com.milimoe.fungame"
package/name="FunGameGodot"
package/signed=true
package/app_category=2
package/retain_data_on_uninstall=false
package/exclude_from_recents=false
package/show_in_android_tv=false
package/show_in_app_library=true
package/show_as_launcher_app=false
launcher_icons/main_192x192=""
launcher_icons/adaptive_foreground_432x432=""
launcher_icons/adaptive_background_432x432=""
graphics/opengl_debug=false
xr_features/xr_mode=0
screen/immersive_mode=true
screen/support_small=true
screen/support_normal=true
screen/support_large=true
screen/support_xlarge=true
user_data_backup/allow=false
command_line/extra_args=""
apk_expansion/enable=false
apk_expansion/SALT=""
apk_expansion/public_key=""
permissions/custom_permissions=PackedStringArray()
permissions/access_checkin_properties=false
permissions/access_coarse_location=false
permissions/access_fine_location=false
permissions/access_location_extra_commands=false
permissions/access_mock_location=false
permissions/access_network_state=false
permissions/access_surface_flinger=false
permissions/access_wifi_state=false
permissions/account_manager=false
permissions/add_voicemail=false
permissions/authenticate_accounts=false
permissions/battery_stats=false
permissions/bind_accessibility_service=false
permissions/bind_appwidget=false
permissions/bind_device_admin=false
permissions/bind_input_method=false
permissions/bind_nfc_service=false
permissions/bind_notification_listener_service=false
permissions/bind_print_service=false
permissions/bind_remoteviews=false
permissions/bind_text_service=false
permissions/bind_vpn_service=false
permissions/bind_wallpaper=false
permissions/bluetooth=false
permissions/bluetooth_admin=false
permissions/bluetooth_privileged=false
permissions/brick=false
permissions/broadcast_package_removed=false
permissions/broadcast_sms=false
permissions/broadcast_sticky=false
permissions/broadcast_wap_push=false
permissions/call_phone=false
permissions/call_privileged=false
permissions/camera=false
permissions/capture_audio_output=false
permissions/capture_secure_video_output=false
permissions/capture_video_output=false
permissions/change_component_enabled_state=false
permissions/change_configuration=false
permissions/change_network_state=false
permissions/change_wifi_multicast_state=false
permissions/change_wifi_state=false
permissions/clear_app_cache=false
permissions/clear_app_user_data=false
permissions/control_location_updates=false
permissions/delete_cache_files=false
permissions/delete_packages=false
permissions/device_power=false
permissions/diagnostic=false
permissions/disable_keyguard=false
permissions/dump=false
permissions/expand_status_bar=false
permissions/factory_test=false
permissions/flashlight=false
permissions/force_back=false
permissions/get_accounts=false
permissions/get_package_size=false
permissions/get_tasks=false
permissions/get_top_activity_info=false
permissions/global_search=false
permissions/hardware_test=false
permissions/inject_events=false
permissions/install_location_provider=false
permissions/install_packages=false
permissions/install_shortcut=false
permissions/internal_system_window=false
permissions/internet=false
permissions/kill_background_processes=false
permissions/location_hardware=false
permissions/manage_accounts=false
permissions/manage_app_tokens=false
permissions/manage_documents=false
permissions/manage_external_storage=false
permissions/master_clear=false
permissions/media_content_control=false
permissions/modify_audio_settings=false
permissions/modify_phone_state=false
permissions/mount_format_filesystems=false
permissions/mount_unmount_filesystems=false
permissions/nfc=false
permissions/persistent_activity=false
permissions/post_notifications=false
permissions/process_outgoing_calls=false
permissions/read_calendar=false
permissions/read_call_log=false
permissions/read_contacts=false
permissions/read_external_storage=false
permissions/read_frame_buffer=false
permissions/read_history_bookmarks=false
permissions/read_input_state=false
permissions/read_logs=false
permissions/read_phone_state=false
permissions/read_profile=false
permissions/read_sms=false
permissions/read_social_stream=false
permissions/read_sync_settings=false
permissions/read_sync_stats=false
permissions/read_user_dictionary=false
permissions/reboot=false
permissions/receive_boot_completed=false
permissions/receive_mms=false
permissions/receive_sms=false
permissions/receive_wap_push=false
permissions/record_audio=false
permissions/reorder_tasks=false
permissions/restart_packages=false
permissions/send_respond_via_message=false
permissions/send_sms=false
permissions/set_activity_watcher=false
permissions/set_alarm=false
permissions/set_always_finish=false
permissions/set_animation_scale=false
permissions/set_debug_app=false
permissions/set_orientation=false
permissions/set_pointer_speed=false
permissions/set_preferred_applications=false
permissions/set_process_limit=false
permissions/set_time=false
permissions/set_time_zone=false
permissions/set_wallpaper=false
permissions/set_wallpaper_hints=false
permissions/signal_persistent_processes=false
permissions/status_bar=false
permissions/subscribed_feeds_read=false
permissions/subscribed_feeds_write=false
permissions/system_alert_window=false
permissions/transmit_ir=false
permissions/uninstall_shortcut=false
permissions/update_device_stats=false
permissions/use_credentials=false
permissions/use_sip=false
permissions/vibrate=false
permissions/wake_lock=false
permissions/write_apn_settings=false
permissions/write_calendar=false
permissions/write_call_log=false
permissions/write_contacts=false
permissions/write_external_storage=false
permissions/write_gservices=false
permissions/write_history_bookmarks=false
permissions/write_profile=false
permissions/write_secure_settings=false
permissions/write_settings=false
permissions/write_sms=false
permissions/write_social_stream=false
permissions/write_sync_settings=false
permissions/write_user_dictionary=false
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false

1
icon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 994 B

37
icon.svg.import Normal file
View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bt3hbaeylmp4w"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

47
project.godot Normal file
View File

@ -0,0 +1,47 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="FunGame-Godot"
run/main_scene="res://scenes/SplashScreen.tscn"
config/features=PackedStringArray("4.4", "C#", "GL Compatibility")
boot_splash/bg_color=Color(1, 1, 1, 1)
boot_splash/show_image=false
config/icon="res://icon.svg"
[display]
window/size/viewport_width=1280
window/size/viewport_height=720
window/size/resizable=false
window/size/borderless=true
window/stretch/mode="viewport"
window/stretch/scale_mode="integer"
[dotnet]
project/assembly_name="FunGame-Godot"
[editor]
movie_writer/movie_file="C:/milimoe/GameRecords/GodotGame.avi"
[importer_defaults]
animation_library={
"animation/fps": 60.0
}
[rendering]
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
textures/vram_compression/import_etc2_astc=true

View File

@ -0,0 +1,240 @@
{
"1": {
"Key": "1",
"Priority": 0,
"NextNodes": [],
"Options": [
{
"Key": "1-1",
"Name": "我是弗利伯格·cy1·推斯特贼贼·NiKoの趣事·device·玩机器。",
"Targets": [
"2"
]
},
{
"Key": "1-2",
"Name": "我是雷恩。",
"Targets": [
"3"
]
}
],
"Name": "艾琳",
"Content": "你是谁?",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"2": {
"Key": "2",
"Priority": 0,
"NextNodes": [
"3"
],
"Name": "艾琳",
"Content": "喔 是吗?我不认可。\n请告诉我你的真实名字。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"3": {
"Key": "3",
"Priority": 0,
"NextNodes": [
"4"
],
"Name": "艾琳",
"Content": "雷恩啊……很高兴认识你。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"4": {
"Key": "4",
"Priority": 0,
"NextNodes": [
"5"
],
"Name": "艾琳",
"Content": "谢谢你救了我。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"5": {
"Key": "5",
"Priority": 0,
"NextNodes": [
"6"
],
"Name": "雷恩",
"Content": "为什么……你会被那些魔物追杀?",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"6": {
"Key": "6",
"Priority": 0,
"NextNodes": [
"7"
],
"Name": "",
"Content": "……艾琳告诉了你事情的经过。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"7": {
"Key": "7",
"Priority": 0,
"NextNodes": [
"8"
],
"Name": "艾琳",
"Content": "我……我来自一个遥远的村庄,\n那里的人们拥有特殊的力量但也被魔物觊觎。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"8": {
"Key": "8",
"Priority": 0,
"NextNodes": [
"9"
],
"Name": "雷恩",
"Content": "特殊的力量?什么样的力量?",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"9": {
"Key": "9",
"Priority": 0,
"NextNodes": [
"10"
],
"Name": "艾琳",
"Content": "我们能够与自然沟通,操控元素。\n而魔物被力量吸引想要夺取我们的力量。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"10": {
"Key": "10",
"Priority": 0,
"NextNodes": [
"11"
],
"Name": "雷恩",
"Content": "所以你逃了出来?",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"11": {
"Key": "11",
"Priority": 0,
"NextNodes": [
"12"
],
"Name": "艾琳",
"Content": "是的,我逃了出来。但我的村庄……",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"12": {
"Key": "12",
"Priority": 0,
"NextNodes": [
"13"
],
"Name": "雷恩",
"Content": "你的村庄怎么了?",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"13": {
"Key": "13",
"Priority": 0,
"NextNodes": [],
"Options": [
{
"Key": "13-1",
"Name": "安慰她。",
"Targets": [
"14"
]
},
{
"Key": "13-2",
"Name": "询问更多细节。",
"Targets": [
"15"
]
}
],
"Name": "艾琳",
"Content": "……我不知道。我只希望他们还安全。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"14": {
"Key": "14",
"Priority": 0,
"NextNodes": [
"18"
],
"Name": "雷恩",
"Content": "别担心,我会帮助你找到你的村庄,并确保他们安全。",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"15": {
"Key": "15",
"Priority": 0,
"NextNodes": [
"16"
],
"Name": "雷恩",
"Content": "你能告诉我更多关于你村庄的信息吗?\n例如它在哪里或者有什么特别的标志",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"16": {
"Key": "16",
"Priority": 0,
"NextNodes": [
"17"
],
"Name": "艾琳",
"Content": "我的村庄位于森林深处。\n那里有一棵古树树上刻着村庄的图腾。",
"PortraitImagePath": "res://assets/character/艾琳.png"
},
"17": {
"Key": "17",
"Priority": 0,
"NextNodes": [
"18"
],
"Name": "雷恩",
"Content": "古老的森林……\n我知道一个地方也许那就是你说的森林。",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"18": {
"Key": "18",
"Priority": 0,
"NextNodes": [],
"Options": [
{
"Key": "18-1",
"Name": "我们现在就出发。",
"Targets": [
"19"
]
},
{
"Key": "18-2",
"Name": "先休息一下再出发。",
"Targets": [
"20"
]
}
],
"Name": "雷恩",
"Content": "我们现在怎么办?",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"19": {
"Key": "19",
"Priority": 0,
"NextNodes": [],
"Name": "雷恩",
"Content": "好吧,我们现在就出发!",
"PortraitImagePath": "res://assets/character/雷恩.png"
},
"20": {
"Key": "20",
"Priority": 0,
"NextNodes": [],
"Name": "雷恩",
"Content": "我们先休息一下,明天再出发吧。",
"PortraitImagePath": "res://assets/character/雷恩.png"
}
}

View File

@ -0,0 +1,7 @@
[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://b3h4w1jmyijkt"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_my4h2"]
[resource]
font = ExtResource("1_my4h2")
font_size = 24

View File

@ -0,0 +1,16 @@
[gd_resource type="Theme" load_steps=3 format=3 uid="uid://d1gp4l4cwgtw4"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_qn7vl"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ig2yt"]
bg_color = Color(0.6, 0.6, 0.6, 0)
border_color = Color(0.8, 0.8, 0.8, 0)
[resource]
default_font = ExtResource("1_qn7vl")
default_font_size = 32
Button/colors/font_color = Color(0.219588, 0.0827059, 0.254825, 1)
Button/colors/font_focus_color = Color(0.219608, 0.0823529, 0.254902, 1)
Button/colors/font_hover_color = Color(0.491785, 0.118317, 0.344885, 1)
Button/colors/font_pressed_color = Color(0.560784, 0.2, 0.568627, 1)
Button/styles/focus = SubResource("StyleBoxFlat_ig2yt")

View File

@ -0,0 +1,7 @@
[gd_resource type="Theme" load_steps=2 format=3 uid="uid://d0pi6io7y7tky"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_x2o6a"]
[resource]
default_font = ExtResource("1_x2o6a")
default_font_size = 24

View File

@ -0,0 +1,28 @@
[gd_resource type="Theme" load_steps=6 format=3 uid="uid://bi5n6j6qn74xi"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_74oji"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g0ilb"]
bg_color = Color(0.619608, 0.556863, 0.784314, 0.317647)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_74oji"]
bg_color = Color(0.619608, 0.556863, 0.784314, 0.317647)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0ue46"]
bg_color = Color(0.619608, 0.556863, 0.784314, 0.317647)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_f01gi"]
bg_color = Color(0.621262, 0.558113, 0.782392, 0.317647)
[resource]
default_font = ExtResource("1_74oji")
default_font_size = 36
Button/colors/font_color = Color(0.219608, 0.0823529, 0.254902, 1)
Button/colors/font_focus_color = Color(0.219608, 0.0823529, 0.254902, 1)
Button/colors/font_hover_color = Color(0.962767, 0.668492, 1, 1)
Button/colors/font_hover_pressed_color = Color(0.962767, 0.668492, 1, 1)
Button/colors/font_pressed_color = Color(0.219608, 0.0823529, 0.254902, 1)
Button/styles/focus = SubResource("StyleBoxFlat_g0ilb")
Button/styles/hover = SubResource("StyleBoxFlat_74oji")
Button/styles/hover_pressed = SubResource("StyleBoxFlat_0ue46")
Button/styles/normal = SubResource("StyleBoxFlat_f01gi")

View File

@ -0,0 +1,16 @@
[gd_resource type="Theme" load_steps=3 format=3 uid="uid://cc3c0kkawa67y"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_f2lmy"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_f2lmy"]
bg_color = Color(0.979537, 0.857103, 0.86027, 0.784314)
[resource]
default_font = ExtResource("1_f2lmy")
default_font_size = 16
Button/colors/font_color = Color(0.978118, 0.835541, 0.839506, 1)
Button/colors/font_focus_color = Color(0.930652, 0.271242, 0.578928, 1)
Button/colors/font_hover_color = Color(0.917647, 0.521569, 0.639216, 1)
Button/colors/font_hover_pressed_color = Color(0.917647, 0.521569, 0.639216, 1)
Button/colors/font_pressed_color = Color(0.930652, 0.271242, 0.578928, 1)
Button/styles/pressed = SubResource("StyleBoxFlat_f2lmy")

View File

@ -0,0 +1,7 @@
[gd_resource type="Theme" load_steps=2 format=3 uid="uid://dtn33cy1yub47"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_5i6gt"]
[resource]
default_font = ExtResource("1_5i6gt")
default_font_size = 48

View File

@ -0,0 +1,81 @@
[gd_resource type="Theme" load_steps=7 format=3 uid="uid://clwk8wh5003m8"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_ul7ps"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_jibf8"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0.1, 0.1, 0.1, 0.3)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
corner_detail = 5
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1n1tr"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(1, 1, 1, 0.75)
draw_center = false
border_width_left = 2
border_width_top = 2
border_width_right = 2
border_width_bottom = 2
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
corner_detail = 5
expand_margin_left = 2.0
expand_margin_top = 2.0
expand_margin_right = 2.0
expand_margin_bottom = 2.0
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_evjqp"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0.225, 0.225, 0.225, 0.6)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
corner_detail = 5
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6tvex"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0.1, 0.1, 0.1, 0.6)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
corner_detail = 5
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_034k8"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0, 0, 0, 0.6)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
corner_detail = 5
[resource]
default_font = ExtResource("1_ul7ps")
default_font_size = 32
Button/styles/disabled = SubResource("StyleBoxFlat_jibf8")
Button/styles/focus = SubResource("StyleBoxFlat_1n1tr")
Button/styles/hover = SubResource("StyleBoxFlat_evjqp")
Button/styles/normal = SubResource("StyleBoxFlat_6tvex")
Button/styles/pressed = SubResource("StyleBoxFlat_034k8")

View File

@ -0,0 +1,27 @@
[gd_resource type="Theme" load_steps=4 format=3 uid="uid://bs3813xiv8ivn"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_edkmk"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mjtl5"]
bg_color = Color(0.6, 0.6, 0.6, 0.588235)
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color(0.219608, 0.0823529, 0.254902, 1)
border_blend = true
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_j4r45"]
bg_color = Color(0.6, 0.6, 0.6, 0.666667)
border_width_left = 8
border_width_top = 8
border_width_right = 8
border_width_bottom = 8
border_color = Color(0.219608, 0.0823529, 0.254902, 1)
border_blend = true
[resource]
default_font = ExtResource("1_edkmk")
default_font_size = 24
Panel/styles/panel = SubResource("StyleBoxFlat_mjtl5")
PanelContainer/styles/panel = SubResource("StyleBoxFlat_j4r45")

View File

@ -0,0 +1,100 @@
[gd_scene load_steps=7 format=3 uid="uid://boa4gvdodn6is"]
[ext_resource type="Theme" uid="uid://d0pi6io7y7tky" path="res://resources/themes/dialog.tres" id="1_21m4e"]
[ext_resource type="Theme" uid="uid://d1gp4l4cwgtw4" path="res://resources/themes/button.tres" id="2_jet3t"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dugby"]
bg_color = Color(0.6, 0.6, 0.6, 0)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_jet3t"]
bg_color = Color(0, 0.715563, 0.406543, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cnh2t"]
bg_color = Color(0.360998, 0.609236, 0.919164, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_arpqe"]
bg_color = Color(0.879745, 0.48415, 7.70092e-07, 1)
[node name="CharacterStatus" type="Panel"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_right = -88.0
offset_bottom = -368.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_dugby")
[node name="Image" type="TextureRect" parent="."]
layout_mode = 1
offset_right = 320.0
offset_bottom = 320.0
[node name="HPBar" type="ProgressBar" parent="."]
layout_mode = 1
offset_left = 352.0
offset_top = 64.0
offset_right = 1152.0
offset_bottom = 128.0
theme = ExtResource("1_21m4e")
theme_override_styles/fill = SubResource("StyleBoxFlat_jet3t")
value = 70.0
show_percentage = false
[node name="MPBar" type="ProgressBar" parent="."]
layout_mode = 1
offset_left = 352.0
offset_top = 160.0
offset_right = 1152.0
offset_bottom = 224.0
theme = ExtResource("1_21m4e")
theme_override_styles/fill = SubResource("StyleBoxFlat_cnh2t")
value = 30.0
show_percentage = false
[node name="EPBar" type="ProgressBar" parent="."]
layout_mode = 1
offset_left = 352.0
offset_top = 256.0
offset_right = 1152.0
offset_bottom = 320.0
theme = ExtResource("1_21m4e")
theme_override_styles/fill = SubResource("StyleBoxFlat_arpqe")
value = 10.0
show_percentage = false
[node name="HP" type="Label" parent="."]
layout_mode = 1
offset_left = 352.0
offset_top = 64.0
offset_right = 1152.0
offset_bottom = 128.0
theme = ExtResource("2_jet3t")
theme_override_colors/font_color = Color(0, 0.715563, 0.406543, 1)
text = "17110"
horizontal_alignment = 2
vertical_alignment = 1
[node name="MP" type="Label" parent="."]
layout_mode = 1
offset_left = 352.0
offset_top = 160.0
offset_right = 1152.0
offset_bottom = 224.0
theme = ExtResource("2_jet3t")
theme_override_colors/font_color = Color(0.360998, 0.609236, 0.919164, 1)
text = "7945"
horizontal_alignment = 2
vertical_alignment = 1
[node name="EP" type="Label" parent="."]
layout_mode = 1
offset_left = 352.0
offset_top = 256.0
offset_right = 1152.0
offset_bottom = 320.0
theme = ExtResource("2_jet3t")
theme_override_colors/font_color = Color(0.879745, 0.48415, 7.70092e-07, 1)
text = "15"
horizontal_alignment = 2
vertical_alignment = 1

203
resources/ui/Novel.tscn Normal file
View File

@ -0,0 +1,203 @@
[gd_scene load_steps=11 format=3 uid="uid://exqgca0e7vay"]
[ext_resource type="Script" uid="uid://cgcdu4cg7u28g" path="res://scripts/NovelController.cs" id="1_0tl37"]
[ext_resource type="Texture2D" uid="uid://0dkwmsresstm" path="res://assets/character/艾琳.png" id="1_af382"]
[ext_resource type="Theme" uid="uid://d1gp4l4cwgtw4" path="res://resources/themes/button.tres" id="1_df34q"]
[ext_resource type="Theme" uid="uid://bs3813xiv8ivn" path="res://resources/themes/panel.tres" id="1_fmroo"]
[ext_resource type="Texture2D" uid="uid://biooen7y20ks8" path="res://assets/character/雷恩.png" id="1_u842g"]
[ext_resource type="Theme" uid="uid://dtn33cy1yub47" path="res://resources/themes/noveldialog.tres" id="4_o8h6h"]
[ext_resource type="Theme" uid="uid://clwk8wh5003m8" path="res://resources/themes/option.tres" id="5_b05s4"]
[ext_resource type="Script" uid="uid://c4ny5p54lotj0" path="res://scripts/AnimatedRichTextLabel.cs" id="7_vvt2q"]
[ext_resource type="Theme" uid="uid://cc3c0kkawa67y" path="res://resources/themes/novelbutton.tres" id="9_bp2jl"]
[ext_resource type="PackedScene" uid="uid://b25umg4d0y13" path="res://resources/ui/SavedSelection.tscn" id="10_sk065"]
[node name="Novel" type="CanvasLayer" node_paths=PackedStringArray("SavedSelection")]
script = ExtResource("1_0tl37")
SavedSelection = NodePath("SavedSelection")
[node name="立绘1" type="TextureRect" parent="."]
offset_left = 451.0
offset_right = 899.0
offset_bottom = 720.0
metadata/_edit_lock_ = true
[node name="Image" type="TextureRect" parent="立绘1"]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -360.0
offset_top = -360.0
offset_right = 360.0
offset_bottom = 360.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("1_u842g")
expand_mode = 2
[node name="立绘2左" type="TextureRect" parent="."]
offset_left = 131.0
offset_right = 579.0
offset_bottom = 720.0
metadata/_edit_lock_ = true
[node name="Image" type="TextureRect" parent="立绘2左"]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -360.0
offset_top = -360.0
offset_right = 360.0
offset_bottom = 360.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("1_u842g")
expand_mode = 2
[node name="立绘2右" type="TextureRect" parent="."]
offset_left = 707.0
offset_right = 1155.0
offset_bottom = 720.0
metadata/_edit_lock_ = true
[node name="Image" type="TextureRect" parent="立绘2右"]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -360.0
offset_top = -360.0
offset_right = 360.0
offset_bottom = 360.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("1_af382")
expand_mode = 2
[node name="Panel" type="Panel" parent="."]
offset_top = 512.0
offset_right = 1280.0
offset_bottom = 720.0
theme = ExtResource("1_fmroo")
metadata/_edit_lock_ = true
[node name="NamePanel" type="Panel" parent="Panel"]
layout_mode = 0
offset_top = -64.0
offset_right = 256.0
theme = ExtResource("1_fmroo")
metadata/_edit_lock_ = true
[node name="Name" type="Label" parent="Panel/NamePanel"]
layout_mode = 0
offset_right = 256.0
offset_bottom = 64.0
theme = ExtResource("1_df34q")
text = "说话的人名"
horizontal_alignment = 1
vertical_alignment = 1
metadata/_edit_lock_ = true
[node name="Content" type="RichTextLabel" parent="Panel"]
layout_mode = 0
offset_left = 64.0
offset_top = 24.0
offset_right = 1216.0
offset_bottom = 176.0
theme = ExtResource("4_o8h6h")
bbcode_enabled = true
text = "这是说话的内容。。。
行2测试。 "
scroll_active = false
autowrap_mode = 0
script = ExtResource("7_vvt2q")
metadata/_edit_lock_ = true
[node name="Timer" type="Timer" parent="Panel/Content"]
[node name="透明挡板" type="ColorRect" parent="."]
offset_right = 1280.0
offset_bottom = 720.0
color = Color(1, 1, 1, 0)
metadata/_edit_lock_ = true
[node name="选项框" type="VBoxContainer" parent="."]
anchors_preset = -1
anchor_left = 1.0
anchor_top = 0.704
anchor_right = 1.0
anchor_bottom = 0.704
offset_left = -384.0
offset_top = -319.88
offset_bottom = 0.119965
grow_horizontal = 0
grow_vertical = 0
size_flags_horizontal = 8
alignment = 2
metadata/_edit_use_anchors_ = true
metadata/_edit_lock_ = true
[node name="Button3" type="Button" parent="选项框"]
layout_mode = 2
theme = ExtResource("5_b05s4")
text = "选项三"
icon_alignment = 1
[node name="Button2" type="Button" parent="选项框"]
layout_mode = 2
theme = ExtResource("5_b05s4")
text = "选项二"
icon_alignment = 1
[node name="Button1" type="Button" parent="选项框"]
layout_mode = 2
theme = ExtResource("5_b05s4")
text = "选项一"
icon_alignment = 1
[node name="自动播放" type="Button" parent="."]
offset_left = 1208.0
offset_top = 528.0
offset_right = 1256.0
offset_bottom = 560.0
theme = ExtResource("9_bp2jl")
toggle_mode = true
text = "自动"
[node name="读取存档" type="Button" parent="."]
offset_left = 1208.0
offset_top = 576.0
offset_right = 1256.0
offset_bottom = 608.0
theme = ExtResource("9_bp2jl")
text = "读档"
[node name="保存存档" type="Button" parent="."]
offset_left = 1208.0
offset_top = 624.0
offset_right = 1256.0
offset_bottom = 656.0
theme = ExtResource("9_bp2jl")
text = "存档"
[node name="游戏菜单" type="Button" parent="."]
offset_left = 1208.0
offset_top = 672.0
offset_right = 1256.0
offset_bottom = 704.0
theme = ExtResource("9_bp2jl")
text = "菜单"
[node name="SavedSelection" parent="." node_paths=PackedStringArray("Parent") instance=ExtResource("10_sk065")]
visible = false
Parent = NodePath("..")

26
resources/ui/Rayne.tscn Normal file
View File

@ -0,0 +1,26 @@
[gd_scene load_steps=4 format=3 uid="uid://dj16n8yvwwgr7"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_dg3fm"]
[ext_resource type="Texture2D" uid="uid://dbyovpk0xc6jo" path="res://assets/character/2D雷恩.png" id="2_xfrxc"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_s5ben"]
bg_color = Color(0, 0.701961, 0.54902, 0.784314)
[node name="Rayne" type="CharacterBody2D"]
[node name="ProgressBar" type="ProgressBar" parent="."]
visible = false
offset_left = -592.0
offset_top = -728.0
offset_right = 618.0
offset_bottom = -576.0
theme_override_fonts/font = ExtResource("1_dg3fm")
theme_override_font_sizes/font_size = 48
theme_override_styles/fill = SubResource("StyleBoxFlat_s5ben")
value = 100.0
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="."]
polygon = PackedVector2Array(0, 0, 0, 440, 160, 440, 320, 360, 320, 160, 280, 40, 200, 0, 240, -80, 280, -80, 320, -120, 320, -280, 280, -400, 160, -520, -40, -520, -160, -440, -240, -320, -240, -160, -360, 0, -360, 200, -280, 240, -240, 360, -200, 440, 0, 440)
[node name="Sprite2D" type="Sprite2D" parent="CollisionPolygon2D"]
texture = ExtResource("2_xfrxc")

View File

@ -0,0 +1,79 @@
[gd_scene load_steps=5 format=3 uid="uid://bds4gw3kdxsa1"]
[ext_resource type="LabelSettings" uid="uid://b3h4w1jmyijkt" path="res://resources/themes/Label.tres" id="1_ckjip"]
[ext_resource type="Theme" uid="uid://bs3813xiv8ivn" path="res://resources/themes/panel.tres" id="1_yor01"]
[ext_resource type="Script" uid="uid://yb8nssj7d04f" path="res://scripts/SavedSelection/SavedNode.cs" id="2_fj806"]
[ext_resource type="Theme" uid="uid://d0pi6io7y7tky" path="res://resources/themes/dialog.tres" id="4_bsuih"]
[node name="SavedNode" type="PanelContainer" node_paths=PackedStringArray("Button", "SaveDialog", "LoadDialog", "SavedName", "SavedTime", "ChapterInGame", "AreaInGame")]
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -316.0
offset_top = -45.5
offset_right = 316.0
offset_bottom = 45.5
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme = ExtResource("1_yor01")
script = ExtResource("2_fj806")
Button = NodePath("Button")
SaveDialog = NodePath("Save?")
LoadDialog = NodePath("Load?")
SavedName = NodePath("MarginContainer/SavedName")
SavedTime = NodePath("MarginContainer/SavedTime")
ChapterInGame = NodePath("MarginContainer/ChapterInGame")
AreaInGame = NodePath("MarginContainer/AreaInGame")
[node name="MarginContainer" type="GridContainer" parent="."]
layout_mode = 2
theme = ExtResource("1_yor01")
columns = 2
[node name="SavedName" type="Label" parent="MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "存档名"
label_settings = ExtResource("1_ckjip")
vertical_alignment = 1
[node name="SavedTime" type="Label" parent="MarginContainer"]
layout_mode = 2
text = "保存时间2025年2月23日19:57:27"
label_settings = ExtResource("1_ckjip")
vertical_alignment = 1
[node name="ChapterInGame" type="Label" parent="MarginContainer"]
layout_mode = 2
text = "章节"
label_settings = ExtResource("1_ckjip")
vertical_alignment = 1
[node name="AreaInGame" type="Label" parent="MarginContainer"]
layout_mode = 2
text = "存档地点"
label_settings = ExtResource("1_ckjip")
vertical_alignment = 1
[node name="Button" type="Button" parent="."]
layout_mode = 2
flat = true
[node name="Load?" type="ConfirmationDialog" parent="."]
title = "加载存档"
theme = ExtResource("4_bsuih")
ok_button_text = "是"
dialog_text = "加载这个存档?"
cancel_button_text = "否"
[node name="Save?" type="ConfirmationDialog" parent="."]
auto_translate_mode = 1
title = "保存存档"
theme = ExtResource("4_bsuih")
ok_button_text = "是"
dialog_text = "保存到这个位置吗?"
cancel_button_text = "否"

View File

@ -0,0 +1,166 @@
[gd_scene load_steps=9 format=3 uid="uid://b25umg4d0y13"]
[ext_resource type="Script" uid="uid://djcq2jgoaism" path="res://scripts/SavedSelection/SavedSelection.cs" id="1_3af8h"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="1_h4xw3"]
[ext_resource type="PackedScene" uid="uid://bds4gw3kdxsa1" path="res://resources/ui/SavedNode.tscn" id="2_pb2kw"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ub0h0"]
bg_color = Color(1, 1, 1, 0.470588)
shadow_color = Color(0.917647, 0.521569, 0.639216, 0.470588)
shadow_size = 5
[sub_resource type="Animation" id="Animation_keguw"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(0, -936)]
}
[sub_resource type="Animation" id="Animation_02gau"]
resource_name = "flyin"
length = 0.3
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.3),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(0, -936), Vector2(0, 0)]
}
[sub_resource type="Animation" id="Animation_d4ukt"]
resource_name = "flyout"
length = 0.3
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.3),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(0, 0), Vector2(0, -936)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_p1rrd"]
_data = {
&"RESET": SubResource("Animation_keguw"),
&"flyin": SubResource("Animation_02gau"),
&"flyout": SubResource("Animation_d4ukt")
}
[node name="SavedSelection" type="CanvasLayer"]
script = ExtResource("1_3af8h")
[node name="ColorRect" type="ColorRect" parent="."]
offset_right = 1280.0
offset_bottom = 720.0
color = Color(1, 1, 1, 0)
metadata/_edit_lock_ = true
[node name="Label" type="Label" parent="ColorRect"]
layout_mode = 0
offset_left = 128.0
offset_right = 1152.0
offset_bottom = 92.0
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_outline_size = 3
theme_override_fonts/font = ExtResource("1_h4xw3")
theme_override_font_sizes/font_size = 56
text = "选择一个存档"
horizontal_alignment = 1
vertical_alignment = 1
metadata/_edit_lock_ = true
[node name="Panel" type="Panel" parent="ColorRect"]
layout_mode = 0
offset_left = 128.0
offset_top = 92.0
offset_right = 1152.0
offset_bottom = 704.0
theme_override_styles/panel = SubResource("StyleBoxFlat_ub0h0")
metadata/_edit_lock_ = true
[node name="ScrollContainer" type="ScrollContainer" parent="ColorRect"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -512.0
offset_top = -268.0
offset_right = 524.0
offset_bottom = 343.0
grow_horizontal = 2
grow_vertical = 2
metadata/_edit_lock_ = true
[node name="VBoxContainer" type="VBoxContainer" parent="ColorRect/ScrollContainer"]
clip_contents = true
custom_minimum_size = Vector2(1024, 576)
layout_mode = 2
metadata/_edit_lock_ = true
[node name="AutoSavedNode" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 0
IsAuto = true
[node name="SavedNode1" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
[node name="SavedNode2" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 2
[node name="SavedNode3" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 3
[node name="SavedNode4" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 4
[node name="SavedNode5" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 5
[node name="SavedNode6" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 6
[node name="SavedNode7" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 7
[node name="SavedNode8" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 8
[node name="SavedNode9" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 9
[node name="SavedNode10" parent="ColorRect/ScrollContainer/VBoxContainer" instance=ExtResource("2_pb2kw")]
layout_mode = 2
Index = 10
[node name="AnimationPlayer" type="AnimationPlayer" parent="ColorRect"]
libraries = {
&"": SubResource("AnimationLibrary_p1rrd")
}

View File

@ -0,0 +1,43 @@
[gd_scene load_steps=4 format=3 uid="uid://dewev77kmbwre"]
[ext_resource type="Theme" uid="uid://d1gp4l4cwgtw4" path="res://resources/themes/button.tres" id="1_r31ah"]
[ext_resource type="PackedScene" uid="uid://boa4gvdodn6is" path="res://resources/ui/CharacterStatus.tscn" id="2_infd8"]
[ext_resource type="Script" uid="uid://bc5cucvklcmrd" path="res://scripts/UserInterface.cs" id="3_mwlxn"]
[node name="UserInterface" type="Control" node_paths=PackedStringArray("CharacterStatus1", "CharacterStatus2")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("3_mwlxn")
CharacterStatus1 = NodePath("CharacterStatus")
CharacterStatus2 = NodePath("CharacterStatus2")
metadata/_edit_lock_ = true
[node name="Label" type="Label" parent="."]
layout_mode = 0
offset_right = 448.0
offset_bottom = 72.0
theme = ExtResource("1_r31ah")
text = "当前位置"
horizontal_alignment = 1
vertical_alignment = 1
[node name="CharacterStatus" parent="." instance=ExtResource("2_infd8")]
visible = false
layout_mode = 1
offset_top = 648.0
offset_right = -85.0
offset_bottom = 269.0
scale = Vector2(0.2, 0.2)
[node name="CharacterStatus2" parent="." instance=ExtResource("2_infd8")]
visible = false
layout_mode = 1
offset_left = 240.0
offset_top = 648.0
offset_right = 155.0
offset_bottom = 269.0
scale = Vector2(0.2, 0.2)

111
resources/ui/menu.tscn Normal file
View File

@ -0,0 +1,111 @@
[gd_scene load_steps=5 format=3 uid="uid://l0twf4e20yas"]
[ext_resource type="Texture2D" uid="uid://cy8hsxd2nn0i8" path="res://assets/EclipticSonataLogo.png" id="1_82ouh"]
[ext_resource type="Script" uid="uid://c0hp2amidehe0" path="res://scripts/MenuController.cs" id="1_f01gi"]
[ext_resource type="Theme" uid="uid://bi5n6j6qn74xi" path="res://resources/themes/menubutton.tres" id="2_82ouh"]
[ext_resource type="Theme" uid="uid://d0pi6io7y7tky" path="res://resources/themes/dialog.tres" id="4_w85t6"]
[node name="Menu" type="ColorRect" node_paths=PackedStringArray("ContinueGame", "GameSettings", "BackToTitle", "ExitGame", "ExitConfirmationDialog", "BackToTitleConfirmationDialog")]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(1, 1, 1, 0.392157)
script = ExtResource("1_f01gi")
ContinueGame = NodePath("继续游戏")
GameSettings = NodePath("游戏设置")
BackToTitle = NodePath("返回标题")
ExitGame = NodePath("结束游戏")
ExitConfirmationDialog = NodePath("ExitGame?")
BackToTitleConfirmationDialog = NodePath("BackToTitle?")
metadata/_edit_lock_ = true
[node name="TextureRect" type="TextureRect" parent="."]
layout_mode = 0
offset_left = 203.0
offset_top = 8.0
offset_right = 1079.0
offset_bottom = 338.0
texture = ExtResource("1_82ouh")
metadata/_edit_lock_ = true
[node name="继续游戏" type="Button" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -86.0
offset_top = 48.5
offset_right = 86.0
offset_bottom = 101.5
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2_82ouh")
text = "继续游戏"
[node name="游戏设置" type="Button" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -86.0
offset_top = 111.5
offset_right = 86.0
offset_bottom = 164.5
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2_82ouh")
text = "游戏设置"
[node name="返回标题" type="Button" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -86.0
offset_top = 176.5
offset_right = 86.0
offset_bottom = 229.5
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2_82ouh")
text = "返回标题"
[node name="结束游戏" type="Button" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -86.0
offset_top = 240.5
offset_right = 86.0
offset_bottom = 293.5
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2_82ouh")
text = "结束游戏"
[node name="ExitGame?" type="ConfirmationDialog" parent="."]
auto_translate_mode = 1
title = "提示"
theme = ExtResource("4_w85t6")
ok_button_text = "是"
dialog_text = "是否退出游戏?未保存的内容将丢失。"
cancel_button_text = "否"
[node name="BackToTitle?" type="ConfirmationDialog" parent="."]
auto_translate_mode = 1
title = "提示"
theme = ExtResource("4_w85t6")
ok_button_text = "是"
dialog_text = "返回标题界面?未保存的内容将丢失。"
cancel_button_text = "否"

73
scenes/SplashScreen.tscn Normal file
View File

@ -0,0 +1,73 @@
[gd_scene load_steps=5 format=3 uid="uid://dhvw4k0vyu1aa"]
[ext_resource type="Texture2D" uid="uid://dsuuk4kdoevn3" path="res://assets/raincandy.png" id="1_8ukic"]
[ext_resource type="Script" uid="uid://dbyq6vgnnib7w" path="res://scripts/SplashScreen.cs" id="1_v5ida"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="3_jobkp"]
[ext_resource type="Texture2D" uid="uid://b7mtjukcndwbc" path="res://assets/logo_large_color_light.png" id="5_s88rl"]
[node name="SplashScreen" type="CanvasLayer" node_paths=PackedStringArray("GodotLogo", "Logo", "Label")]
script = ExtResource("1_v5ida")
GodotLogo = NodePath("Godot")
Logo = NodePath("Raincandy")
Label = NodePath("Raincandy/Milimoe")
[node name="ColorRect" type="ColorRect" parent="."]
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -640.0
offset_top = -360.0
offset_right = 640.0
offset_bottom = 360.0
grow_horizontal = 2
grow_vertical = 2
metadata/_edit_lock_ = true
[node name="Raincandy" type="TextureRect" parent="."]
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -290.5
offset_right = 290.5
offset_bottom = 581.0
grow_horizontal = 2
size_flags_horizontal = 4
texture = ExtResource("1_8ukic")
metadata/_edit_lock_ = true
[node name="Milimoe" type="Label" parent="Raincandy"]
layout_mode = 1
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -313.0
offset_top = -102.0
offset_right = 335.0
offset_bottom = 26.0
grow_horizontal = 2
grow_vertical = 0
theme_override_colors/font_color = Color(0.940591, 0.290397, 0.55787, 1)
theme_override_fonts/font = ExtResource("3_jobkp")
theme_override_font_sizes/font_size = 50
text = "Milimoe Presents"
horizontal_alignment = 1
vertical_alignment = 1
metadata/_edit_lock_ = true
[node name="Godot" type="TextureRect" parent="."]
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -509.0
offset_top = 160.0
offset_right = 2024.0
offset_bottom = 1184.0
grow_horizontal = 2
scale = Vector2(0.4, 0.4)
size_flags_horizontal = 4
texture = ExtResource("5_s88rl")
metadata/_edit_lock_ = true

208
scenes/TitleScreen.tscn Normal file
View File

@ -0,0 +1,208 @@
[gd_scene load_steps=15 format=3 uid="uid://b8tj5ccjo6lqe"]
[ext_resource type="Script" uid="uid://cyi0j3meewtyt" path="res://scripts/TitleScreen.cs" id="1_mgv04"]
[ext_resource type="Texture2D" uid="uid://ghgridyqby8w" path="res://assets/backgrounds/EclipticSonata.png" id="2_t3h42"]
[ext_resource type="Theme" uid="uid://d1gp4l4cwgtw4" path="res://resources/themes/button.tres" id="2_xbc5l"]
[ext_resource type="FontFile" uid="uid://ch6s7n1ri81gt" path="res://assets/fonts/思源宋体.TTF" id="4_xoekp"]
[ext_resource type="Theme" uid="uid://d0pi6io7y7tky" path="res://resources/themes/dialog.tres" id="6_bdtiy"]
[ext_resource type="Texture2D" uid="uid://cy8hsxd2nn0i8" path="res://assets/EclipticSonataLogo.png" id="6_nf1md"]
[ext_resource type="AudioStream" uid="uid://l6k3d3408tj" path="res://assets/music/Wolfgang Amadeus Mozart - 莫扎特 摇篮曲.mp3" id="7_68hpm"]
[ext_resource type="PackedScene" uid="uid://b25umg4d0y13" path="res://resources/ui/SavedSelection.tscn" id="8_88cje"]
[sub_resource type="Animation" id="Animation_yw73o"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(64, -300)]
}
[sub_resource type="Animation" id="Animation_gm0ka"]
resource_name = "flyin"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(64, -300), Vector2(64, 33)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_csld4"]
_data = {
&"RESET": SubResource("Animation_yw73o"),
&"flyin": SubResource("Animation_gm0ka")
}
[sub_resource type="Animation" id="Animation_4v6qd"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(1520, 470)]
}
[sub_resource type="Animation" id="Animation_86lmj"]
resource_name = "flyin"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(1520, 470), Vector2(1056, 470)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_5laux"]
_data = {
&"RESET": SubResource("Animation_4v6qd"),
&"flyin": SubResource("Animation_86lmj")
}
[node name="TitleScreen" type="Node2D" node_paths=PackedStringArray("StartGameButton", "LoadGameButton", "GameSettingsButton", "ExitGameButton", "StartConfirmationDialog", "ExitConfirmationDialog", "SavedSelection")]
script = ExtResource("1_mgv04")
StartGameButton = NodePath("VBoxContainer/新的开始")
LoadGameButton = NodePath("VBoxContainer/载入游戏")
GameSettingsButton = NodePath("VBoxContainer/游戏设置")
ExitGameButton = NodePath("VBoxContainer/退出游戏")
StartConfirmationDialog = NodePath("StartNew?")
ExitConfirmationDialog = NodePath("ExitGame?")
SavedSelection = NodePath("SavedSelection")
[node name="bg" type="Sprite2D" parent="."]
position = Vector2(640, 360)
texture = ExtResource("2_t3h42")
metadata/_edit_lock_ = true
[node name="CopyRight" type="Label" parent="."]
offset_left = 8.0
offset_top = 688.0
offset_right = 272.0
offset_bottom = 717.0
theme_override_colors/font_color = Color(0.219608, 0.0823529, 0.254902, 1)
theme_override_colors/font_shadow_color = Color(0.983899, 0.825836, 0.867247, 0.458824)
theme_override_fonts/font = ExtResource("4_xoekp")
theme_override_font_sizes/font_size = 18
text = "©2025 Milimoe. 米粒的糖果屋"
horizontal_alignment = 1
vertical_alignment = 1
metadata/_edit_lock_ = true
[node name="ExitGame?" type="ConfirmationDialog" parent="."]
title = "提示"
theme = ExtResource("6_bdtiy")
ok_button_text = "是"
dialog_text = "是否退出游戏?"
cancel_button_text = "否"
[node name="StartNew?" type="ConfirmationDialog" parent="."]
auto_translate_mode = 1
title = "提示"
theme = ExtResource("6_bdtiy")
ok_button_text = "是"
dialog_text = "开始新的游戏吗?"
cancel_button_text = "否"
[node name="EclipticSonataLogo" type="TextureRect" parent="."]
offset_left = 64.0
offset_top = -300.0
offset_right = 940.0
offset_bottom = 30.0
scale = Vector2(0.7, 0.7)
texture = ExtResource("6_nf1md")
metadata/_edit_lock_ = true
[node name="AnimationPlayer" type="AnimationPlayer" parent="EclipticSonataLogo"]
libraries = {
&"": SubResource("AnimationLibrary_csld4")
}
autoplay = "flyin"
playback_auto_capture = false
playback_default_blend_time = 0.3
[node name="VBoxContainer" type="VBoxContainer" parent="."]
offset_left = 1520.0
offset_top = 470.0
offset_right = 1656.0
offset_bottom = 702.0
metadata/_edit_lock_ = true
[node name="新的开始" type="Button" parent="VBoxContainer"]
layout_mode = 2
theme = ExtResource("2_xbc5l")
text = "新的开始"
flat = true
icon_alignment = 1
metadata/_edit_lock_ = true
[node name="载入游戏" type="Button" parent="VBoxContainer"]
layout_mode = 2
theme = ExtResource("2_xbc5l")
text = "载入游戏"
flat = true
icon_alignment = 1
metadata/_edit_lock_ = true
[node name="游戏设置" type="Button" parent="VBoxContainer"]
layout_mode = 2
theme = ExtResource("2_xbc5l")
text = "游戏设置"
flat = true
icon_alignment = 1
metadata/_edit_lock_ = true
[node name="退出游戏" type="Button" parent="VBoxContainer"]
layout_mode = 2
theme = ExtResource("2_xbc5l")
text = "退出游戏"
flat = true
icon_alignment = 1
metadata/_edit_lock_ = true
[node name="AnimationPlayer" type="AnimationPlayer" parent="VBoxContainer"]
callback_mode_method = 1
libraries = {
&"": SubResource("AnimationLibrary_5laux")
}
autoplay = "flyin"
playback_auto_capture = false
playback_default_blend_time = 0.3
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
stream = ExtResource("7_68hpm")
volume_db = -8.0
autoplay = true
parameters/looping = true
[node name="SavedSelection" parent="." node_paths=PackedStringArray("Parent") instance=ExtResource("8_88cje")]
visible = false
Parent = NodePath("..")
[node name="ColorRect" type="ColorRect" parent="."]
visible = false
offset_right = 1280.0
offset_bottom = 720.0
color = Color(0, 0, 0, 1)
metadata/_edit_lock_ = true

4
scenes/main.tscn Normal file
View File

@ -0,0 +1,4 @@
[gd_scene format=3 uid="uid://cxg1hupyc68hw"]
[node name="Main" type="Node2D"]
metadata/_edit_lock_ = true

1806
scenes/第一章.tres Normal file

File diff suppressed because it is too large Load Diff

79
scenes/第一章.tscn Normal file

File diff suppressed because one or more lines are too long

244
scripts/.editorconfig Normal file
View File

@ -0,0 +1,244 @@
# 如果要从更高级别的目录继承 .editorconfig 设置,请删除以下行
root = true
# c# 文件
[*.cs]
#### Core EditorConfig 选项 ####
# 缩进和间距
indent_size = 4
indent_style = space
tab_width = 4
# 新行首选项
end_of_line = crlf
insert_final_newline = false
#### .NET 代码操作 ####
# 类型成员
dotnet_hide_advanced_members = false
dotnet_member_insertion_location = with_other_members_of_the_same_kind
dotnet_property_generation_behavior = prefer_throwing_properties
# 符号搜索
dotnet_search_reference_assemblies = true
#### .NET 编码约定 ####
# 组织 Using
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = true
file_header_template = unset
# this. 和 Me. 首选项
dotnet_style_qualification_for_event = false
dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_property = false
# 语言关键字与 bcl 类型首选项
dotnet_style_predefined_type_for_locals_parameters_members = true
dotnet_style_predefined_type_for_member_access = true
# 括号首选项
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
# 修饰符首选项
dotnet_style_require_accessibility_modifiers = for_non_interface_members
# 表达式级首选项
dotnet_prefer_system_hash_code = true
dotnet_style_coalesce_expression = true
dotnet_style_collection_initializer = true
dotnet_style_explicit_tuple_names = true
dotnet_style_namespace_match_folder = true
dotnet_style_null_propagation = true
dotnet_style_object_initializer = true
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_prefer_auto_properties = true
dotnet_style_prefer_collection_expression = when_types_loosely_match
dotnet_style_prefer_compound_assignment = true
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
dotnet_style_prefer_inferred_anonymous_type_member_names = true
dotnet_style_prefer_inferred_tuple_names = true
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
dotnet_style_prefer_simplified_boolean_expressions = true
dotnet_style_prefer_simplified_interpolation = true
# 字段首选项
dotnet_style_readonly_field = true
# 参数首选项
dotnet_code_quality_unused_parameters = all
# 禁止显示首选项
dotnet_remove_unnecessary_suppression_exclusions = none
# 新行首选项
dotnet_style_allow_multiple_blank_lines_experimental = true
dotnet_style_allow_statement_immediately_after_block_experimental = true
#### c# 编码约定 ####
# var 首选项
csharp_style_var_elsewhere = false
csharp_style_var_for_built_in_types = false
csharp_style_var_when_type_is_apparent = false
# Expression-bodied 成员
csharp_style_expression_bodied_accessors = true
csharp_style_expression_bodied_constructors = false
csharp_style_expression_bodied_indexers = true
csharp_style_expression_bodied_lambdas = true
csharp_style_expression_bodied_local_functions = false
csharp_style_expression_bodied_methods = false
csharp_style_expression_bodied_operators = false
csharp_style_expression_bodied_properties = true
# 模式匹配首选项
csharp_style_pattern_matching_over_as_with_null_check = true
csharp_style_pattern_matching_over_is_with_cast_check = true
csharp_style_prefer_extended_property_pattern = true
csharp_style_prefer_not_pattern = true
csharp_style_prefer_pattern_matching = true
csharp_style_prefer_switch_expression = true
# Null 检查首选项
csharp_style_conditional_delegate_call = true
# 修饰符首选项
csharp_prefer_static_anonymous_function = true
csharp_prefer_static_local_function = true
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
csharp_style_prefer_readonly_struct = true
csharp_style_prefer_readonly_struct_member = true
# 代码块首选项
csharp_prefer_braces = true
csharp_prefer_simple_using_statement = true
csharp_prefer_system_threading_lock = true
csharp_style_namespace_declarations = block_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_primary_constructors = true
csharp_style_prefer_top_level_statements = true
# 表达式级首选项
csharp_prefer_simple_default_expression = true
csharp_style_deconstructed_variable_declaration = true
csharp_style_implicit_object_creation_when_type_is_apparent = true
csharp_style_inlined_variable_declaration = true
csharp_style_prefer_index_operator = true
csharp_style_prefer_local_over_anonymous_function = true
csharp_style_prefer_null_check_over_type_check = true
csharp_style_prefer_range_operator = true
csharp_style_prefer_tuple_swap = true
csharp_style_prefer_utf8_string_literals = true
csharp_style_throw_expression = true
csharp_style_unused_value_assignment_preference = discard_variable
csharp_style_unused_value_expression_statement_preference = discard_variable
# "using" 指令首选项
csharp_using_directive_placement = outside_namespace
# 新行首选项
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
csharp_style_allow_embedded_statements_on_same_line_experimental = true
#### C# 格式规则 ####
# 新行首选项
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
# 缩进首选项
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true
# 空格键首选项
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# 包装首选项
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
#### 命名样式 ####
# 命名规则
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# 符号规范
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# 命名样式
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case

View File

@ -0,0 +1,91 @@
using System;
using Godot;
namespace Milimoe.GodotGame;
public partial class AnimatedRichTextLabel : RichTextLabel
{
[Export]
public float CharactersPerSecond { get; set; } = 20; // 每秒显示的字符数
public NovelController NovelController { get; set; } = null; // 是否在小说控制器中
public bool IsAnimationRunning = false; // 动画是否正在运行
private string _fullText; // 完整的文本内容
private float _elapsedTime = 0; // 经过的时间
private int _visibleCharacters = 0; // 当前显示的字符数
private Timer _timer;
public override void _Ready()
{
_timer = GetNode<Timer>("Timer");
_timer.Timeout += OnTimerTimeout;
_fullText = Text; // 保存完整的文本内容
Text = ""; // 清空 RichTextLabel 的初始文本
VisibleCharacters = 0; // 确保初始状态下不显示任何字符
}
public void StartAnimation()
{
_elapsedTime = 0;
_visibleCharacters = 0;
Text = _fullText; // 恢复完整的文本内容
VisibleCharacters = 0; // 确保从头开始显示
IsAnimationRunning = true;
_timer.Start(); // 启动 Timer
}
public void SkipAnimation()
{
if (IsAnimationRunning)
{
VisibleCharacters = _fullText.Length; // 直接显示所有字符
StopAnimation();
}
}
private void StopAnimation()
{
if (IsAnimationRunning)
{
_timer.Stop();
IsAnimationRunning = false;
NovelController.TextAnimationHasFinished();
}
}
public override void _Process(double delta)
{
if (!IsAnimationRunning) return;
if (_timer.IsStopped()) return;
_elapsedTime += (float)delta;
int targetVisibleCharacters = (int)(_elapsedTime * CharactersPerSecond);
if (targetVisibleCharacters > _visibleCharacters)
{
_visibleCharacters = Math.Min(targetVisibleCharacters, _fullText.Length);
VisibleCharacters = _visibleCharacters;
}
if (_visibleCharacters >= _fullText.Length)
{
StopAnimation();
}
}
private void OnTimerTimeout()
{
// 这里可以添加一些逻辑,例如在动画结束后触发一个信号
// 或者执行其他操作
}
public new void SetText(string text)
{
_fullText = text;
Text = "";
VisibleCharacters = 0;
IsAnimationRunning = false;
}
}

View File

@ -0,0 +1 @@
uid://c4ny5p54lotj0

View File

@ -0,0 +1 @@
uid://33pxslbxxwv1

View File

@ -0,0 +1,151 @@
using System.Threading.Tasks;
using Godot;
namespace Milimoe.GodotGame;
public partial class ChapterScene : Node2D, INovelEndEvent, IMenuObject, IFadeInFadeOutBlack
{
[Export]
public PackedScene NovelScene { get; set; }
[Export]
public PackedScene MenuScene { get; set; }
[Export]
public CanvasLayer UI { get; set; }
[Export]
public string ChapterInGame { get; set; }
[Export]
public string AreaInGame { get; set; }
[Export]
public string NovelName { get; set; }
[Export]
public string SceneName { get; set; }
private CanvasLayer _novelCanvasLayer;
private CanvasLayer _menuCanvasLayer;
private Node _novelInterface;
private Node _menuInterface;
public override async void _Ready()
{
GameConstant.ChapterInGame = ChapterInGame;
GameConstant.AreaInGame = AreaInGame;
GameConstant.NovelName = NovelName;
GameConstant.SceneName = SceneName;
_novelCanvasLayer = GetNode<CanvasLayer>("Novel");
_novelCanvasLayer.Visible = true;
ColorRect colorRect = GetNode<ColorRect>("ColorRect");
colorRect.SelfModulate = new Color(0, 0, 0, 1);
colorRect.Show();
// 实例化小说界面场景
if (NovelScene != null)
{
_novelInterface = NovelScene.Instantiate();
_novelCanvasLayer.AddChild(_novelInterface);
if (_novelInterface is NovelController novelController)
{
novelController.ChapterObject = this;
novelController.MenuObject = this;
novelController.FadeObject = this;
await FadeOutBlack(1f, true);
novelController.InitNovel(NovelName, SceneName);
GameConstant.AutoSave(0);
}
}
// 实例化菜单界面场景
if (MenuScene != null)
{
_menuCanvasLayer = GetNode<CanvasLayer>("Menu");
_menuCanvasLayer.Visible = false;
_menuInterface = MenuScene.Instantiate();
if (_menuInterface is MenuController menuController)
{
menuController.Parent = this;
}
_menuCanvasLayer.AddChild(_menuInterface);
}
}
public override void _Input(InputEvent @event)
{
if (@event is InputEventKey keyEvent)
{
if (keyEvent.Pressed && keyEvent.Keycode == Key.Escape)
{
if (_menuCanvasLayer != null)
{
ChangeState();
}
}
}
}
public async void OnNovelEnd(CanvasLayer node, string novel_name, string scene_name)
{
node.Visible = false;
await FadeInBlack(1f);
await Task.Delay(500);
await FadeOutBlack(0.5f, true);
if (UI != null)
{
UI.Visible = true;
if (UI.GetNode<Control>("UserInterface") is UserInterface userInterface)
{
if (GameConstant.Characters.Count == 1)
{
userInterface.CharacterStatus1.Visible = true;
TextureRect image = userInterface.CharacterStatus1.GetNode<TextureRect>("Image");
using Texture2D texture = GD.Load<CompressedTexture2D>("res://assets/character/雷恩.png");
image.Texture = texture;
}
else if (GameConstant.Characters.Count == 2)
{
userInterface.CharacterStatus1.Visible = true;
userInterface.CharacterStatus2.Visible = true;
}
}
}
}
public async Task FadeInBlack(float fadeTime, bool hide = false)
{
// 淡入黑色遮罩
ColorRect colorRect = GetNode<ColorRect>("ColorRect");
colorRect.SelfModulate = new Color(0, 0, 0, 0);
colorRect.Show();
Tween tween = CreateTween();
tween.TweenProperty(colorRect, "self_modulate", new Color(0, 0, 0, 1), fadeTime);
await ToSignal(tween, "finished");
if (hide) colorRect.Hide();
}
public async Task FadeOutBlack(float fadeTime, bool hide = false)
{
// 淡出黑色遮罩
ColorRect colorRect = GetNode<ColorRect>("ColorRect");
colorRect.SelfModulate = new Color(0, 0, 0, 1);
colorRect.Show();
Tween tween = CreateTween();
tween.TweenProperty(colorRect, "self_modulate", new Color(0, 0, 0, 0), fadeTime);
await ToSignal(tween, "finished");
if (hide) colorRect.Hide();
}
public void ChangeState()
{
GD.Print("Change Menu State!");
if (_menuCanvasLayer != null)
{
_menuCanvasLayer.Visible = !_menuCanvasLayer.Visible;
}
}
}

View File

@ -0,0 +1 @@
uid://q16vfxvc5i54

View File

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.GodotGame
{
public class GameConstant
{
public static Dictionary<long, Character> Characters { get; set; } = [];
public static Dictionary<Character, Region> CharacterInRegion { get; set; } = [];
public static Dictionary<long, Region> Regions { get; set; } = [];
public static string ChapterInGame { get; set; } = "";
public static string AreaInGame { get; set; } = "";
public static string NovelName { get; set; } = "";
public static string SceneName { get; set; } = "";
public static string NovelNodeKey { get; set; } = "";
public static void InitGame()
{
Character character = Factory.GetCharacter();
character.Id = 1;
character.Name = "雷恩";
character.FirstName = "Rayne";
character.NickName = "雷恩";
character.PrimaryAttribute = PrimaryAttribute.AGI;
character.InitialATK = 21;
character.InitialHP = 120;
character.InitialMP = 20;
character.InitialSTR = 7;
character.STRGrowth = 1;
character.InitialAGI = 21;
character.AGIGrowth = 1.8;
character.InitialINT = 2;
character.INTGrowth = 0.2;
character.InitialSPD = 300;
character.InitialHR = 4;
character.InitialMR = 2;
Characters.Add(character.Id, character);
character = Factory.GetCharacter();
character.Id = 2;
character.Name = "艾琳";
character.FirstName = "Irene";
character.NickName = "艾琳";
character.PrimaryAttribute = PrimaryAttribute.INT;
character.InitialATK = 17;
character.InitialHP = 110;
character.InitialMP = 80;
character.InitialSTR = 6;
character.STRGrowth = 0.5;
character.InitialAGI = 4;
character.AGIGrowth = 0.5;
character.InitialINT = 20;
character.INTGrowth = 2;
character.InitialSPD = 270;
character.InitialHR = 4;
character.InitialMR = 2;
Characters.Add(character.Id, character);
Region region = new()
{
Id = 1,
Guid = Guid.NewGuid(),
Name = "霜语城废墟",
Category = "主线地图",
Description = "第一章",
Difficulty = RarityType.OneStar,
Weathers = { ["晴"] = 15, ["阴"] = 10, ["雨"] = 5 }
};
region.ChangeRandomWeather();
Regions.Add(region.Id, region);
region = new()
{
Id = 2,
Guid = Guid.NewGuid(),
Name = "幽暗密林",
Category = "主线地图",
Description = "第一章",
Difficulty = RarityType.OneStar,
Weathers = { ["晴"] = 15, ["阴"] = 10, ["雨"] = 5 }
};
region.ChangeRandomWeather();
Regions.Add(region.Id, region);
region = new()
{
Id = 3,
Guid = Guid.NewGuid(),
Name = "翡翠回廊",
Category = "主线地图",
Description = "第二章",
Difficulty = RarityType.OneStar,
Weathers = { ["晴"] = 15, ["阴"] = 10, ["雨"] = 5 }
};
region.ChangeRandomWeather();
Regions.Add(region.Id, region);
region = new()
{
Id = 4,
Guid = Guid.NewGuid(),
Name = "炼狱裂谷",
Category = "主线地图",
Description = "第三章",
Difficulty = RarityType.OneStar,
Weathers = { ["晴"] = 15, ["阴"] = 10, ["雨"] = 5 }
};
region.ChangeRandomWeather();
Regions.Add(region.Id, region);
region = new()
{
Id = 5,
Guid = Guid.NewGuid(),
Name = "虚空回廊",
Category = "主线地图",
Description = "第四章",
Difficulty = RarityType.OneStar,
Weathers = { ["晴"] = 15, ["阴"] = 10, ["雨"] = 5 }
};
region.ChangeRandomWeather();
Regions.Add(region.Id, region);
region = new()
{
Id = 6,
Guid = Guid.NewGuid(),
Name = "地脉祭坛",
Category = "主线地图",
Description = "第五章",
Difficulty = RarityType.OneStar,
Weathers = { ["晴"] = 15, ["阴"] = 10, ["雨"] = 5 }
};
region.ChangeRandomWeather();
Regions.Add(region.Id, region);
region = new()
{
Id = 7,
Guid = Guid.NewGuid(),
Name = "天空圣殿",
Category = "主线地图",
Description = "终章",
Difficulty = RarityType.OneStar,
Weathers = { ["晴"] = 15, ["阴"] = 10, ["雨"] = 5 }
};
region.ChangeRandomWeather();
Regions.Add(region.Id, region);
foreach (Character c in Characters.Values)
{
CharacterInRegion[c] = Regions[1];
}
}
public static void AutoSave(int index)
{
PluginConfig config = new("Saved", $"auto{index}")
{
{ "SavedTime", $"保存时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}" },
{ "ChapterInGame", ChapterInGame },
{ "AreaInGame", AreaInGame },
{ "NovelName", NovelName },
{ "SceneName", SceneName },
{ "NovelNodeKey", NovelNodeKey },
{ "Characters", new List<Character>(Characters.Values) }
};
config.SaveConfig();
}
}
}

View File

@ -0,0 +1 @@
uid://2ji25axqwn1k

View File

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace Milimoe.GodotGame
{
public interface IFadeInFadeOutBlack
{
public Task FadeInBlack(float fadeTime, bool hide = false);
public Task FadeOutBlack(float fadeTime, bool hide = false);
}
}

View File

@ -0,0 +1 @@
uid://cg0f0ruumecf8

View File

@ -0,0 +1,9 @@
using Godot;
namespace Milimoe.GodotGame
{
public interface IMenuObject
{
public void ChangeState();
}
}

View File

@ -0,0 +1 @@
uid://b0cxf7ncshow5

View File

@ -0,0 +1,9 @@
using Godot;
namespace Milimoe.GodotGame
{
public interface INovelEndEvent
{
public void OnNovelEnd(CanvasLayer node, string novel_name, string scene_name);
}
}

View File

@ -0,0 +1 @@
uid://c321wc8h21hju

View File

@ -0,0 +1,9 @@
using Godot;
namespace Milimoe.GodotGame
{
public interface ISaveSelectionEvent
{
public void OnSaveSelectionClosed(bool selected, int index, bool isSave);
}
}

View File

@ -0,0 +1 @@
uid://d0esjr7pxrxq4

91
scripts/MenuController.cs Normal file
View File

@ -0,0 +1,91 @@
using Godot;
namespace Milimoe.GodotGame;
public partial class MenuController : ColorRect
{
[Export]
public Node Parent;
[Export]
public Button ContinueGame;
[Export]
public Button GameSettings;
[Export]
public Button BackToTitle;
[Export]
public Button ExitGame;
[Export]
public ConfirmationDialog ExitConfirmationDialog;
[Export]
public ConfirmationDialog BackToTitleConfirmationDialog;
[Export]
public string TitleScenePath = "res://scenes/TitleScreen.tscn"; // 标题场景的路径
public override void _Ready()
{
if (ExitConfirmationDialog != null)
{
ExitConfirmationDialog.GetOkButton().Pressed += () => GetTree().Quit();
}
if (BackToTitleConfirmationDialog != null)
{
BackToTitleConfirmationDialog.GetOkButton().Pressed += async () =>
{
if (Parent is IFadeInFadeOutBlack fade)
{
await fade.FadeInBlack(1f);
// 加载标题场景
GD.Print("LoadTitleScene!");
GetTree().ChangeSceneToFile(TitleScenePath);
}
};
}
if (ContinueGame != null)
{
ContinueGame.Pressed += ContinueGame_Pressed;
}
if (BackToTitle != null)
{
BackToTitle.Pressed += BackToTitle_Pressed;
}
if (ExitGame != null)
{
ExitGame.Pressed += ExitGame_Pressed;
}
}
private void ContinueGame_Pressed()
{
if (Parent is IMenuObject obj)
{
obj.ChangeState();
}
}
private void BackToTitle_Pressed()
{
// 返回标题界面
BackToTitleConfirmationDialog?.PopupCentered(); // 弹出对话框
}
private void ExitGame_Pressed()
{
// 退出游戏
if (ExitConfirmationDialog != null)
{
ExitConfirmationDialog.PopupCentered(); // 弹出对话框
}
else
{
GD.PrintErr("ExitConfirmationDialog is not connected!");
GetTree().Quit(); // 如果对话框未连接,则直接退出
}
}
}

View File

@ -0,0 +1 @@
uid://c0hp2amidehe0

291
scripts/NovelController.cs Normal file
View File

@ -0,0 +1,291 @@
using System.Linq;
using System.Threading.Tasks;
using Godot;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Model;
namespace Milimoe.GodotGame;
public partial class NovelController : CanvasLayer, ISaveSelectionEvent
{
public string NovelName { get; set; } = "";
public string SceneName { get; set; } = "";
public NovelConfig NovelConfig { get; set; } = null;
public NovelNode Current { get; set; } = null;
public INovelEndEvent ChapterObject { get; set; } = null;
public IMenuObject MenuObject { get; set; } = null;
public IFadeInFadeOutBlack FadeObject { get; set; } = null;
public bool Automatic { get; set; } = false;
[Export]
public SavedSelection SavedSelection;
[Signal]
public delegate void CloseSavedSelectionEventHandler(bool selected, int index);
private TextureRect _portrait1;
private TextureRect _portrait2left;
private TextureRect _portrait2right;
private TextureRect _image1;
private TextureRect _image2left;
private TextureRect _image2right;
private Panel _panel;
private Panel _namePanel;
private Label _name;
private RichTextLabel _content;
private AnimatedRichTextLabel _content_richLabel;
private VBoxContainer _vBoxContainer;
private ColorRect _colorRect;
private Button _autoPlay;
private Button _load;
private Button _save;
private Button _menu;
public override void _Ready()
{
Visible = false;
_portrait1 = GetNode<TextureRect>("立绘1");
_portrait2left = GetNode<TextureRect>("立绘2左");
_portrait2right = GetNode<TextureRect>("立绘2右");
_image1 = _portrait1.GetNode<TextureRect>("Image");
_image2left = _portrait2left.GetNode<TextureRect>("Image");
_image2right = _portrait2right.GetNode<TextureRect>("Image");
_panel = GetNode<Panel>("Panel");
_namePanel = _panel.GetNode<Panel>("NamePanel");
_name = _namePanel.GetNode<Label>("Name");
_content = _panel.GetNode<RichTextLabel>("Content");
if (_content is AnimatedRichTextLabel richLabel)
{
_content_richLabel = richLabel;
_content_richLabel.NovelController = this;
}
_colorRect = GetNode<ColorRect>("透明挡板");
_vBoxContainer = GetNode<VBoxContainer>("选项框");
if (_colorRect != null)
{
_colorRect.GuiInput += ColorRect_GuiInput;
}
_autoPlay = GetNode<Button>("自动播放");
_load = GetNode<Button>("读取存档");
_save = GetNode<Button>("保存存档");
_menu = GetNode<Button>("游戏菜单");
if (_autoPlay != null)
{
_autoPlay.Pressed += () => Automatic = _autoPlay.ButtonPressed;
}
if (_load != null)
{
_load.Pressed += () => OnLoadSaveButtonPressed(false);
}
if (_save != null)
{
_save.Pressed += () => OnLoadSaveButtonPressed(true);
}
if (_menu != null)
{
_menu.Pressed += OnMenuButtonPressed;
}
}
public void InitNovel(string novel_name, string scene_name)
{
NovelName = novel_name;
SceneName = scene_name;
if (NovelName != "" && SceneName != "")
{
NovelConfig ??= NovelConfig.LoadFrom(ProjectSettings.GlobalizePath("res://resources/novels/第一章/场景一.json"), NovelName, false);
if (NovelConfig.Count > 0)
{
ShowNode(NovelConfig.Values.First());
}
}
}
public void ShowNode(NovelNode node)
{
if (node != null)
{
GameConstant.NovelName = NovelName;
GameConstant.SceneName = SceneName;
GameConstant.NovelNodeKey = node.Key;
_name.Text = node.Name;
_namePanel.Visible = _name.Text != "";
_name.Visible = _name.Text != "";
if (node.PortraitImagePath != "")
{
using Texture2D texture = GD.Load<CompressedTexture2D>(node.PortraitImagePath);
_image1.Texture = texture;
_image1.Visible = true;
}
else _image1.Visible = false;
if (_content_richLabel != null)
{
_content_richLabel.SetText(node.Content);
_content_richLabel.StartAnimation();
}
else _content.Text = node.Content;
foreach (Node child in _vBoxContainer.GetChildren())
{
child.QueueFree();
}
_vBoxContainer.Visible = false;
_colorRect.Visible = true;
Current = node;
Visible = true;
}
else Visible = false;
}
public async void TextAnimationHasFinished()
{
if (Current != null)
{
await Task.Delay(500);
if (_vBoxContainer.Visible)
{
return;
}
foreach (NovelOption option in Current.AvailableOptions)
{
Button button = new()
{
Text = option.Name,
Theme = GD.Load<Theme>("res://resources/themes/option.tres")
};
button.Pressed += () => OnOptionButtonClick(option);
_vBoxContainer.AddChild(button);
}
if (Current.AvailableOptions.Count == 0)
{
// 透明挡板用于控制在没有选项时继续
_colorRect.Visible = true;
// 如果是自动播放剧情则在800ms后自动下一句
if (Automatic)
{
await Task.Delay(800);
// 需要再次判断
if (Automatic && !_content_richLabel.IsAnimationRunning)
{
NovelNode next = Current.Next;
if (next != null)
{
ShowNode(next);
}
else
{
ChapterObject.OnNovelEnd(this, NovelName, SceneName);
}
}
}
}
else
{
// 显示选项框
_vBoxContainer.Visible = true;
}
}
}
public void OnOptionButtonClick(NovelOption option)
{
if (option != null && option.Targets.Count > 0)
{
NovelNode next = option.Targets.First();
ShowNode(next);
}
}
private void ColorRect_GuiInput(InputEvent @event)
{
if (@event is InputEventMouseButton mouseButtonEvent)
{
if (mouseButtonEvent.ButtonIndex == MouseButton.Left && mouseButtonEvent.Pressed)
{
if (_content_richLabel.IsAnimationRunning)
{
_content_richLabel.SkipAnimation();
}
else
{
if (Current.AvailableOptions.Count > 0)
{
return;
}
NovelNode next = Current.Next;
if (next != null)
{
ShowNode(next);
}
else
{
ChapterObject.OnNovelEnd(this, NovelName, SceneName);
}
}
}
}
}
private void OnLoadSaveButtonPressed(bool isSave)
{
if (isSave)
{
// 保存游戏
GD.Print("Save Game!");
SavedSelection.SetIsSave(true);
}
else
{
// 载入游戏
GD.Print("Load Game!");
SavedSelection.SetIsSave(false);
}
// 使用动画效果显示存档列表
if (SavedSelection != null)
{
SavedSelection.Show();
SavedSelection.GetNode<ColorRect>("ColorRect").GetNode<AnimationPlayer>("AnimationPlayer").Play("flyin");
}
}
private void OnMenuButtonPressed()
{
// 打开游戏菜单
GD.Print("Open Game Menu!");
if (MenuObject is IMenuObject obj)
{
obj.ChangeState();
}
}
public async void OnSaveSelectionClosed(bool selected, int index, bool isSave)
{
if (SavedSelection != null && !SavedSelection.IsClosing)
{
// 关闭存档选择界面
SavedSelection.IsClosing = true;
SavedSelection.GetNode<ColorRect>("ColorRect").GetNode<AnimationPlayer>("AnimationPlayer").Play("flyout");
await Task.Delay(300);
SavedSelection.IsClosing = false;
SavedSelection.Hide();
if (selected && index >= 0)
{
if (!isSave)
{
// 载入游戏
GD.Print($"Selected Saved: {index}!");
if (FadeObject != null)
{
await FadeObject.FadeInBlack(1f);
}
else await Task.Delay(1000);
GetTree().Quit();
}
}
else
{
GD.Print("Close SavedSelection!");
}
}
}
}

View File

@ -0,0 +1 @@
uid://cgcdu4cg7u28g

View File

@ -0,0 +1,192 @@
using System;
using System.Collections.Generic;
using Godot;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.GodotGame;
public partial class SavedNode : PanelContainer
{
[Export]
public int Index = 1;
[Export]
public bool IsAuto = false;
[Export]
public Button Button;
[Export]
public ConfirmationDialog SaveDialog;
[Export]
public ConfirmationDialog LoadDialog;
[Export]
public Label SavedName;
[Export]
public Label SavedTime;
[Export]
public Label ChapterInGame;
[Export]
public Label AreaInGame;
public Node Parent { get; set; }
public bool IsSave { get; set; } = false;
public bool HasValue { get; set; } = false;
public PluginConfig Config { get; set; } = null;
public override void _Ready()
{
if (IsAuto)
{
Config ??= new("Saved", $"auto{Index}");
}
else
{
Config ??= new("Saved", Index.ToString());
}
Config.LoadConfig();
Button ??= GetNode<Button>("Button");
Button.Pressed += Button_Pressed;
if (SaveDialog != null)
{
SaveDialog.GetOkButton().Pressed += SaveDialogConfirmed;
}
if (LoadDialog != null)
{
LoadDialog.GetOkButton().Pressed += LoadDialogConfirmed;
}
RefreshValue();
}
public void RefreshValue()
{
if (IsAuto) SavedName.Text = $"自动存档";
else SavedName.Text = $"存档位置 {Index}";
string savedTime = "";
string chapterInGame = "";
string areaInGame = "";
if (Config.Count > 0)
{
savedTime = Config["SavedTime"].ToString();
chapterInGame = Config["ChapterInGame"].ToString();
areaInGame = Config["AreaInGame"].ToString();
if (savedTime != "" && chapterInGame != "" && areaInGame != "")
{
HasValue = true;
}
}
if (!HasValue)
{
SavedTime.Text = "<空>";
ChapterInGame.Text = "";
AreaInGame.Text = "";
}
else
{
SavedTime.Text = savedTime;
ChapterInGame.Text = chapterInGame;
AreaInGame.Text = areaInGame;
}
}
private void Button_Pressed()
{
if (IsSave)
{
if (IsAuto)
{
ShowAlert("不能保存到自动存档位。");
return;
}
GD.Print("Save");
SaveDialog?.PopupCentered();
}
else
{
if (!HasValue)
{
ShowAlert("这个存档位是空的,请选择其他位置。");
return;
}
GD.Print("Load");
LoadDialog?.PopupCentered();
}
}
private void SaveDialogConfirmed()
{
if (HasValue)
{
ShowConfirmation("这个存档位已经有存档了,是否覆盖?", Save);
return;
}
Save();
}
private void LoadDialogConfirmed()
{
GD.Print("LoadDialogConfirmed");
if (Parent is ISaveSelectionEvent e)
{
e.OnSaveSelectionClosed(true, Index, IsSave);
}
}
private void Save()
{
GD.Print("SaveDialogConfirmed");
if (Parent is ISaveSelectionEvent e)
{
Config.Add("SavedTime", $"保存时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}");
Config.Add("ChapterInGame", GameConstant.ChapterInGame);
Config.Add("AreaInGame", GameConstant.AreaInGame);
Config.Add("NovelName", GameConstant.NovelName);
Config.Add("SceneName", GameConstant.SceneName);
Config.Add("NovelNodeKey", GameConstant.NovelNodeKey);
Config.Add("Characters", new List<Character>(GameConstant.Characters.Values));
Config.SaveConfig();
e.OnSaveSelectionClosed(true, Index, IsSave);
}
}
public void ShowAlert(string message)
{
// 创建并配置 AcceptDialog
AcceptDialog dialog = new()
{
Title = "提示",
OkButtonText = "好",
DialogText = message,
Theme = GD.Load<Theme>("res://resources/themes/dialog.tres")
};
GetViewport().GetWindow().AddChild(dialog);
dialog.PopupCentered();
dialog.Connect("confirmed", new Callable(dialog, nameof(dialog.QueueFree)));
}
public void ShowConfirmation(string message, Action ok)
{
// 创建并配置 AcceptDialog
ConfirmationDialog dialog = new()
{
Title = "提示",
OkButtonText = "是",
CancelButtonText = "否",
DialogText = message,
Theme = GD.Load<Theme>("res://resources/themes/dialog.tres")
};
dialog.GetOkButton().Pressed += () => ok();
GetViewport().GetWindow().AddChild(dialog);
dialog.PopupCentered();
dialog.Connect("confirmed", new Callable(dialog, nameof(dialog.QueueFree)));
}
}

View File

@ -0,0 +1 @@
uid://yb8nssj7d04f

View File

@ -0,0 +1,60 @@
using Godot;
namespace Milimoe.GodotGame;
public partial class SavedSelection : CanvasLayer
{
[Export]
public Node Parent { get; set; }
[Export]
public bool IsSave { get; private set; } = false;
public bool IsClosing { get; set; } = false;
public override void _Ready()
{
SetProcessUnhandledInput(true);
SetIsSave(IsSave);
}
public void SetIsSave(bool isSave)
{
IsSave = isSave;
VBoxContainer vBoxContainer = GetNode<ColorRect>("ColorRect")?.GetNode<ScrollContainer>("ScrollContainer")?.GetNode<VBoxContainer>("VBoxContainer");
if (vBoxContainer != null)
{
foreach (Node node in vBoxContainer.GetChildren())
{
if (node is SavedNode savedNode)
{
savedNode.IsSave = IsSave;
if (Parent != null)
{
savedNode.Parent = Parent;
}
savedNode.Config.LoadConfig();
savedNode.RefreshValue();
}
}
}
}
public override void _Input(InputEvent @event)
{
if (Visible && @event is InputEventMouseButton mouseButtonEvent)
{
if (mouseButtonEvent.ButtonIndex == MouseButton.Right)
{
if (mouseButtonEvent.Pressed)
{
GD.Print("Mouse right button pressed outside UI!");
if (Parent is ISaveSelectionEvent e)
{
e.OnSaveSelectionClosed(false, 0, IsSave);
}
}
}
}
}
}

View File

@ -0,0 +1 @@
uid://djcq2jgoaism

120
scripts/SplashScreen.cs Normal file
View File

@ -0,0 +1,120 @@
using System;
using System.Threading.Tasks;
using Godot;
namespace Milimoe.GodotGame;
public partial class SplashScreen : Node
{
[Export]
public TextureRect GodotLogo;
[Export]
public TextureRect Logo;
[Export]
public Label Label;
[Export]
public float FadeDuration = 0.5f; // 淡入/淡出持续时间 (秒)
[Export]
public float VisibleDuration = 2.0f; // 显示时间 (秒)
[Export]
public string TitleScenePath = "res://scenes/TitleScreen.tscn"; // 标题场景的路径
private Color _initialGodotColor;
private Color _initialLogoColor;
private Color _initialLabelColor;
public override void _Ready()
{
// 检查节点是否为空
if (GodotLogo == null || Logo == null || Label == null)
{
GD.PrintErr("请在编辑器中指定 GodotLogo, Logo, Label 节点!");
return;
}
// 保存初始颜色
_initialGodotColor = GodotLogo.SelfModulate;
_initialLogoColor = Logo.SelfModulate;
_initialLabelColor = Label.SelfModulate;
// 初始时,隐藏 Raincandy 和 Milimoe
Logo.SelfModulate = new Color(_initialLogoColor.R, _initialLogoColor.G, _initialLogoColor.B, 0.0f);
Label.SelfModulate = new Color(_initialLabelColor.R, _initialLabelColor.G, _initialLabelColor.B, 0.0f);
// 显示 Godot Logo
GodotLogo.SelfModulate = new Color(_initialGodotColor.R, _initialGodotColor.G, _initialGodotColor.B, 1.0f);
// 开始流程
StartSequence();
}
private async void StartSequence()
{
// 等待一段时间
await Task.Delay(TimeSpan.FromSeconds(VisibleDuration));
// 淡出 Godot Logo
await FadeOutGodot();
// 淡入 Raincandy Logo 和 Milimoe Label
await FadeInRaincandy();
// 等待一段时间
await Task.Delay(TimeSpan.FromSeconds(VisibleDuration));
// 淡出 Raincandy Logo 和 Milimoe Label
await FadeOutRaincandy();
}
private async Task FadeOutGodot()
{
Tween tween = CreateTween();
Color targetColor = new(_initialGodotColor.R, _initialGodotColor.G, _initialGodotColor.B, 0.0f);
tween.TweenProperty(GodotLogo, "self_modulate", targetColor, FadeDuration);
await ToSignal(tween, "finished");
}
private async Task FadeInRaincandy()
{
Tween tween = CreateTween();
// 淡入 Raincandy Logo
Color targetRaincandyColor = new(_initialLogoColor.R, _initialLogoColor.G, _initialLogoColor.B, 1.0f);
tween.TweenProperty(Logo, "self_modulate", targetRaincandyColor, FadeDuration);
// 同时淡入 Milimoe Label
Color targetMilimoeColor = new(_initialLabelColor.R, _initialLabelColor.G, _initialLabelColor.B, 1.0f);
tween.Parallel().TweenProperty(Label, "self_modulate", targetMilimoeColor, FadeDuration);
await ToSignal(tween, "finished");
}
private async Task FadeOutRaincandy()
{
Tween tween = CreateTween();
// 淡出 Raincandy Logo
Color targetRaincandyColor = new(_initialLogoColor.R, _initialLogoColor.G, _initialLogoColor.B, 0.0f);
tween.TweenProperty(Logo, "self_modulate", targetRaincandyColor, FadeDuration);
// 同时淡出 Milimoe Label
Color targetMilimoeColor = new(_initialLabelColor.R, _initialLabelColor.G, _initialLabelColor.B, 0.0f);
tween.Parallel().TweenProperty(Label, "self_modulate", targetMilimoeColor, FadeDuration);
tween.TweenProperty(GetNode<ColorRect>("ColorRect"), "self_modulate", new Color(0, 0, 0, 1), 0.5f);
await ToSignal(tween, "finished");
// 加载游戏常量
GameConstant.InitGame();
// 加载标题场景
GD.Print("LoadTitleScene!");
GetTree().ChangeSceneToFile(TitleScenePath);
}
}

View File

@ -0,0 +1 @@
uid://dbyq6vgnnib7w

8
scripts/Template.cs Normal file
View File

@ -0,0 +1,8 @@
using Godot;
namespace Milimoe.GodotGame;
public partial class Template : Node
{
}

1
scripts/Template.cs.uid Normal file
View File

@ -0,0 +1 @@
uid://kscitnmnjd31

172
scripts/TitleScreen.cs Normal file
View File

@ -0,0 +1,172 @@
using System.Threading.Tasks;
using Godot;
namespace Milimoe.GodotGame;
public partial class TitleScreen : Node, ISaveSelectionEvent
{
[Export]
public Button StartGameButton;
[Export]
public Button LoadGameButton;
[Export]
public Button GameSettingsButton;
[Export]
public Button ExitGameButton;
[Export]
public ConfirmationDialog StartConfirmationDialog;
[Export]
public ConfirmationDialog ExitConfirmationDialog;
[Export]
public SavedSelection SavedSelection;
public override async void _Ready()
{
ColorRect colorRect = GetNode<ColorRect>("ColorRect");
colorRect.SelfModulate = new Color(0, 0, 0, 1);
colorRect.Show();
// 检查按钮是否已连接
if (StartGameButton != null)
{
StartGameButton.Pressed += OnStartGameButtonPressed;
}
if (LoadGameButton != null)
{
LoadGameButton.Pressed += OnLoadGameButtonPressed;
}
if (GameSettingsButton != null)
{
GameSettingsButton.Pressed += OnGameSettingsButtonPressed;
}
if (ExitGameButton != null)
{
ExitGameButton.Pressed += OnExitGameButtonPressed;
}
if (StartConfirmationDialog != null)
{
StartConfirmationDialog.GetOkButton().Pressed += OnStartGameConfirmation;
}
if (ExitConfirmationDialog != null)
{
ExitConfirmationDialog.GetOkButton().Pressed += () => GetTree().Quit();
}
await FadeOutBlack(1f, true);
}
private async Task FadeInBlack(float fadeTime, bool hide = false)
{
// 淡入黑色遮罩
ColorRect colorRect = GetNode<ColorRect>("ColorRect");
colorRect.SelfModulate = new Color(0, 0, 0, 0);
colorRect.Show();
Tween tween = CreateTween();
tween.TweenProperty(colorRect, "self_modulate", new Color(0, 0, 0, 1), fadeTime);
await ToSignal(tween, "finished");
if (hide) colorRect.Hide();
}
private async Task FadeOutBlack(float fadeTime, bool hide = false)
{
// 淡出黑色遮罩
ColorRect colorRect = GetNode<ColorRect>("ColorRect");
colorRect.SelfModulate = new Color(0, 0, 0, 1);
colorRect.Show();
Tween tween = CreateTween();
tween.TweenProperty(colorRect, "self_modulate", new Color(0, 0, 0, 0), fadeTime);
await ToSignal(tween, "finished");
if (hide) colorRect.Hide();
}
private void OnStartGameButtonPressed()
{
// 开始新游戏
GD.Print("Start New Game!");
StartConfirmationDialog?.PopupCentered();
}
private void OnLoadGameButtonPressed()
{
// 载入游戏
GD.Print("Load Game!");
// 使用动画效果显示存档列表
if (SavedSelection != null)
{
SavedSelection.SetIsSave(false);
SavedSelection.Show();
SavedSelection.GetNode<ColorRect>("ColorRect").GetNode<AnimationPlayer>("AnimationPlayer").Play("flyin");
}
}
private async void OnStartGameConfirmation()
{
await FadeInBlack(1f);
await Task.Delay(1000);
//GetTree().Quit();
// 加载第一章
GD.Print("LoadTitleScene!");
GetTree().ChangeSceneToFile("res://scenes/第一章.tscn");
}
private void OnGameSettingsButtonPressed()
{
// 打开游戏设置
GD.Print("Open Game Settings!");
}
private void OnExitGameButtonPressed()
{
// 退出游戏
if (ExitConfirmationDialog != null)
{
ExitConfirmationDialog.PopupCentered(); // 弹出对话框
}
else
{
GD.PrintErr("ExitConfirmationDialog is not connected!");
GetTree().Quit(); // 如果对话框未连接,则直接退出
}
}
public async void OnSaveSelectionClosed(bool selected, int index, bool isSave)
{
if (SavedSelection != null && !SavedSelection.IsClosing)
{
// 关闭存档选择界面
SavedSelection.IsClosing = true;
SavedSelection.GetNode<ColorRect>("ColorRect").GetNode<AnimationPlayer>("AnimationPlayer").Play("flyout");
await Task.Delay(300);
SavedSelection.IsClosing = false;
SavedSelection.Hide();
if (selected && index >= 0)
{
if (!isSave)
{
// 载入游戏
GD.Print($"Selected Saved: {index}!");
await FadeInBlack(1f);
await Task.Delay(1000);
GetTree().Quit();
}
}
else
{
GD.Print("Close SavedSelection!");
}
}
}
}

View File

@ -0,0 +1 @@
uid://cyi0j3meewtyt

20
scripts/UserInterface.cs Normal file
View File

@ -0,0 +1,20 @@
using Godot;
namespace Milimoe.GodotGame;
public partial class UserInterface : Control
{
[Export]
public Panel CharacterStatus1 { get; set; }
[Export]
public Panel CharacterStatus2 { get; set; }
[Export]
public Panel CharacterStatus3 { get; set; }
public override void _Ready()
{
}
}

View File

@ -0,0 +1 @@
uid://bc5cucvklcmrd