add code step 1

This commit is contained in:
cakipaul 2024-12-23 09:29:31 +08:00
parent e4fb9933ad
commit ac51d3031d
59 changed files with 2104 additions and 0 deletions

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

View File

@ -0,0 +1,64 @@
{
"items": [
{
"event_date": "12/22/2024",
"item_id": "876528753689",
"log_content": "* 完成动画导入功能:\n * 自动检测目录下文件,帧排序后,导入到: res://config/animation/player_sprite_frames.tres \n * 文件名 mapping 到动画 animation 名称\n * 取第一帧作动画\n * 镜像动画\n * 网格化检阅",
"tags": [
"2@code",
"3@art_tool",
"2@animation"
],
"update_date": "12/22/2024"
},
{
"event_date": "12/20/2024",
"item_id": "2546254798879",
"log_content": "* 游戏时间戳\n * 全局游戏时长记录\n * 当前存档时间状态:章节进度,游戏时长等\n* 场景管理器:发送消息浮窗\n* 事件系统:\n * 数据格式(四要素):\n * 时间chapter_section时间戳周目状态等\n * 地点场景id坐标\n * 实体实体id状态\n * 实体动作action_id\n * 流程:发送事件流程,消费事件流程\n* 存档:\n * 保存全局配置(如游戏总时长,周目数)\n * 分存档保存当前存档状态:时间、场景、实体\n* 组装实体:\n * 规格配置:进行中\n * 素材填充:进行中",
"tags": [
"2@code",
"2@design"
],
"update_date": "12/22/2024"
},
{
"event_date": "12/19/2024",
"item_id": "52643524662456",
"log_content": "* 角色移动状态机功能:静止/行走/奔跑/躺卧移动/上下爬行\n * 允许锁定移动/锁定奔跑,躺卧移动与上下爬行互斥\n* 规格化调整:\n * UI 规格化物品HUD对话浮窗\n * 场景规格化:层次背景,角色\n* 镜头 Marker :随玩家移动方向轻微偏移,优化视野细节",
"tags": [
"2@design",
"2@code",
"2@animation"
],
"update_date": "12/22/2024"
},
{
"event_date": "12/18/2024",
"item_id": "5423765786358",
"log_content": "确定资源类型,围绕规格化的资源\n基本工作流设计\n完善 HUD 功能",
"tags": [
"2@ui",
"2@design"
],
"update_date": "12/22/2024"
},
{
"event_date": "12/17/2024",
"item_id": "11242354",
"log_content": "加入基础的游戏背景、角色行走功能",
"tags": [
"2@code"
],
"update_date": "12/22/2024"
},
{
"event_date": "12/16/2024",
"item_id": "17343458739570",
"log_content": "新建项目等",
"tags": [
"2@design"
],
"update_date": "12/22/2024"
}
]
}

View File

@ -0,0 +1,140 @@
extends CanvasLayer
class_name ProjectLogPanel
enum TAG_TYPE{VERSION=0,FIX=1,FEATURE=2,TOOL=3}
const TAG_TYPE_COLOR_DICT = {
TAG_TYPE.VERSION: Color.SKY_BLUE,
TAG_TYPE.FIX: Color.RED,
TAG_TYPE.FEATURE: Color.AQUAMARINE,
TAG_TYPE.TOOL: Color.ORCHID
}
const TAG_DICT = {
TAG_TYPE.VERSION:["demo","0.1","1.0"],
TAG_TYPE.FIX:["bugfix","uxfix"],
TAG_TYPE.FEATURE:["code","design","ui","audio","art","animation"],
TAG_TYPE.TOOL:["art_tool","log_tool","manage_tool"],
}
#const LOG_CONFIG_KEY_prefix = "log_panel_json_"
const LOG_DATA_DIR = "res://log/logger/logs/"
var log_files = []
var current_log_file
const IMAGE_DIR = ""
@onready var add_btn := %Add
@onready var save_btn := %Save
@onready var archives_btn := %Archives as MenuButton
@onready var archives_label := %ArchiveLabel as Label
@onready var log_items_container = %LogItemsContainer
const LOG_ITEM_GROUP = "log_item"
const LOG_ITEM_GROUP_MENBER = "log_item[{0}]"
var log_item_scene = preload("res://log/logger/project_log_panel_item.tscn")
var data = {"items":[]} as Dictionary
func _ready():
add_btn.pressed.connect(_on_add)
save_btn.pressed.connect(save_logs)
archives_btn.get_popup().id_pressed.connect(_on_archive_switch)
_load_archives()
_on_archive_switch(log_files.find("v-demo-mountwuwang.json"))
# var quat = Quaternion.from_euler(Vector3(deg_to_rad(10),0,deg_to_rad(10)))
# print(quat)
# quat = quat.normalized()
# print(quat)
# quat = Quaternion(Vector3(1,0,0),deg_to_rad(10)) * Quaternion(Vector3(0,0,1),deg_to_rad(10))
# print(quat)
# quat = quat.normalized()
# print(quat)
func _load_archives():
log_files = DirAccess.get_files_at(LOG_DATA_DIR) as PackedStringArray
if log_files.size() == 0:
printerr("_load_archives no file exists:",LOG_DATA_DIR)
for i in range(0,log_files.size()):
archives_btn.get_popup().add_item(log_files[i],i)
_on_archive_switch(0)
func _load_logs():
var path = _get_curr_path()
if !FileAccess.file_exists(path):
printerr("_load_logs no file exists:",path)
return
var json = ResourceLoader.load(path,"",ResourceLoader.CACHE_MODE_IGNORE)
#print("load data=",json.data)
print("loaded data")
data = json.data
if !data.has("items"):
data["items"] = []
_refresh_items()
func _get_curr_path():
return LOG_DATA_DIR + current_log_file
func _refresh_items():
var items = data["items"] as Array
get_tree().call_group(LOG_ITEM_GROUP, "queue_free")
for i in range(items.size()):
var item_instance = log_item_scene.instantiate() as Control
item_instance.add_to_group(LOG_ITEM_GROUP)
item_instance.add_to_group(LOG_ITEM_GROUP_MENBER.format([]))
item_instance.update.connect(_on_log_item_update.bind(i))
#item_instance.save.connect(_on_log_item_save.bind(i))
item_instance.remove.connect(_on_log_item_remove.bind(i))
log_items_container.add_child(item_instance)
if items[i] is Dictionary:
item_instance.load_item(items[i])
elif items[i] is String:
var item_dict = JSON.parse_string(items[i])
item_instance.load_item(item_dict)
else :
push_error("unknow type items[",i,"]=",items[i])
func save_logs():
var path = _get_curr_path()
if !FileAccess.file_exists(path):
printerr("save_logs no file exists:",path)
return
#print("save logs data=", data)
print("saved logs")
var file := FileAccess.open(path, FileAccess.WRITE_READ) as FileAccess
file.store_string(JSON.stringify(data, "\t"))
file.close()
func _on_log_item_update(item:LogItem.ItemData, index:int):
var json = item.to_json_dict()
print("_on_log_item_update item=", json)
data["items"][index] = json
func _on_log_item_save(item:LogItem.ItemData, index:int):
var json = item.to_json_dict()
print("_on_log_item_save item=", json)
data["items"][index] = json
save_logs()
func _on_log_item_remove(index:int):
(data["items"] as Array).remove_at(index)
save_logs()
# reset index for each item
_refresh_items()
func _on_add():
(data["items"] as Array).push_front({})
save_logs()
# reset index for each item
_refresh_items()
func _on_archive_switch(id:int):
current_log_file = log_files[id]
archives_label.text = log_files[id]
_load_logs()
func _unhandled_input(event):
if event.is_action("save"):
save_logs()

View File

@ -0,0 +1,119 @@
[gd_scene load_steps=4 format=3 uid="uid://b3n06jtdpqy5y"]
[ext_resource type="Script" path="res://log/logger/project_log_panel.gd" id="1_2rhk7"]
[ext_resource type="PackedScene" uid="uid://bdy4u3e7rmo7f" path="res://ui/button/sound_button.tscn" id="2_71u5c"]
[ext_resource type="PackedScene" uid="uid://dhvo15vyxpkja" path="res://log/logger/project_log_panel_item.tscn" id="4_1yhgi"]
[node name="ProjectLogPanel" type="CanvasLayer"]
script = ExtResource("1_2rhk7")
[node name="MarginContainer" type="MarginContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/margin_left = 12
theme_override_constants/margin_top = 6
theme_override_constants/margin_right = 12
theme_override_constants/margin_bottom = 6
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/MarginContainer"]
layout_mode = 2
size_flags_vertical = 4
alignment = 2
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 4
theme_override_constants/margin_left = 12
theme_override_constants/margin_top = 6
theme_override_constants/margin_right = 12
theme_override_constants/margin_bottom = 6
[node name="Title" type="Label" parent="MarginContainer/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 4
theme_override_colors/font_color = Color(0.670588, 0.952941, 0.972549, 1)
theme_override_colors/font_shadow_color = Color(0.180392, 0.180392, 0.180392, 1)
theme_override_colors/font_outline_color = Color(0.0156863, 0.258824, 0.341176, 1)
theme_override_constants/shadow_offset_x = 2
theme_override_constants/shadow_offset_y = 2
theme_override_constants/outline_size = 4
theme_override_constants/shadow_outline_size = 12
theme_override_font_sizes/font_size = 24
text = "Project Log"
[node name="Add" parent="MarginContainer/VBoxContainer/MarginContainer/HBoxContainer" instance=ExtResource("2_71u5c")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
text = "Add"
script = null
[node name="Save" parent="MarginContainer/VBoxContainer/MarginContainer/HBoxContainer" instance=ExtResource("2_71u5c")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
text = "Save"
script = null
[node name="Archives" type="MenuButton" parent="MarginContainer/VBoxContainer/MarginContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
text = "Archives"
flat = false
[node name="ArchiveLabel" type="Label" parent="MarginContainer/VBoxContainer/MarginContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
[node name="MarginContainer2" type="MarginContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer/MarginContainer2"]
layout_mode = 2
size_flags_vertical = 3
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/MarginContainer2/ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 4
[node name="LogItemsContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/MarginContainer2/ScrollContainer/MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 0
alignment = 1
[node name="LogItem" parent="MarginContainer/VBoxContainer/MarginContainer2/ScrollContainer/MarginContainer/LogItemsContainer" instance=ExtResource("4_1yhgi")]
visible = false
layout_mode = 2
[node name="LogItem2" parent="MarginContainer/VBoxContainer/MarginContainer2/ScrollContainer/MarginContainer/LogItemsContainer" instance=ExtResource("4_1yhgi")]
visible = false
layout_mode = 2

View File

@ -0,0 +1,198 @@
extends HBoxContainer
class_name LogItem
#signal save(data:ItemData)
signal update(data: ItemData)
signal remove
const TAG_BTN_GROUP_PREFIX = "tag_btn"
@onready var log_content := %LogContent as TextEdit
@onready var event_date := %EventDate as Label
#@onready var update_date := %LogUpdateDate as Label
@onready var tags_container := %TagsContainer as GridContainer
@onready var add_tag_btn := %AddTag as MenuButton
@onready var reload_btn = %Reload
@onready var save_btn = %Save
@onready var delete_btn = %Delete
var original_data := ItemData.new()
var data: ItemData = original_data
class ItemData:
var item_id := _generate_random_id()
var log_content := "":
set(new_val):
if new_val != log_content:
update_date = _get_current_time()
log_content = new_val
var tags := []:
set(new_val):
update_date = _get_current_time()
tags = new_val
var event_date := _get_current_time()
var update_date := _get_current_time()
func _generate_random_id() -> String:
# float time
var timestamp := Time.get_unix_time_from_system()
return str(int(timestamp * 10000 + randi_range(0, 10000)))
func _get_current_time() -> String:
# Returns the current date as a dictionary of keys: year, month, day, and weekday.
var dict = Time.get_date_dict_from_system()
return str(dict["month"]) + "/" + str(dict["day"]) + "/" + str(dict["year"])
func duplicate() -> ItemData:
var item := ItemData.new()
item.item_id = item_id
item.log_content = log_content
item.tags = tags.duplicate()
item.event_date = event_date
item.update_date = update_date
return item
func to_json_dict() -> Dictionary:
# JSON.stringify(self) doesn't work
return {
"item_id": item_id,
"log_content": log_content,
"tags": tags,
"event_date": event_date,
"update_date": update_date,
}
static func parse(data: Dictionary) -> ItemData:
var item := ItemData.new()
if data.has("item_id"):
item.item_id = data["item_id"]
if data.has("tags"):
item.tags = data["tags"]
if data.has("log_content"):
item.log_content = data["log_content"]
if data.has("event_date"):
item.event_date = data["event_date"]
if data.has("update_date"):
item.update_date = data["update_date"]
return item
# {id:{"btn":btn,"key":key,"name":name,"id":id}}
static var tag_btns = {}
static var tag_key_to_id_map = {}
static var tag_shadow_color = Color.html("1b1b1b")
static var tag_shadow_outline_size = 1
# id->key
var current_tags = {}
func _ready():
_load_tag_popup()
reload_btn.pressed.connect(_on_reload_pressed)
#save_btn.pressed.connect(_save_item)
delete_btn.pressed.connect(_remove_signal)
log_content.text_changed.connect(_on_log_content_changed)
call_deferred("_update_signal")
#load_item(original_data)
static func _static_init():
var tag_id := 0
for tag_type in ProjectLogPanel.TAG_TYPE.values():
var tag_color = ProjectLogPanel.TAG_TYPE_COLOR_DICT[tag_type]
for tag in ProjectLogPanel.TAG_DICT[tag_type]:
var tag_btn = Button.new() as Button
tag_btn.add_theme_color_override("font_color", tag_color)
tag_btn.add_theme_color_override("font_shadow_color", tag_shadow_color)
tag_btn.add_theme_constant_override("shadow_outline_size", tag_shadow_outline_size)
tag_btn.text = tag
var tag_key = _get_tag_key(tag_type, tag)
tag_btns[tag_id] = {"btn": tag_btn, "id": tag_id, "name": tag, "key": tag_key}
tag_key_to_id_map[tag_key] = tag_id
tag_id += 1
static func _get_tag_key(tag_type: ProjectLogPanel.TAG_TYPE, tag: String):
return str(tag_type) + "@" + tag
func _load_tag_popup():
var popup = add_tag_btn.get_popup() as PopupMenu
for btn_dict in tag_btns.values():
popup.add_item(btn_dict["name"], btn_dict["id"])
popup.id_pressed.connect(_on_popup_menu_pressed)
func _reload_tag_btns():
var btn_group = TAG_BTN_GROUP_PREFIX + data.item_id
get_tree().call_group(btn_group, "queue_free")
current_tags.clear()
for tag_key in data["tags"]:
if !tag_key_to_id_map.has(tag_key):
push_error("tag_key has been removed!! tag_key=", tag_key)
continue
var tag_id = tag_key_to_id_map[tag_key]
current_tags[tag_id] = tag_key
var btn = (tag_btns[tag_id]["btn"] as Button).duplicate()
btn.pressed.connect(_on_tag_btn_pressed.bind(btn, tag_id))
btn.add_to_group(btn_group)
tags_container.add_child(btn)
func load_item(new_data: Dictionary):
if new_data.keys().size() != 0:
original_data = ItemData.parse(new_data)
_reload_original_data()
func _reload_original_data():
data = original_data.duplicate()
#print("_load_item_data data=", data)
log_content.text = data.log_content
event_date.text = data.event_date
#update_date.text = data["update_date"]
_reload_tag_btns()
func _on_popup_menu_pressed(id: int):
#{"btn":btn,"key":key,"name":name,"id":id}
if !current_tags.has(id):
current_tags[id] = tag_btns[id]["key"]
data.tags = current_tags.values()
_update_signal()
#_save_item()
_reload_tag_btns()
func _on_log_content_changed():
data["log_content"] = log_content.text
_update_signal()
func _on_tag_btn_pressed(btn: Control, id: int):
current_tags.erase(id)
btn.queue_free()
data.tags = current_tags.values()
_update_signal()
#_save_item()
#func _save_item():
#save.emit(data)
func _update_signal():
update.emit(data)
func _remove_signal():
remove.emit()
func _on_reload_pressed():
_reload_original_data()
_update_signal()

View File

@ -0,0 +1,86 @@
[gd_scene load_steps=3 format=3 uid="uid://dhvo15vyxpkja"]
[ext_resource type="Script" path="res://log/logger/project_log_panel_item.gd" id="1_gn7ev"]
[ext_resource type="PackedScene" uid="uid://bdy4u3e7rmo7f" path="res://ui/button/sound_button.tscn" id="2_wb6pu"]
[node name="LogItem" type="HBoxContainer"]
anchors_preset = 14
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_top = -4.0
offset_bottom = 4.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_gn7ev")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
[node name="LogContent" type="TextEdit" parent="MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "123"
wrap_mode = 1
scroll_fit_content_height = true
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="TagsContainer" type="GridContainer" parent="HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
columns = 2
[node name="AddTag" type="MenuButton" parent="HBoxContainer/TagsContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Tags"
[node name="VBoxContainer2" type="VBoxContainer" parent="."]
layout_mode = 2
[node name="EventDate" type="Label" parent="VBoxContainer2"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0.929412, 0.929412, 0.929412, 1)
theme_override_colors/font_shadow_color = Color(0.105882, 0.105882, 0.105882, 1)
theme_override_constants/shadow_offset_x = 1
theme_override_constants/shadow_offset_y = 1
theme_override_constants/shadow_outline_size = 4
text = "01/01/24"
[node name="LogUpdateDate" type="Label" parent="VBoxContainer2"]
unique_name_in_owner = true
visible = false
layout_mode = 2
text = "01/01/24"
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer2"]
layout_mode = 2
[node name="Reload" parent="VBoxContainer2/HBoxContainer" instance=ExtResource("2_wb6pu")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
text = "Reload"
script = null
[node name="Save" parent="VBoxContainer2/HBoxContainer" instance=ExtResource("2_wb6pu")]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
text = "Save"
script = null
[node name="Delete" parent="VBoxContainer2/HBoxContainer" instance=ExtResource("2_wb6pu")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
text = "Delete"
script = null

View File

@ -0,0 +1,125 @@
extends Node
@export var user_archive_root_dir := "user://archive/" # must end with "/"
@export var save_dir_prefix := "save"
var accessible := false
var archives: Array[int] # archive id list in ascending order
var managers = {
"TimeManager": TimeManager,
"EntityManager": EntityManager,
"SceneManager": SceneManager,
"InputManager": InputManager,
# "ArchiveManager" : ArchiveManager, #self
# "AudioManager" : AudioManager,
# "EventManager" : EventManager,
# "CameraManager" : CameraManager,
# "DialogManager" : DialogManager,
# "CgManager": CgManager,
}
var autosave_timer := Timer.new()
func _ready() -> void:
accessible = _check_archive_dirs()
if !accessible:
return
# _open_log_file()
add_child(autosave_timer)
autosave_timer.wait_time = GlobalConfigManager.config.auto_save_seconds
autosave_timer.one_shot = false
autosave_timer.timeout.connect(_try_auto_save)
autosave_timer.stop()
GlobalConfigManager.config.current_selected_save_changed.connect(_check_autosave_options)
GlobalConfigManager.config.auto_save_seconds_changed.connect(_check_autosave_options)
load_all()
SceneManager.pop_notification("预加载完成")
func _check_autosave_options():
if (
GlobalConfigManager.config.auto_save_seconds > 5
and GlobalConfigManager.config.current_selected_save >= 0
):
autosave_timer.start()
else:
autosave_timer.stop()
func _try_auto_save():
if (
GlobalConfigManager.config.auto_save_seconds > 5
and GlobalConfigManager.config.current_selected_save >= 0
):
save_all()
SceneManager.pop_notification("自动保存成功")
func _check_archive_dirs() -> bool:
# Check if the archive directory is accessible
if !DirAccess.dir_exists_absolute(user_archive_root_dir):
DirAccess.make_dir_recursive_absolute(user_archive_root_dir)
print("Create archive directory:", user_archive_root_dir)
var archive_dir_access = DirAccess.open(user_archive_root_dir)
if !archive_dir_access:
printerr("Archive directory is not accessible")
# TODO pop up a dialog to inform the user
return false
var files = archive_dir_access.get_files()
# get archive number
for file in files:
if file.begins_with(save_dir_prefix):
var id_str = file.substr(save_dir_prefix.length())
var id = int(id_str)
archives.append(id)
archives.sort()
return true
func save_all() -> void:
# save config
var config = GlobalConfigManager.config
var path = user_archive_root_dir + "config" + GlobalConfig.RES_FILE_FORMAT
ResourceSaver.save(config, path)
if not accessible or GlobalConfigManager.config.current_selected_save == -1:
return
# Save all managers by the current selected save
for manager in managers:
# .tres
var res = managers[manager].get_data_res()
if !res:
continue
# save to file
path = (
user_archive_root_dir
+ str(config.current_selected_save)
+ "/"
+ manager
+ GlobalConfig.RES_FILE_FORMAT
)
ResourceSaver.save(res, path)
func load_all() -> void:
_check_archive_dirs()
# load config
var path = user_archive_root_dir + "config" + GlobalConfig.RES_FILE_FORMAT
var config
if FileAccess.file_exists(path):
config = ResourceLoader.load(path)
GlobalConfigManager.load_data_res(config)
else:
config = GlobalConfigManager.config
# save config
ResourceSaver.save(config, path)
if not accessible or config.current_selected_save == -1:
return
# Load managers by the current selected save
path = user_archive_root_dir + save_dir_prefix + str(config.current_selected_save) + "/"
for manager in managers:
var manager_path = path + manager + GlobalConfig.RES_FILE_FORMAT
if FileAccess.file_exists(manager_path):
var res = ResourceLoader.load(manager_path)
managers[manager].load_data_res(res)

View File

@ -0,0 +1 @@
class_name AssetMetadata extends Resource

View File

@ -0,0 +1,11 @@
extends Node
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass

View File

@ -0,0 +1,11 @@
class_name AssetMetadata extends Resource
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass

View File

@ -0,0 +1,18 @@
extends Node
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
func get_data_res() -> Resource:
return null
func load_data_res(data: Resource) -> void:
pass

View File

@ -0,0 +1,15 @@
extends Node
func pop_notification(msg: String, number := 1) -> void:
var notification_node = get_node_or_null("/root/Main/UILayer/Notification")
if notification_node:
notification_node.show_notification(msg, number)
else:
printerr("Notification node not found")
func get_data_res() -> Resource:
return null
func load_data_res(data: Resource) -> void:
pass

View File

@ -0,0 +1,11 @@
extends Node
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass

View File

@ -0,0 +1,11 @@
extends Node
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass

View File

@ -0,0 +1,11 @@
extends Node
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass

View File

@ -0,0 +1,34 @@
class_name GlobalConfig extends Resource
# .res would be binary encoded, .tres is text encoded
const RES_FILE_FORMAT = ".tres"
const CONFIG_FILE_NAME = "config"
const DEBUG = true
#const DEBUG = false
const CANVAS_LAYER_VIGNETTE = 1000
const CANVAS_LAYER_PROP_INSPECTOR = 100
const CANVAS_LAYER_UI = 99
const CANVAS_LAYER_FG = 50
const CANVAS_LAYER_BG = -100
const COLOR_BOARDER = Color.BLACK
const _ART_RESOURCE_BASE_DIR = "res://asset/art/"
signal current_selected_save_changed
signal auto_save_seconds_changed
# 注意:编辑与新增属性时,需要同时编辑 GlobalConfigManager.gd 中的 load_data_res 方法
@export var game_total_seconds := 0 # 游戏总时长
@export var game_rounds := 1 # 当前周目数
@export var current_selected_save := -1: # 当前选定存档 id, -1 means no save selected
set(val):
current_selected_save = val
current_selected_save_changed.emit()
@export var auto_save_seconds := 60:
set(val):
auto_save_seconds = val
auto_save_seconds_changed.emit()

View File

@ -0,0 +1,15 @@
extends Node
var config = GlobalConfig.new()
func get_data_res() -> Resource:
return config
func load_data_res(data: Resource) -> void:
var new_config = data as GlobalConfig
config.game_total_seconds = new_config.game_total_seconds
config.game_rounds = new_config.game_rounds
config.current_selected_save = new_config.current_selected_save
config.auto_save_seconds = new_config.auto_save_seconds

View File

@ -0,0 +1,31 @@
extends Node
# 事件注册表
# { entity: [MatcherConsumer] }
var _event_registry: Dictionary = {}
class MatcherConsumer extends RefCounted:
var _matcher: GameEventMatcher
var _consumer: Callable
func _init(matcher: GameEventMatcher, consumer: Callable) -> void:
self._matcher = matcher
self._consumer = consumer
# 注册事件
func register_event_matcher(event_matcher: GameEventMatcher, consumer: Callable) -> void:
if !event_matcher.entity:
return
var matcher_consumer = MatcherConsumer.new(event_matcher, consumer)
if event_matcher.entity not in _event_registry:
_event_registry[event_matcher.entity] = []
_event_registry[event_matcher.entity].append(matcher_consumer)
# 触发事件
func trigger_event(event: GameEvent) -> void:
if event.entity not in _event_registry:
return
for matcher_consumer in _event_registry[event.entity]:
# matcher_consumer = matcher_consumer as MatcherConsumer
if matcher_consumer._matcher.match(event):
matcher_consumer._consumer.call(event)

View File

@ -0,0 +1,19 @@
class_name GameEvent extends Resource
# * 事件&剧情管理器: player / release / debug 事件,触发者:玩家/系统(系统触发意味着进入 CG
# * 事件定义:「通变之谓事」
# * 事件发送机制:玩家进行特定操作后,发送事件进度(开始(注意到),尝试&进度完成成功or失败
# * 发送内容
# * 时间点:玩家现实时间(系统时间),游戏时长(时间戳),章节剧情时间点(事件编号)
# * 地点:场景编号,位置坐标
# * 实体:道具/NPC/部署点
# * 激发器类型:地图区域(手动部署) / 玩家特定操作(自动发送)/ 实体信号(监听玩家特定操作/状态变化)
# * 事件订阅机制:订阅开始/进度/成功/失败,触发特定响应
# * 消费器能力:执行 CG锁定/无锁定,剧本/特效) / 执行实体变化脚本(赠送/消耗/状态变化)
# * 保存与加载
@export var event_id: int
@export var packed_time: PackedTime
@export var scene: String
@export var scene_position: Vector2
@export var entity: String
@export var entity_action: String

View File

@ -0,0 +1,43 @@
class_name GameEventMatcher extends Resource
# match event under certain conditions
# can't be empty
@export var entity: String
# empty means any action
@export var entity_actions: Array[String]
# empty means any scene
@export var scenes: Array[String]
# regex matcher, "[chapter]_[section]", * means any
# e.g. 3_* means any section in chapter 3
# empty means any chapter_section
@export var chapter_section: Array[String]
# check if the event matches the conditions
func match(event: GameEvent) -> bool:
if !entity or entity != event.entity:
return false
if entity_actions.size() > 0 and !entity_actions.has(event.entity_action):
return false
if scenes.size() > 0 and !scenes.has(event.scene):
return false
if chapter_section.size() > 0:
var chapter := str(event.packed_time.chapter)
var section := str(event.packed_time.section)
var matched := false
for chapter_section_matcher in chapter_section:
# regex match
var parts = chapter_section_matcher.split("_")
if parts.size() != 2:
continue
var chapter_matcher = parts[0]
var section_matcher = parts[1]
if chapter_matcher == "*" or chapter_matcher == chapter:
matched = true
break
if section_matcher == "*" or section_matcher == section:
matched = true
break
if !matched:
return false
return true

View File

@ -0,0 +1,19 @@
extends Node
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
func get_data_res() -> Resource:
return null
func load_data_res(data: Resource) -> void:
pass

View File

@ -0,0 +1,12 @@
class_name PackedTime extends Resource
# 系统时间,游戏时长,章节时间点
@export var game_archive_id := 0
@export var game_rounds := 0
@export var timestamp := "2024-12-20 08:00:00" #system
@export var game_seconds_all := 0 #game seconds since current archive start
@export var game_seconds_current := 0 #game seconds since last chapter
@export var chapter := 0 #chapter id
@export var section := 0 #section id

View File

@ -0,0 +1,63 @@
extends Node
@export var current_chapter := 0
@export var current_section := 0
@export var game_seconds_all := 0
@export var game_seconds_current := 0
var timer: Timer
func _ready() -> void:
timer = Timer.new()
timer.wait_time = 1
timer.one_shot = false
timer.timeout.connect(_on_timer_timeout)
add_child(timer)
timer.start()
func _on_timer_timeout():
game_seconds_all += 1
game_seconds_current += 1
GlobalConfigManager.config.game_total_seconds += 1
func pack_current_time():
var packed_time = PackedTime.new()
packed_time.time = Time.get_datetime_string_from_system(false, true)
packed_time.chapter = current_chapter
packed_time.section = current_section
packed_time.game_archive_id = ArchiveManager.current_archive_id
packed_time.game_seconds_all = game_seconds_all
packed_time.game_seconds_current = game_seconds_current
# for log use
func get_concise_timemark() -> String:
var hour := game_seconds_current / 3600 as int
var minute := (game_seconds_current % 3600) / 60 as int
var second := game_seconds_current % 60
return (
"r"
+ str(ArchiveManager.current_archive_id)
+ "_c"
+ str(current_chapter)
+ "_s"
+ str(current_section)
+ " "
+ str(hour)
+ ":"
+ str(minute)
+ ":"
+ str(second)
)
func get_data_res() -> Resource:
return pack_current_time()
func load_data_res(data: Resource) -> void:
var packed_time = data as PackedTime
game_seconds_all = packed_time.game_seconds_all
game_seconds_current = packed_time.game_seconds_current
current_chapter = packed_time.chapter
current_section = packed_time.section

114
project.godot Normal file
View File

@ -0,0 +1,114 @@
; 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
[addons]
resources_spreadsheet_view/array_color_tint=100.0
resources_spreadsheet_view/color_rows=true
resources_spreadsheet_view/array_min_width=128.0
resources_spreadsheet_view/resource_preview_size=32.0
resources_spreadsheet_view/clip_headers=false
resources_spreadsheet_view/dupe_arrays=true
resources_spreadsheet_view/context_menu_on_leftclick=false
[application]
config/name="xiandie"
run/main_scene="res://scene/main.tscn"
config/features=PackedStringArray("4.3", "Mobile")
config/icon="res://icon.svg"
[audio]
buses/default_bus_layout="res://config/default_bus_layout.tres"
[autoload]
DebugMenu="*res://addons/debug_menu/debug_menu.tscn"
GlobalConfigManager="*res://manager/config_manager/global_config_manager.gd"
TimeManager="*res://manager/time_manager/time_manager.gd"
EntityManager="*res://manager/assemble/entity/entity_manager.gd"
SceneManager="*res://manager/assemble/scene/scene_manager.gd"
AudioManager="*res://manager/audio_manager/audio_manager.gd"
EventManager="*res://manager/event_manager/event_manager.gd"
DialogManager="*res://manager/assemble/dialog/dialog_manager.gd"
CameraManager="*res://manager/camera_manager/camera_manager.gd"
CgManager="*res://manager/cg_manager/cg_manager.gd"
InputManager="*res://manager/input/input_manager.gd"
ArchiveManager="*res://manager/archive_manager/archive_manager.gd"
[display]
window/size/viewport_width=564
window/size/viewport_height=317
window/size/window_width_override=1692
window/size/window_height_override=951
window/stretch/mode="canvas_items"
window/stretch/scale_mode="integer"
[editor_plugins]
enabled=PackedStringArray("res://addons/debug_menu/plugin.cfg", "res://addons/project-statistics/plugin.cfg")
[gui]
theme/custom="res://config/default_theme.tres"
theme/custom_font="res://asset/font/zpix-commercial-one-grand.ttf"
[input]
save={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"command_or_control_autoremap":true,"alt_pressed":false,"shift_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
up={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
down={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
left={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
right={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
run={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
jump={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
]
}
[rendering]
textures/canvas_textures/default_texture_filter=0
renderer/rendering_method="mobile"
[statistics]
force_include=PackedStringArray()

View File

@ -0,0 +1,6 @@
extends Marker2D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.

View File

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cqkeegrcdjyg4"]
[ext_resource type="Script" path="res://scene/camera/camera_focus_marker.gd" id="1_7t4e6"]
[node name="CameraFocusMarker" type="Marker2D"]
script = ExtResource("1_7t4e6")

View File

@ -0,0 +1,9 @@
extends Camera2D
class_name MainCamera
func _ready() -> void:
enabled = true
#position_smoothing_enabled = false
position_smoothing_speed = 10
position_smoothing_enabled = true

View File

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://ogyvstscr0kx"]
[ext_resource type="Script" path="res://scene/camera/main_camera.gd" id="1_pwiuw"]
[node name="MainCamera" type="Camera2D"]
script = ExtResource("1_pwiuw")

View File

@ -0,0 +1 @@
extends Control

View File

@ -0,0 +1,44 @@
[gd_scene load_steps=3 format=3 uid="uid://dmkt1roqc4he7"]
[ext_resource type="Script" path="res://scene/dialog/dialog_container.gd" id="1_s1ka3"]
[ext_resource type="Theme" uid="uid://j42sexotwnvk" path="res://config/default_theme.tres" id="2_q6yks"]
[node name="DialogContainer" type="MarginContainer"]
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -86.0
grow_horizontal = 2
grow_vertical = 0
size_flags_vertical = 8
theme_override_constants/margin_left = 32
theme_override_constants/margin_top = 16
theme_override_constants/margin_right = 32
theme_override_constants/margin_bottom = 42
script = ExtResource("1_s1ka3")
[node name="DialogPanelContainer" type="PanelContainer" parent="."]
layout_mode = 2
[node name="DialogMarginContainer" type="MarginContainer" parent="DialogPanelContainer"]
layout_mode = 2
theme = ExtResource("2_q6yks")
theme_type_variation = &"dialog_container"
theme_override_constants/margin_left = 12
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 12
theme_override_constants/margin_bottom = 8
[node name="RichTextLabel" type="RichTextLabel" parent="DialogPanelContainer/DialogMarginContainer"]
custom_minimum_size = Vector2(460, 0)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
mouse_filter = 2
text = "Dialog: test
2
3
4
5"
fit_content = true

View File

@ -0,0 +1,8 @@
extends Control
@onready var color_top := %ColorRectTop as ColorRect
@onready var color_bottom := %ColorRectBottom as ColorRect
func _ready() -> void:
color_top.color = GlobalConfig.COLOR_BOARDER
color_bottom.color = GlobalConfig.COLOR_BOARDER

View File

@ -0,0 +1,41 @@
[gd_scene load_steps=2 format=3 uid="uid://o4a2eluydtep"]
[ext_resource type="Script" path="res://scene/ground/boarder_frame.gd" id="1_50vde"]
[node name="BoarderFrame" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_50vde")
[node name="ColorRectTop" type="ColorRect" parent="."]
unique_name_in_owner = true
custom_minimum_size = Vector2(564, 38.5)
layout_mode = 1
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -282.0
offset_right = 282.0
offset_bottom = 40.0
grow_horizontal = 2
color = Color(0.372549, 0.0156863, 0.0156863, 1)
[node name="ColorRectBottom" type="ColorRect" parent="."]
unique_name_in_owner = true
custom_minimum_size = Vector2(564, 38.5)
layout_mode = 1
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -282.0
offset_top = -38.5
offset_right = 282.0
grow_horizontal = 2
grow_vertical = 0
color = Color(0.372549, 0.0156863, 0.0156863, 1)

View File

@ -0,0 +1,12 @@
extends ParallaxBackground
#
## Called every frame. 'delta' is the elapsed time since the previous frame.
#func _physics_process(delta: float) -> void:
#var x = Input.get_axis("left", "right")
#var y = Input.get_axis("up", "down")
#camera.position.x += delta * x * 1000
#camera.position.y += delta * y * 1000
func _ready() -> void:
layer = GlobalConfig.CANVAS_LAYER_BG

View File

@ -0,0 +1,15 @@
[gd_scene load_steps=3 format=3 uid="uid://d0mnndg67dru1"]
[ext_resource type="Script" path="res://scene/ground/parallax_background.gd" id="1_w8735"]
[ext_resource type="Texture2D" uid="uid://dukm6cix2kghn" path="res://asset/art/第一章/场景五1012外间现实版/1012外间.png" id="2_6t5qy"]
[node name="ParallaxBackground" type="ParallaxBackground"]
scroll_base_offset = Vector2(-250, -200)
script = ExtResource("1_w8735")
[node name="ParallaxLayer" type="ParallaxLayer" parent="."]
[node name="Sprite2D" type="Sprite2D" parent="ParallaxLayer"]
scale = Vector2(1.33649, 1.32083)
texture = ExtResource("2_6t5qy")
centered = false

View File

@ -0,0 +1,5 @@
extends ParallaxBackground
func _ready() -> void:
layer = GlobalConfig.CANVAS_LAYER_FG

View File

@ -0,0 +1,21 @@
[gd_scene load_steps=4 format=3 uid="uid://02lmmldikfar"]
[ext_resource type="Script" path="res://scene/ground/parallax_foreground.gd" id="1_32n5c"]
[ext_resource type="Texture2D" uid="uid://c0l7pkwvbrgey" path="res://asset/art/第一章/场景五1012外间现实版/前景.png" id="3_4g2yq"]
[ext_resource type="PackedScene" uid="uid://o4a2eluydtep" path="res://scene/ground/boarder_frame.tscn" id="4_18dtv"]
[node name="ParallaxForeground" type="ParallaxBackground"]
scroll_base_offset = Vector2(-250, -200)
script = ExtResource("1_32n5c")
[node name="ParallaxLayer2" type="ParallaxLayer" parent="."]
motion_scale = Vector2(1.1, 1.1)
motion_mirroring = Vector2(2000, 1300)
[node name="Sprite2D" type="Sprite2D" parent="ParallaxLayer2"]
position = Vector2(2, 73)
scale = Vector2(1.33886, 1.05)
texture = ExtResource("3_4g2yq")
centered = false
[node name="ShadedFrame" parent="." instance=ExtResource("4_18dtv")]

1
scene/hud/prop_hud.gd Normal file
View File

@ -0,0 +1 @@
extends Control

85
scene/hud/prop_hud.tscn Normal file
View File

@ -0,0 +1,85 @@
[gd_scene load_steps=12 format=3 uid="uid://dc778gsjfr3ky"]
[ext_resource type="Script" path="res://scene/hud/prop_hud.gd" id="1_bbv0a"]
[ext_resource type="Texture2D" uid="uid://chyumeohdhwnh" path="res://asset/art/ui/道具快捷栏/normal_left.png" id="2_bjc2b"]
[ext_resource type="Texture2D" uid="uid://cvepj6u80c5wv" path="res://asset/art/ui/道具快捷栏/pressed_left.png" id="3_fca7p"]
[ext_resource type="Script" path="res://ui/button/sound_texture_button.gd" id="3_xijdf"]
[ext_resource type="Texture2D" uid="uid://bospbmb0gr2sb" path="res://asset/art/ui/道具快捷栏/Prop.png" id="5_6tt77"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="5_wmvnw"]
[ext_resource type="Resource" uid="uid://cor5ec6ogq3fe" path="res://config/audio/casino/card_slide.tres" id="6_32vbt"]
[ext_resource type="Texture2D" uid="uid://optvgar5g2c" path="res://asset/art/道具/第一章/绳子物品.png" id="8_kpmil"]
[ext_resource type="Texture2D" uid="uid://bgsbwhy1c2jna" path="res://asset/art/ui/道具快捷栏/hand.png" id="9_0crjo"]
[ext_resource type="Texture2D" uid="uid://boqpr7i2a5uan" path="res://asset/art/ui/道具快捷栏/normal_right.png" id="10_vkaik"]
[ext_resource type="Texture2D" uid="uid://daj2n408y2vfp" path="res://asset/art/ui/道具快捷栏/pressed_right.png" id="11_a512b"]
[node name="PropHUD" type="HBoxContainer"]
offset_left = 10.0
offset_top = 4.0
offset_right = 98.0
offset_bottom = 36.0
scale = Vector2(0.3, 0.3)
script = ExtResource("1_bbv0a")
[node name="LeftMargin" type="MarginContainer" parent="."]
layout_mode = 2
theme_override_constants/margin_left = 8
[node name="LeftButton" type="TextureButton" parent="LeftMargin"]
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("2_bjc2b")
texture_pressed = ExtResource("3_fca7p")
stretch_mode = 5
script = ExtResource("3_xijdf")
[node name="HudPanel" type="TextureButton" parent="."]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("5_6tt77")
stretch_mode = 5
script = ExtResource("3_xijdf")
audio_collections = Array[ExtResource("5_wmvnw")]([ExtResource("6_32vbt")])
[node name="Prop" type="TextureRect" parent="HudPanel"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -73.0
offset_top = -41.0
offset_right = 73.0
offset_bottom = 41.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("8_kpmil")
[node name="Mark" type="TextureRect" parent="HudPanel"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -14.0
offset_top = -15.0
grow_horizontal = 0
grow_vertical = 0
texture = ExtResource("9_0crjo")
[node name="RightMargin" type="MarginContainer" parent="."]
layout_mode = 2
theme_override_constants/margin_right = 8
[node name="RightButton" type="TextureButton" parent="RightMargin"]
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
texture_normal = ExtResource("10_vkaik")
texture_pressed = ExtResource("11_a512b")
stretch_mode = 5
script = ExtResource("3_xijdf")

View File

@ -0,0 +1,16 @@
[gd_scene load_steps=3 format=3 uid="uid://dpgmgc5qf0apc"]
[sub_resource type="GDScript" id="GDScript_5nh3u"]
script/source = "extends StaticBody2D
func _ready() -> void:
pass"
[sub_resource type="RectangleShape2D" id="RectangleShape2D_gyjm3"]
size = Vector2(38, 38)
[node name="PropHudItem2D" type="StaticBody2D"]
script = SubResource("GDScript_5nh3u")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_gyjm3")

4
scene/main.gd Normal file
View File

@ -0,0 +1,4 @@
extends Node2D
func _ready() -> void:
$UILayer.layer = GlobalConfig.CANVAS_LAYER_VIGNETTE

48
scene/main.tscn Normal file
View File

@ -0,0 +1,48 @@
[gd_scene load_steps=12 format=3 uid="uid://dygvcmykn02n8"]
[ext_resource type="PackedScene" uid="uid://d0mnndg67dru1" path="res://scene/ground/parallax_background.tscn" id="1_f7g4d"]
[ext_resource type="Script" path="res://scene/main.gd" id="1_pks84"]
[ext_resource type="PackedScene" uid="uid://3gk1gxwanw24" path="res://ui/vignette/vignette_shading.tscn" id="2_d1re1"]
[ext_resource type="PackedScene" uid="uid://dmkt1roqc4he7" path="res://scene/dialog/dialog_container.tscn" id="3_prpss"]
[ext_resource type="PackedScene" uid="uid://dc778gsjfr3ky" path="res://scene/hud/prop_hud.tscn" id="4_t7gb2"]
[ext_resource type="PackedScene" uid="uid://5g07x6q7wwr1" path="res://scene/notification/notification.tscn" id="5_3gg5t"]
[ext_resource type="PackedScene" uid="uid://cekhj65axie0p" path="res://scene/popup/prop_inspector_2d.tscn" id="5_ux0rw"]
[ext_resource type="PackedScene" uid="uid://cjhw5ecygrqty" path="res://scene/player/player_2d.tscn" id="6_6geb0"]
[ext_resource type="PackedScene" uid="uid://cqkeegrcdjyg4" path="res://scene/camera/camera_focus_marker.tscn" id="7_n7qcv"]
[ext_resource type="PackedScene" uid="uid://ogyvstscr0kx" path="res://scene/camera/main_camera.tscn" id="8_nj084"]
[ext_resource type="PackedScene" uid="uid://02lmmldikfar" path="res://scene/ground/parallax_foreground.tscn" id="11_anxqu"]
[node name="Main" type="Node2D"]
script = ExtResource("1_pks84")
[node name="ParallaxBackground" parent="." instance=ExtResource("1_f7g4d")]
[node name="UILayer" type="CanvasLayer" parent="."]
layer = 5
[node name="HUD2D" parent="UILayer" instance=ExtResource("4_t7gb2")]
scale = Vector2(0.24, 0.24)
mouse_filter = 0
[node name="DialogLayer" parent="UILayer" instance=ExtResource("3_prpss")]
offset_top = -134.0
mouse_filter = 2
[node name="Notification" parent="UILayer" instance=ExtResource("5_3gg5t")]
mouse_filter = 2
[node name="VignetteShading" parent="." instance=ExtResource("2_d1re1")]
[node name="PropInspector2D" parent="." instance=ExtResource("5_ux0rw")]
[node name="Player2D" parent="." instance=ExtResource("6_6geb0")]
unique_name_in_owner = true
[node name="CameraFocusMarker" parent="Player2D" instance=ExtResource("7_n7qcv")]
unique_name_in_owner = true
[node name="MainCamera" parent="Player2D/CameraFocusMarker" instance=ExtResource("8_nj084")]
unique_name_in_owner = true
position = Vector2(1, 0)
[node name="ParallaxForeground" parent="." instance=ExtResource("11_anxqu")]

View File

@ -0,0 +1,6 @@
extends Control
func show_notification(msg, number):
#TODO: Implement this method
print("show_notification:", msg, number)

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://5g07x6q7wwr1"]
[ext_resource type="Script" path="res://scene/notification/notification.gd" id="1_j0g80"]
[node name="Notification" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_j0g80")

166
scene/player/player_2d.gd Normal file
View File

@ -0,0 +1,166 @@
extends CharacterBody2D
class_name MainPlayer
enum MOVEMENT_STATUS {
IDLE,
WALKING,
RUNNING,
LAYING_STAY,
LAYING_MOVING,
CLIMBING_STAY,
CLIMBING,
}
@export var action_locked := false:
set(val):
action_locked = val
_process_action_lock()
@export var current_status : MOVEMENT_STATUS
@export var facing_direction := Vector2(1.0, -1.0)
@export var is_laying := false:
set(val):
is_laying = val
# reset the facing direction wether the player is laying or not.
_reset_face_direction()
if is_laying:
is_climbing = false
@export var is_climbing := false:
set(val):
is_climbing = val
# reset the facing direction wether the player is climbing or not.
_reset_face_direction()
if is_climbing:
is_laying = false
@export var running_locked := false
@export var speed_walking := 300.0
@export var speed_runnig := 500.0
@export var speed_laying := 150.0
@export var speed_climbing := 170.0
#const JUMP_VELOCITY = -400.0
@onready var camera = %MainCamera as Camera2D
@onready var sprite = %AnimatedSprite2D as AnimatedSprite2D
func _ready() -> void:
_reset_face_direction()
func _reset_face_direction() -> void:
facing_direction = Vector2(1, -1)
func _process_action_lock() -> void:
# reset status to idle or stay
if action_locked:
if current_status == MOVEMENT_STATUS.WALKING or current_status == MOVEMENT_STATUS.RUNNING:
current_status = MOVEMENT_STATUS.IDLE
elif current_status == MOVEMENT_STATUS.LAYING_MOVING:
current_status = MOVEMENT_STATUS.LAYING_STAY
elif current_status == MOVEMENT_STATUS.CLIMBING:
current_status = MOVEMENT_STATUS.CLIMBING_STAY
_play_animation()
# return whether the player status or facing direction has changed.
func _check_status(direction) -> bool:
var tmp_status = current_status
var new_facing_direction := facing_direction
if is_laying:
if direction.x:
new_facing_direction.x = direction.x
tmp_status = MOVEMENT_STATUS.LAYING_MOVING
else:
tmp_status = MOVEMENT_STATUS.LAYING_STAY
elif is_climbing:
if direction.y:
new_facing_direction.y = direction.y
tmp_status = MOVEMENT_STATUS.CLIMBING
else:
tmp_status = MOVEMENT_STATUS.CLIMBING_STAY
else:
if direction.x:
new_facing_direction.x = direction.x
tmp_status = MOVEMENT_STATUS.WALKING
if !running_locked and Input.is_action_pressed("run"):
tmp_status = MOVEMENT_STATUS.RUNNING
else:
tmp_status = MOVEMENT_STATUS.IDLE
if new_facing_direction != facing_direction or tmp_status != current_status:
facing_direction = new_facing_direction
current_status = tmp_status
return true
return false
func _play_animation() -> void:
match current_status:
MOVEMENT_STATUS.IDLE:
if facing_direction.x > 0.0:
sprite.play(&"idle_r")
else:
sprite.play(&"idle_l")
MOVEMENT_STATUS.WALKING:
if facing_direction.x > 0.0:
sprite.play(&"walking_r")
else:
sprite.play(&"walking_l")
MOVEMENT_STATUS.RUNNING:
if facing_direction.x > 0.0:
sprite.play(&"running_r")
else:
sprite.play(&"running_l")
MOVEMENT_STATUS.LAYING_STAY:
if facing_direction.x > 0.0:
sprite.play(&"laying_stay_r")
else:
sprite.play(&"laying_stay_l")
MOVEMENT_STATUS.LAYING_MOVING:
if facing_direction.x > 0.0:
sprite.play(&"laying_moving_r")
else:
sprite.play(&"laying_moving_l")
MOVEMENT_STATUS.CLIMBING_STAY:
sprite.play(&"climbing_stay")
MOVEMENT_STATUS.CLIMBING:
if facing_direction.y > 0.0:
sprite.play(&"climbing_down")
else:
sprite.play(&"climbing_up")
func _get_speed(direction: Vector2) -> Vector2:
match current_status:
MOVEMENT_STATUS.WALKING:
return Vector2(speed_walking * direction.x, 0.0)
MOVEMENT_STATUS.RUNNING:
return Vector2(speed_runnig * direction.x, 0.0)
MOVEMENT_STATUS.LAYING_MOVING:
return Vector2(speed_laying * direction.x, 0.0)
MOVEMENT_STATUS.CLIMBING:
return Vector2(0, speed_climbing * direction.y)
return Vector2(0, 0)
func _physics_process(_delta: float) -> void:
if action_locked:
velocity = Vector2.ZERO
return
# Add the gravity.
#if not is_on_floor():
#velocity += get_gravity() * delta
#if Input.is_action_just_pressed("jump") and is_on_floor():
#velocity.y = JUMP_VELOCITY
var x_direction := Input.get_axis("left", "right")
var y_direction := Input.get_axis("up", "down")
var direction := Vector2(x_direction, y_direction)
if _check_status(direction):
_play_animation()
var speed := _get_speed(direction) as Vector2
velocity.x = move_toward(velocity.x, speed.x, 300.0)
velocity.y = move_toward(velocity.y, speed.y, 300.0)
move_and_slide()
_tweak_camera_marker()
# drag the camera marker against the player movement
# so there will be a better vision in front of the player.
func _tweak_camera_marker():
var marker = get_node("./CameraFocusMarker") as Node2D
if marker:
marker.position.x = facing_direction.x * abs(velocity.x) * 0.11
marker.position.y = facing_direction.y * abs(velocity.y) * 0.11

View File

@ -0,0 +1,34 @@
[gd_scene load_steps=5 format=3 uid="uid://cjhw5ecygrqty"]
[ext_resource type="Script" path="res://scene/player/player_2d.gd" id="1_3a78y"]
[ext_resource type="SpriteFrames" uid="uid://c43gyexokirl4" path="res://config/animation/player_sprite_frames.tres" id="1_23i43"]
[ext_resource type="Texture2D" uid="uid://t526pexw4ng4" path="res://asset/art/neutral_point_light.webp" id="3_scilj"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_fno82"]
size = Vector2(105, 238.5)
[node name="Player2D" type="CharacterBody2D"]
script = ExtResource("1_3a78y")
current_status = null
facing_direction = null
running_locked = null
speed_walking = null
speed_runnig = null
speed_laying = null
speed_climbing = null
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
unique_name_in_owner = true
sprite_frames = ExtResource("1_23i43")
animation = &"idle_r"
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(-1, -1)
shape = SubResource("RectangleShape2D_fno82")
[node name="PointLight2D" type="PointLight2D" parent="."]
position = Vector2(2, -175)
scale = Vector2(0.810547, 0.849609)
energy = 0.4
texture = ExtResource("3_scilj")
height = 50.0

View File

@ -0,0 +1,12 @@
extends CanvasLayer
@onready var panel := %Panel
@export var shown := false:
set(val):
shown = val
panel.visible = val
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
layer = GlobalConfig.CANVAS_LAYER_PROP_INSPECTOR

View File

@ -0,0 +1,15 @@
[gd_scene load_steps=2 format=3 uid="uid://cekhj65axie0p"]
[ext_resource type="Script" path="res://scene/popup/prop_inspector_2d.gd" id="1_p4yxb"]
[node name="PropInspector2D" type="CanvasLayer"]
script = ExtResource("1_p4yxb")
[node name="Panel" type="Panel" parent="."]
unique_name_in_owner = true
visible = false
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View File

@ -0,0 +1,9 @@
[gd_scene format=3 uid="uid://beok2r6fgburn"]
[node name="Settings" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

19
ui/button/sound_button.gd Normal file
View File

@ -0,0 +1,19 @@
extends Button
class_name SoundButton
@export var audio_collections: Array[AudioStreamCollection]
func _ready():
if !audio_collections:
audio_collections.append(preload("res://config/audio/ui/ui_click.tres"))
#print("sound button loaded default ui_click.tres")
if audio_collections:
#print("sound button load audio_collections into audio_player")
var audio_player := RandomAudioStreamPlayer.new()
audio_player.audio_collections = audio_collections
pressed.connect(audio_player.play_random)
add_child(audio_player)
else:
printerr("sound button has no audio_collections! ignore initialization of audio_player")

View File

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://bdy4u3e7rmo7f"]
[ext_resource type="Script" path="res://ui/button/sound_button.gd" id="1_vn1us"]
[node name="SoundButton" type="Button"]
offset_right = 8.0
offset_bottom = 8.0
script = ExtResource("1_vn1us")

View File

@ -0,0 +1,28 @@
extends TextureButton
class_name SoundTextureButton
@export var audio_collections: Array[AudioStreamCollection]
func _ready():
if !audio_collections:
audio_collections.append(preload("res://config/audio/ui/ui_click.tres"))
#print("sound button loaded default ui_click.tres")
if audio_collections:
#print("sound button load audio_collections into audio_player")
var audio_player := RandomAudioStreamPlayer.new()
audio_player.audio_collections = audio_collections
button_down.connect(audio_player.play_random)
add_child(audio_player)
else:
printerr("sound button has no audio_collections! ignore initialization of audio_player")
#button_down.connect(_on_press_down)
#button_up.connect(_on_press_up)
#func _on_press_down():
#InputUtil.set_cursor_hand_patting()
#
#func _on_press_up():
#InputUtil.set_cursor_hand_rest()

View File

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://cef5mgr1hgpmr"]
[ext_resource type="Script" path="res://ui/button/sound_texture_button.gd" id="1_k7j4d"]
[node name="SoundButton" type="TextureButton"]
size_flags_horizontal = 0
size_flags_vertical = 0
script = ExtResource("1_k7j4d")

100
ui/hud/Inventory.tscn Executable file
View File

@ -0,0 +1,100 @@
[gd_scene load_steps=14 format=3 uid="uid://cmyxinb0ickva"]
[ext_resource type="Script" path="res://UI/Inventory.gd" id="1_gbar7"]
[ext_resource type="Texture2D" uid="uid://2jc6qio7tmuk" path="res://assets/HUD/背包按键/道具快捷栏/zz.png" id="2_c4gqh"]
[ext_resource type="Texture2D" uid="uid://dr1fvkrmtynb6" path="res://assets/HUD/背包按键/道具快捷栏/az.png" id="3_ftsid"]
[ext_resource type="Texture2D" uid="uid://b3pfdsyj0dcdb" path="res://assets/HUD/背包按键/道具快捷栏/wz.png" id="4_rn4wj"]
[ext_resource type="Texture2D" uid="uid://ykv7o43dtjn0" path="res://assets/HUD/背包按键/道具快捷栏/k.png" id="5_o2bgy"]
[ext_resource type="Texture2D" uid="uid://bgjt0y7vs5ix0" path="res://assets/HUD/背包按键/道具快捷栏/s.png" id="6_abx1s"]
[ext_resource type="Texture2D" uid="uid://ukdbwrvd8qdq" path="res://assets/HUD/背包按键/道具快捷栏/zy.png" id="7_n66je"]
[ext_resource type="Texture2D" uid="uid://sv8u083cpov6" path="res://assets/HUD/背包按键/道具快捷栏/ay.png" id="8_iym7w"]
[ext_resource type="Texture2D" uid="uid://dva4vpj5uo8td" path="res://assets/HUD/背包按键/道具快捷栏/wy.png" id="9_aoirx"]
[ext_resource type="FontFile" uid="uid://dehtmf0lanaf3" path="res://assets/HUD/字体/方正楷体简体.TTF" id="10_8p7i8"]
[sub_resource type="FontFile" id="FontFile_5oap5"]
subpixel_positioning = 0
msdf_pixel_range = 14
msdf_size = 128
cache/0/16/0/ascent = 0.0
cache/0/16/0/descent = 0.0
cache/0/16/0/underline_position = 0.0
cache/0/16/0/underline_thickness = 0.0
cache/0/16/0/scale = 1.0
cache/0/16/0/kerning_overrides/16/0 = Vector2(0, 0)
[sub_resource type="Theme" id="Theme_bioai"]
default_base_scale = 0.98
default_font = SubResource("FontFile_5oap5")
[sub_resource type="RectangleShape2D" id="RectangleShape2D_jk1w7"]
size = Vector2(83.6779, 34.3683)
[node name="Inventory" type="VBoxContainer"]
offset_left = 10.0
offset_top = 7.0
offset_right = 277.0
offset_bottom = 184.0
scale = Vector2(0.18, 0.18)
theme_override_constants/separation = 5
script = ExtResource("1_gbar7")
[node name="ItemBar" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="Prev" type="TextureButton" parent="ItemBar"]
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
theme = SubResource("Theme_bioai")
texture_normal = ExtResource("2_c4gqh")
texture_pressed = ExtResource("3_ftsid")
texture_disabled = ExtResource("4_rn4wj")
stretch_mode = 3
[node name="Use" type="TextureButton" parent="ItemBar"]
layout_mode = 2
texture_normal = ExtResource("5_o2bgy")
[node name="Prop" type="Sprite2D" parent="ItemBar/Use"]
z_index = 1
position = Vector2(72, 72)
[node name="Hand" type="Sprite2D" parent="ItemBar/Use"]
z_index = 1
position = Vector2(110, 102)
texture = ExtResource("6_abx1s")
[node name="Next" type="TextureButton" parent="ItemBar"]
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
texture_normal = ExtResource("7_n66je")
texture_pressed = ExtResource("8_iym7w")
texture_disabled = ExtResource("9_aoirx")
stretch_mode = 3
[node name="Area2D" type="Area2D" parent="ItemBar"]
visible = false
position = Vector2(-200, -99.9999)
scale = Vector2(3.60011, 5.23739)
[node name="CollisionShape2D" type="CollisionShape2D" parent="ItemBar/Area2D"]
position = Vector2(91.4901, 32.4589)
scale = Vector2(1, 0.999999)
shape = SubResource("RectangleShape2D_jk1w7")
one_way_collision_margin = 0.0
[node name="Label" type="Label" parent="."]
layout_mode = 2
theme_override_fonts/font = ExtResource("10_8p7i8")
theme_override_font_sizes/font_size = 35
text = "道具的描述"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Timer" type="Timer" parent="Label"]
wait_time = 1.5
one_shot = true
[connection signal="pressed" from="ItemBar/Prev" to="." method="_on_prev_pressed"]
[connection signal="pressed" from="ItemBar/Use" to="." method="_on_use_pressed"]
[connection signal="pressed" from="ItemBar/Next" to="." method="_on_next_pressed"]
[connection signal="timeout" from="Label/Timer" to="." method="_on_timer_timeout"]

11
ui/hud/hud.tscn Normal file
View File

@ -0,0 +1,11 @@
[gd_scene load_steps=2 format=3 uid="uid://bs63fypttsiop"]
[ext_resource type="PackedScene" uid="uid://cmyxinb0ickva" path="res://ui/hud/Inventory.tscn" id="1_tam4l"]
[node name="HUD" type="CanvasLayer"]
layer = 99
[node name="Inventory" parent="." instance=ExtResource("1_tam4l")]
offset_top = 4.0
offset_bottom = 193.0
script = null

112
ui/hud/inventory.gd Executable file
View File

@ -0,0 +1,112 @@
#背包实现
extends VBoxContainer
var _hand_outro: Tween
var _label_outro: Tween
#@onready var item_bar = $ItemBar
@onready var prev = $ItemBar/Prev
@onready var prop = $ItemBar/Use/Prop
@onready var hand = $ItemBar/Use/Hand
@onready var next = $ItemBar/Next
@onready var label = $Label
@onready var timer = $Label/Timer
func _ready() -> void:
#SceneManager.inventory.add_item(preload("res://items/1014_yaoshi.tres"))
#SceneManager.inventory.add_item(preload("res://items/3014_yaoshi.tres"))
hand.hide()
hand.modulate.a = 0.0
label.hide()
label.modulate.a = 0.0
SceneManager.inventory.changed.connect(_update_ui)
_update_ui(true)
#设置在屏幕中点击任意位置,互动手图案消失
func _input(event: InputEvent) -> void:
if event.is_action_pressed("click") and SceneManager.inventory.active_item:
SceneManager.inventory.set_deferred("active_item", true)
_hand_outro = create_tween()
_hand_outro.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE).set_parallel()
_hand_outro.tween_property(hand, "scale", Vector2.ONE * 0.5, 0.15) #Vector2.ONE * 0.5 设置手缩放的大小.0.15表示消失的速度
_hand_outro.tween_property(hand, "modulate:a", 0.0, 0.15)
_hand_outro.chain().tween_callback(hand.hide)
func _update_ui(is_init = false): #is_inte = false 让背包物品在最开始出现时没有动画效果
var count = SceneManager.inventory.get_item_count()
prev.disabled = count < 2
next.disabled = count < 2
visible = count > 0
var item = SceneManager.inventory.get_current_item()
if not item:
return
else:
label.text = item.description
prop.texture = item.prop_texture
#item_bar.modulate.a = 1
#print("prop")
#添加背包物品在左右滑动时的弹出动画效果
if is_init:
return
var tween := create_tween()
tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
tween.tween_property(prop, "scale", Vector2.ONE, 0.15).from(Vector2.ZERO)
_show_label()
func _show_label() -> void:
if _label_outro and _label_outro.is_valid():
_label_outro.kill()
_label_outro = null
label.show()
var tween = create_tween()
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
tween.tween_property(label,"modulate:a",1.0,0.2)
tween.tween_callback(timer.start)
func _on_prev_pressed() -> void:
SoundManager.play_sfx("interact")
SceneManager.inventory.select_prev()
print("prev1")
func _on_next_pressed() -> void:
SoundManager.play_sfx("interact")
SceneManager.inventory.select_next()
print("next2")
@onready var use = $ItemBar/Use
func _on_use_pressed() -> void:
if use.button_mask == MOUSE_BUTTON_MASK_LEFT:
SceneManager.inventory.active_item = SceneManager.inventory.get_current_item()
print("use3")
if _hand_outro and _hand_outro.is_valid():
_hand_outro.kill()
_hand_outro = null
hand.show()
var tween = create_tween()
tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK).set_parallel()
tween.tween_property(hand, "scale", Vector2.ONE, 0.15).from(Vector2.ZERO)
tween.tween_property(hand, "modulate:a", 1.0, 0.15)
_show_label()
func _on_timer_timeout():
_label_outro = create_tween()
_label_outro.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
_label_outro.tween_property(label,"modulate:a",0.0,0.2)
_label_outro.chain().tween_callback(label.hide)

10
ui/settings.tscn Normal file
View File

@ -0,0 +1,10 @@
[gd_scene load_steps=3 format=3 uid="uid://c5wtakm14h7cy"]
[ext_resource type="Texture2D" uid="uid://db8rd4nwl6pve" path="res://asset/art/ui/ui_settings.skt/Layer~2.png" id="1_sl0gr"]
[sub_resource type="AtlasTexture" id="AtlasTexture_jngmd"]
atlas = ExtResource("1_sl0gr")
region = Rect2(254, 362, 994, 1314)
[node name="Settings" type="Sprite2D"]
texture = SubResource("AtlasTexture_jngmd")

View File

@ -0,0 +1,14 @@
extends CanvasLayer
@export var rgb := Color8(0x3f,0x26,0x31):
set(new_val):
rgb = new_val
%ColorRect.material.set("shader_parameter/vignette_rgb", new_val)
@export_range(0, 5) var intensity := 0.3:
set(new_val):
intensity = new_val
%ColorRect.material.set("shader_parameter/vignette_intensity", new_val)
func _ready() -> void:
layer = GlobalConfig.CANVAS_LAYER_VIGNETTE

View File

@ -0,0 +1,23 @@
[gd_scene load_steps=4 format=3 uid="uid://3gk1gxwanw24"]
[ext_resource type="Script" path="res://ui/vignette/vignette_shading.gd" id="1_6w7er"]
[ext_resource type="Shader" path="res://asset/shader/vignette.gdshader" id="1_akp6k"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_pabt5"]
shader = ExtResource("1_akp6k")
shader_parameter/vignette_intensity = 0.4
shader_parameter/vignette_rgb = Color(0.247059, 0.14902, 0.192157, 1)
[node name="VignetteShading" type="CanvasLayer"]
layer = 100
script = ExtResource("1_6w7er")
[node name="ColorRect" type="ColorRect" parent="."]
unique_name_in_owner = true
material = SubResource("ShaderMaterial_pabt5")
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2

17
util/resource_utils.gd Normal file
View File

@ -0,0 +1,17 @@
extends Object
class_name ResourceUtils
# # remove editor's cache
# func remove_editor_cache(resource: Resource) -> void:
# if Engine.is_editor_hint():
# (resource)
static func remove_editor_cache(name: String) -> void:
pass
# var dir = DirAccess.open("res://.godot/editor")
# for file in dir.get_files():
# if file.get_basename().begins_with(name):
# DirAccess.remove_absolute("res://.godot/editor/" + file)
# print("Removed editor cache: ", file)
# break