GroundLoader 实现预加载邻居场景;完善转场效果;全局控制 player 奔跑锁定
This commit is contained in:
parent
4c4566c8d8
commit
5e0183a8a4
@ -97,10 +97,10 @@ func _import(source_file, save_path, options, platform_variants, gen_files):
|
|||||||
var image = texture.get_image()
|
var image = texture.get_image()
|
||||||
var image_path = dir_name + str(i) + ".png"
|
var image_path = dir_name + str(i) + ".png"
|
||||||
image.save_png(image_path)
|
image.save_png(image_path)
|
||||||
image.resource_path = image_path
|
texture = ImageTexture.create_from_image(image)
|
||||||
var new_texture = ImageTexture.create_from_image(image)
|
texture.take_over_path(image_path)
|
||||||
var duration = frames.get_frame_duration("gif", i)
|
var duration = frames.get_frame_duration("gif", i)
|
||||||
sprite_frames.add_frame(animation_name, new_texture, duration)
|
sprite_frames.add_frame(animation_name, texture, duration)
|
||||||
print_debug("Created images and added to SpriteFrames: ", animation_name)
|
print_debug("Created images and added to SpriteFrames: ", animation_name)
|
||||||
ResourceSaver.save(sprite_frames)
|
ResourceSaver.save(sprite_frames)
|
||||||
return code
|
return code
|
||||||
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
@ -3,15 +3,15 @@
|
|||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://cgghff16powfg"
|
uid="uid://cgghff16powfg"
|
||||||
path="res://.godot/imported/prop遮罩.png-f0336d91e6b2ddd4060007c0fc87eea0.ctex"
|
path="res://.godot/imported/prop遮罩.png-85fb17d3ccb28d9d3887ddc81281a85f.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://asset/art/ui/prop遮罩.png"
|
source_file="res://asset/art/ui/prop/prop遮罩.png"
|
||||||
dest_files=["res://.godot/imported/prop遮罩.png-f0336d91e6b2ddd4060007c0fc87eea0.ctex"]
|
dest_files=["res://.godot/imported/prop遮罩.png-85fb17d3ccb28d9d3887ddc81281a85f.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
BIN
asset/art/ui/prop/遮罩.png
Normal file
BIN
asset/art/ui/prop/遮罩.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
34
asset/art/ui/prop/遮罩.png.import
Normal file
34
asset/art/ui/prop/遮罩.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://f186lvt5y2ql"
|
||||||
|
path="res://.godot/imported/遮罩.png-dab9f7c60166ce0e17692f077a460bfb.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://asset/art/ui/prop/遮罩.png"
|
||||||
|
dest_files=["res://.godot/imported/遮罩.png-dab9f7c60166ce0e17692f077a460bfb.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
|
@ -152,9 +152,10 @@ func _create_mirror():
|
|||||||
var flipped_image = mirrored_frame.get_image() as Image
|
var flipped_image = mirrored_frame.get_image() as Image
|
||||||
flipped_image.flip_x()
|
flipped_image.flip_x()
|
||||||
var flipped_img_path = mirror_dir_path + "/" + id + ".png"
|
var flipped_img_path = mirror_dir_path + "/" + id + ".png"
|
||||||
flipped_image.resource_path = flipped_img_path
|
|
||||||
flipped_image.save_png(flipped_img_path)
|
flipped_image.save_png(flipped_img_path)
|
||||||
sprite_frames.add_frame(mirror_mapping, load(flipped_img_path))
|
var texture = ImageTexture.create_from_image(flipped_image)
|
||||||
|
texture.take_over_path(flipped_img_path)
|
||||||
|
sprite_frames.add_frame(mirror_mapping, texture)
|
||||||
sprite_frames.set_animation_speed(mapping_name, frames_per_sec)
|
sprite_frames.set_animation_speed(mapping_name, frames_per_sec)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,9 +3,8 @@ extends Node
|
|||||||
|
|
||||||
signal archive_loaded
|
signal archive_loaded
|
||||||
|
|
||||||
static var archive := (
|
static var archive: AssembledArchive
|
||||||
load("user://data/archives/save0" + GlobalConfig.RES_FILE_FORMAT) as AssembledArchive
|
# current archive
|
||||||
) # current archive
|
|
||||||
static var user_root_dir := "user://data/" # must end with "/"
|
static var user_root_dir := "user://data/" # must end with "/"
|
||||||
static var archive_dir := "user://data/archives/"
|
static var archive_dir := "user://data/archives/"
|
||||||
static var archive_prefix := "save"
|
static var archive_prefix := "save"
|
||||||
|
@ -21,10 +21,14 @@ class_name AssembledArchive extends Resource
|
|||||||
# created time
|
# created time
|
||||||
@export var created_time := "2024-12-24 00:00:00"
|
@export var created_time := "2024-12-24 00:00:00"
|
||||||
|
|
||||||
|
# 全局参数
|
||||||
|
@export var global_data_dict := {}
|
||||||
# 不同场景的地面物品状态存档
|
# 不同场景的地面物品状态存档
|
||||||
@export var ground_archives = {}
|
@export var ground_archives = {}
|
||||||
# true 为匿名,false 非匿名
|
# true 为匿名,false 非匿名
|
||||||
@export var npc_anonymous_states = {}
|
@export var npc_anonymous_states = {}
|
||||||
|
# 玩家跑步锁定状态
|
||||||
|
@export var player_running_locked := true
|
||||||
# prop hud 显示道具
|
# prop hud 显示道具
|
||||||
@export var prop_inventory: PropInventory
|
@export var prop_inventory: PropInventory
|
||||||
|
|
||||||
@ -51,3 +55,9 @@ func ground_archive(scene_name := current_scene) -> GroundArchive:
|
|||||||
return ground_archives[scene_name]
|
return ground_archives[scene_name]
|
||||||
|
|
||||||
|
|
||||||
|
func set_global_entry(property: StringName, value) -> void:
|
||||||
|
global_data_dict[property] = value
|
||||||
|
|
||||||
|
|
||||||
|
func get_global_value(property: StringName) -> Variant:
|
||||||
|
return global_data_dict.get(property)
|
||||||
|
@ -11,7 +11,8 @@ const CANVAS_LAYER_DIALOG = 23
|
|||||||
const CANVAS_LAYER_UI = 22
|
const CANVAS_LAYER_UI = 22
|
||||||
const CANVAS_LAYER_PROP_INSPECTOR = 21
|
const CANVAS_LAYER_PROP_INSPECTOR = 21
|
||||||
const CANVAS_LAYER_SETTINGS = 20
|
const CANVAS_LAYER_SETTINGS = 20
|
||||||
const CANVAS_LAYER_BAG = 11
|
const CANVAS_LAYER_BAG = 12
|
||||||
|
const CANVAS_LAYER_GROUND_MASK = 11
|
||||||
const CANVAS_LAYER_SHADING = 10
|
const CANVAS_LAYER_SHADING = 10
|
||||||
const CANVAS_LAYER_FG = 2
|
const CANVAS_LAYER_FG = 2
|
||||||
const CANVAS_LAYER_HD_ENTITY = 1
|
const CANVAS_LAYER_HD_ENTITY = 1
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
static var config := (
|
static var config: GlobalConfig:
|
||||||
load("user://data/config" + GlobalConfig.RES_FILE_FORMAT) as GlobalConfig
|
|
||||||
):
|
|
||||||
set = _set_config
|
set = _set_config
|
||||||
|
|
||||||
var timer = Timer.new()
|
var timer = Timer.new()
|
||||||
|
@ -72,7 +72,7 @@ func _on_interacted() -> void:
|
|||||||
# 传送,queue free 导致 sfx 无法播放,使用全局声源
|
# 传送,queue free 导致 sfx 无法播放,使用全局声源
|
||||||
sfx.global_play()
|
sfx.global_play()
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("传送前往", target_scene, target_portal)
|
print("传送前往", target_scene, target_portal, " immediately=", immediately)
|
||||||
var ground_loader = SceneManager.get_ground_loader() as GroundLoader
|
var ground_loader = SceneManager.get_ground_loader() as GroundLoader
|
||||||
if ground_loader:
|
if ground_loader:
|
||||||
ground_loader.transition_to_scene(target_scene, target_portal, immediately)
|
ground_loader.transition_to_scene(target_scene, target_portal, immediately)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@tool
|
@tool
|
||||||
class_name Ground2D extends Node2D
|
class_name Ground2D extends Node2D
|
||||||
|
|
||||||
|
@export var scene_name := ""
|
||||||
@export_group("Player", "player_")
|
@export_group("Player", "player_")
|
||||||
@export var player_y_fixed := true
|
@export var player_y_fixed := true
|
||||||
@export var player_y := 70:
|
@export var player_y := 70:
|
||||||
@ -45,6 +46,11 @@ const FOOTSTEP_AUDIO = {
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
foreground.layer = GlobalConfig.CANVAS_LAYER_FG
|
foreground.layer = GlobalConfig.CANVAS_LAYER_FG
|
||||||
_reset_player_positon()
|
_reset_player_positon()
|
||||||
|
# 检查 scene_name 是否合法
|
||||||
|
scene_name = scene_name.strip_edges()
|
||||||
|
if not scene_name or scene_name.length() != 7:
|
||||||
|
printerr("scene_name is not valid")
|
||||||
|
return
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
return
|
return
|
||||||
# 如果 debug 模式下不通过 GroundLoader 启动,读取 palyer 位置
|
# 如果 debug 模式下不通过 GroundLoader 启动,读取 palyer 位置
|
||||||
|
@ -8,35 +8,36 @@ class_name GroundLoader extends Node2D
|
|||||||
@export var debug_reload := false:
|
@export var debug_reload := false:
|
||||||
set(new_val):
|
set(new_val):
|
||||||
debug_reload = false
|
debug_reload = false
|
||||||
if current_scene and entrance_portal:
|
if is_node_ready() and current_scene and entrance_portal:
|
||||||
transition_to_scene(current_scene, entrance_portal, true)
|
transition_to_scene(current_scene, entrance_portal, true)
|
||||||
@export var archive_scene := ""
|
@export var archive_scene := ""
|
||||||
@export var archive_portal := ""
|
@export var archive_portal := ""
|
||||||
|
|
||||||
|
@onready var mask_layer := %MaskLayer as CanvasLayer
|
||||||
|
@onready var mask := %Mask as ColorRect
|
||||||
|
|
||||||
var first_entered := true
|
var first_entered := true
|
||||||
var ground: Ground2D
|
var ground: Ground2D
|
||||||
|
var display_mask_time = 0.0
|
||||||
|
|
||||||
var scenes_dir = "res://scene/ground/scene/"
|
var scenes_dir = "res://scene/ground/scene/"
|
||||||
|
|
||||||
var ground_dict = {}
|
# 场景名字映射到路径
|
||||||
|
var ground_scene_path_dict = {}
|
||||||
|
|
||||||
# 预加载 portal 通往的场景
|
|
||||||
var neighbor_scene_cache = {}
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
mask_layer.layer = GlobalConfig.CANVAS_LAYER_GROUND_MASK
|
||||||
|
mask.visible = true
|
||||||
|
mask.color.a = 0.0
|
||||||
|
# grounds
|
||||||
_read_grounds()
|
_read_grounds()
|
||||||
ground = get_node_or_null("Ground")
|
# ground = get_node_or_null("Ground")
|
||||||
# load save
|
# load save
|
||||||
if not ignore_archive:
|
if not ignore_archive:
|
||||||
_load_save()
|
_load_save()
|
||||||
if archive_scene and archive_portal:
|
|
||||||
current_scene = archive_scene
|
|
||||||
entrance_portal = archive_portal
|
|
||||||
if current_scene and entrance_portal:
|
if current_scene and entrance_portal:
|
||||||
transition_to_scene(current_scene, entrance_portal, true)
|
transition_to_scene(current_scene, entrance_portal, true)
|
||||||
elif ground:
|
|
||||||
ground.queue_free()
|
|
||||||
ground = null
|
|
||||||
|
|
||||||
|
|
||||||
func _read_grounds() -> void:
|
func _read_grounds() -> void:
|
||||||
@ -47,9 +48,9 @@ func _read_grounds() -> void:
|
|||||||
for s_file in DirAccess.open(c_path).get_files():
|
for s_file in DirAccess.open(c_path).get_files():
|
||||||
if s_file.ends_with(".tscn"):
|
if s_file.ends_with(".tscn"):
|
||||||
var s_path = c_path + s_file
|
var s_path = c_path + s_file
|
||||||
ground_dict[c_dir.substr(0, 3) + "_" + s_file.substr(0, 3)] = s_path
|
ground_scene_path_dict[c_dir.substr(0, 3) + "_" + s_file.substr(0, 3)] = s_path
|
||||||
# # 确保每个 ground 都初始化 archive
|
# # 确保每个 ground 都初始化 archive
|
||||||
# for key in ground_dict.keys():
|
# for key in ground_scene_path_dict.keys():
|
||||||
# if GlobalConfig.DEBUG:
|
# if GlobalConfig.DEBUG:
|
||||||
# print("check ground_archive:", key)
|
# print("check ground_archive:", key)
|
||||||
# ArchiveManager.archive.ground_archive(key)
|
# ArchiveManager.archive.ground_archive(key)
|
||||||
@ -61,35 +62,41 @@ func _load_save():
|
|||||||
archive_scene = ArchiveManager.archive.current_scene
|
archive_scene = ArchiveManager.archive.current_scene
|
||||||
if ArchiveManager.archive.entrance_portal:
|
if ArchiveManager.archive.entrance_portal:
|
||||||
archive_portal = ArchiveManager.archive.entrance_portal
|
archive_portal = ArchiveManager.archive.entrance_portal
|
||||||
|
# 使用 archive 所记录的场景
|
||||||
|
if archive_scene and archive_portal:
|
||||||
|
current_scene = archive_scene
|
||||||
|
entrance_portal = archive_portal
|
||||||
|
|
||||||
|
|
||||||
func transition_to_scene(key: String, portal: String, immediately := false) -> void:
|
func _toggle_mask(display: bool, _immediately: bool) -> Tween:
|
||||||
var scene_path = ground_dict[key]
|
var tween = get_tree().create_tween()
|
||||||
|
if display:
|
||||||
|
tween.tween_property(mask, "color:a", 1.0, 0.3).set_trans(Tween.TRANS_CUBIC)
|
||||||
|
display_mask_time = Time.get_ticks_msec()
|
||||||
|
else:
|
||||||
|
# var time = Time.get_ticks_msec()
|
||||||
|
# # 转场至少 0.6s, 除去 0.3s 最后的淡出,需要 0.3s 的等待时间(包含 mask 的淡入)
|
||||||
|
# if not _immediately:
|
||||||
|
# var wait_time = max(display_mask_time + 300 - time, 0.0) * 0.001
|
||||||
|
# if wait_time:
|
||||||
|
# tween.tween_interval(wait_time)
|
||||||
|
tween.tween_property(mask, "color:a", 0.0, 0.3).set_trans(Tween.TRANS_CUBIC)
|
||||||
|
return tween
|
||||||
|
|
||||||
|
|
||||||
|
func transition_to_scene(scene_name: String, portal: String, immediately: bool) -> void:
|
||||||
|
var scene_path = ground_scene_path_dict.get(scene_name)
|
||||||
if scene_path:
|
if scene_path:
|
||||||
var scene = load(scene_path).instantiate()
|
current_scene = scene_name
|
||||||
current_scene = key
|
|
||||||
entrance_portal = portal
|
entrance_portal = portal
|
||||||
# 优先更新 archive,使 ground 可以访问自己的 current_scene 键值
|
# 优先更新 archive,使 ground 可以访问自己的 current_scene 键值
|
||||||
_update_archive()
|
_update_archive()
|
||||||
if immediately:
|
# 转场效果,在 _load_ground_node 之前播放
|
||||||
_do_transition(scene)
|
var tween = _toggle_mask(true, immediately)
|
||||||
# 更新玩家位置
|
tween.tween_callback(_do_transition.bind(scene_name))
|
||||||
if first_entered:
|
tween.tween_callback(_toggle_mask.bind(false, immediately))
|
||||||
_update_player_position()
|
|
||||||
else:
|
|
||||||
var tween = create_tween() as Tween
|
|
||||||
var player = SceneManager.get_player() as MainPlayer
|
|
||||||
if player:
|
|
||||||
player.action_locked = true
|
|
||||||
#TODO 转场效果
|
|
||||||
#
|
|
||||||
tween.tween_interval(0.2)
|
|
||||||
tween.tween_callback(_do_transition.bind(scene))
|
|
||||||
if player:
|
|
||||||
tween.tween_callback(func(): player.action_locked = false)
|
|
||||||
first_entered = false
|
|
||||||
else:
|
else:
|
||||||
print("Scene not found: " + key)
|
print("Scene not found: " + scene_name)
|
||||||
|
|
||||||
|
|
||||||
func _update_player_position():
|
func _update_player_position():
|
||||||
@ -104,17 +111,30 @@ func _update_player_position():
|
|||||||
player.set_facing_direction(ArchiveManager.archive.player_direction)
|
player.set_facing_direction(ArchiveManager.archive.player_direction)
|
||||||
|
|
||||||
|
|
||||||
func _do_transition(scene: Node2D):
|
func _do_transition(scene_name: String):
|
||||||
|
# SceneManager.freeze_player(0)
|
||||||
|
var ground_node = _load_ground_node(scene_name)
|
||||||
|
if ground == ground_node:
|
||||||
|
return
|
||||||
if ground:
|
if ground:
|
||||||
# 提前移除,防止命名冲突
|
# 提前移除,防止命名冲突
|
||||||
remove_child(ground)
|
remove_child(ground)
|
||||||
ground.queue_free()
|
# 不需要释放,因为会缓存,在 ground_node_cache 中释放
|
||||||
ground = scene.get_child(0)
|
# ground.queue_free()
|
||||||
scene.remove_child(ground)
|
# 先设置 ground,再添加到场景中
|
||||||
ground.owner = null
|
# 因为 ground 在 enter_tree 时会用到 SceneManager 的方法
|
||||||
scene.queue_free()
|
# 其中间接用到了 GroundLoader 的 ground
|
||||||
add_child(ground)
|
ground = ground_node
|
||||||
|
_add_ground()
|
||||||
|
# 预先加载邻居场景
|
||||||
|
_post_transition()
|
||||||
|
if GlobalConfig.DEBUG and not Engine.is_editor_hint():
|
||||||
|
_watch_scene_update()
|
||||||
|
|
||||||
|
|
||||||
|
func _add_ground():
|
||||||
ground.name = "Ground"
|
ground.name = "Ground"
|
||||||
|
add_child(ground)
|
||||||
if not Engine.is_editor_hint():
|
if not Engine.is_editor_hint():
|
||||||
var portal_node = ground.get_node_or_null("DeployLayer/portal_" + entrance_portal) as Node2D
|
var portal_node = ground.get_node_or_null("DeployLayer/portal_" + entrance_portal) as Node2D
|
||||||
if portal_node:
|
if portal_node:
|
||||||
@ -126,8 +146,11 @@ func _do_transition(scene: Node2D):
|
|||||||
print("move player to portal:", entrance_portal, portal_node.global_position)
|
print("move player to portal:", entrance_portal, portal_node.global_position)
|
||||||
else:
|
else:
|
||||||
printerr(current_scene + " portal not found: " + entrance_portal)
|
printerr(current_scene + " portal not found: " + entrance_portal)
|
||||||
if GlobalConfig.DEBUG and not Engine.is_editor_hint():
|
# 更新玩家位置
|
||||||
_watch_scene_update()
|
if first_entered and not Engine.is_editor_hint():
|
||||||
|
_update_player_position()
|
||||||
|
first_entered = false
|
||||||
|
# SceneManager.release_player()
|
||||||
|
|
||||||
|
|
||||||
func _update_archive():
|
func _update_archive():
|
||||||
@ -138,13 +161,47 @@ func _update_archive():
|
|||||||
archive_portal = entrance_portal
|
archive_portal = entrance_portal
|
||||||
|
|
||||||
|
|
||||||
|
func _load_ground_node(scene_name: String) -> Node2D:
|
||||||
|
if not ground_scene_path_dict.has(scene_name):
|
||||||
|
return null
|
||||||
|
var path = ground_scene_path_dict[scene_name]
|
||||||
|
var scene = ResourceLoader.load(path) as PackedScene
|
||||||
|
if scene:
|
||||||
|
var instance = scene.instantiate() as Node2D
|
||||||
|
var ground_node = instance.get_child(0)
|
||||||
|
instance.remove_child(ground_node)
|
||||||
|
ground_node.owner = null
|
||||||
|
instance.queue_free()
|
||||||
|
return ground_node
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
# 读取 portals,预加载邻居场景
|
||||||
|
func _post_transition():
|
||||||
|
if ground:
|
||||||
|
var scene_names = []
|
||||||
|
var deploy_layer = ground.get_node("DeployLayer")
|
||||||
|
if deploy_layer:
|
||||||
|
for node in deploy_layer.get_children():
|
||||||
|
var portal = node as Portal2D
|
||||||
|
if not portal or not portal.target_scene:
|
||||||
|
continue
|
||||||
|
if ground_scene_path_dict.has(portal.target_scene):
|
||||||
|
scene_names.append(portal.target_scene)
|
||||||
|
if scene_names:
|
||||||
|
for scene_name in scene_names:
|
||||||
|
ResourceLoader.load_threaded_request(ground_scene_path_dict[scene_name])
|
||||||
|
if GlobalConfig.DEBUG:
|
||||||
|
print("preload neighbor scenes:", scene_names)
|
||||||
|
|
||||||
|
|
||||||
var update_watcher: Timer
|
var update_watcher: Timer
|
||||||
var last_modify_time = 0
|
var last_modify_time = 0
|
||||||
|
|
||||||
|
|
||||||
# DEBUG 时重新加载资源
|
# DEBUG 时重新加载资源
|
||||||
func _watch_scene_update():
|
func _watch_scene_update():
|
||||||
var scene_path = ground_dict[current_scene]
|
var scene_path = ground_scene_path_dict[current_scene]
|
||||||
if scene_path:
|
if scene_path:
|
||||||
last_modify_time = FileAccess.get_modified_time(scene_path)
|
last_modify_time = FileAccess.get_modified_time(scene_path)
|
||||||
if not update_watcher:
|
if not update_watcher:
|
||||||
|
@ -4,3 +4,16 @@
|
|||||||
|
|
||||||
[node name="GroundLoader" type="Node2D"]
|
[node name="GroundLoader" type="Node2D"]
|
||||||
script = ExtResource("1_6mjre")
|
script = ExtResource("1_6mjre")
|
||||||
|
|
||||||
|
[node name="MaskLayer" type="CanvasLayer" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
|
||||||
|
[node name="Mask" type="ColorRect" parent="MaskLayer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
color = Color(0, 0, 0, 0)
|
||||||
|
@ -73,6 +73,17 @@ func set_data(property: StringName, value: Variant) -> bool:
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func set_global_entry(property: StringName, value: Variant) -> void:
|
||||||
|
ArchiveManager.archive.set_global_entry(property, value)
|
||||||
|
|
||||||
|
|
||||||
|
func get_global_value(property: StringName, default_value = null) -> Variant:
|
||||||
|
var val = ArchiveManager.archive.get_global_value(property)
|
||||||
|
if val == null:
|
||||||
|
return default_value
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
func _get(property: StringName) -> Variant:
|
func _get(property: StringName) -> Variant:
|
||||||
if property == "oneshot_animation":
|
if property == "oneshot_animation":
|
||||||
return oneshot_animation
|
return oneshot_animation
|
||||||
|
@ -15,6 +15,8 @@ func _default_data() -> Dictionary:
|
|||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
super._ready()
|
super._ready()
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
func play_intro_dialogue():
|
func play_intro_dialogue():
|
||||||
@ -42,6 +44,7 @@ func _on_deploy_layer_ready() -> void:
|
|||||||
if paper.interacted_times > 0:
|
if paper.interacted_times > 0:
|
||||||
paper.visible = false
|
paper.visible = false
|
||||||
paper.enabled = false
|
paper.enabled = false
|
||||||
|
right_door.enabled = true
|
||||||
else:
|
else:
|
||||||
paper.visible = true
|
paper.visible = true
|
||||||
paper.enabled = true
|
paper.enabled = true
|
||||||
|
@ -206,6 +206,30 @@ tracks/14/keys = {
|
|||||||
"update": 0,
|
"update": 0,
|
||||||
"values": [Vector2(1, 1)]
|
"values": [Vector2(1, 1)]
|
||||||
}
|
}
|
||||||
|
tracks/15/type = "value"
|
||||||
|
tracks/15/imported = false
|
||||||
|
tracks/15/enabled = true
|
||||||
|
tracks/15/path = NodePath("DeployLayer/oneshot纸片/Sign:display_sign")
|
||||||
|
tracks/15/interp = 1
|
||||||
|
tracks/15/loop_wrap = true
|
||||||
|
tracks/15/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [true]
|
||||||
|
}
|
||||||
|
tracks/16/type = "value"
|
||||||
|
tracks/16/imported = false
|
||||||
|
tracks/16/enabled = true
|
||||||
|
tracks/16/path = NodePath("DeployLayer/oneshot纸片/Sign:position")
|
||||||
|
tracks/16/interp = 1
|
||||||
|
tracks/16/loop_wrap = true
|
||||||
|
tracks/16/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Vector2(3, -4)]
|
||||||
|
}
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_7k2c8"]
|
[sub_resource type="Animation" id="Animation_7k2c8"]
|
||||||
resource_name = "intro"
|
resource_name = "intro"
|
||||||
@ -546,6 +570,7 @@ metadata/_edit_horizontal_guides_ = [88.0, 122.0]
|
|||||||
|
|
||||||
[node name="Ground" parent="." instance=ExtResource("1_ff4yb")]
|
[node name="Ground" parent="." instance=ExtResource("1_ff4yb")]
|
||||||
position = Vector2(1, 0)
|
position = Vector2(1, 0)
|
||||||
|
scene_name = "c01_s05"
|
||||||
|
|
||||||
[node name="AnimationPlayer" parent="Ground" index="0"]
|
[node name="AnimationPlayer" parent="Ground" index="0"]
|
||||||
libraries = {
|
libraries = {
|
||||||
@ -566,6 +591,7 @@ position = Vector2(27, 3)
|
|||||||
position = Vector2(503, 11)
|
position = Vector2(503, 11)
|
||||||
texture = ExtResource("4_gdhoy")
|
texture = ExtResource("4_gdhoy")
|
||||||
enabled = false
|
enabled = false
|
||||||
|
immediately = false
|
||||||
target_scene = "c01_s06"
|
target_scene = "c01_s06"
|
||||||
target_portal = "left"
|
target_portal = "left"
|
||||||
default_texture = ExtResource("4_gdhoy")
|
default_texture = ExtResource("4_gdhoy")
|
||||||
@ -644,11 +670,10 @@ file = "物品查看.mp3"
|
|||||||
|
|
||||||
[node name="Sign" parent="Ground/DeployLayer/oneshot纸片" index="2"]
|
[node name="Sign" parent="Ground/DeployLayer/oneshot纸片" index="2"]
|
||||||
modulate = Color(1, 1, 1, 0)
|
modulate = Color(1, 1, 1, 0)
|
||||||
offset_left = 35.0
|
offset_left = 3.0
|
||||||
offset_top = -70.0
|
offset_top = -4.0
|
||||||
offset_right = 35.0
|
offset_right = 3.0
|
||||||
offset_bottom = -70.0
|
offset_bottom = -4.0
|
||||||
display_sign = false
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" parent="Ground/DeployLayer/oneshot纸片/Area2D" index="0"]
|
[node name="CollisionShape2D" parent="Ground/DeployLayer/oneshot纸片/Area2D" index="0"]
|
||||||
shape = SubResource("RectangleShape2D_5s1ih")
|
shape = SubResource("RectangleShape2D_5s1ih")
|
||||||
|
@ -9,6 +9,8 @@ func _default_data() -> Dictionary:
|
|||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
super._ready()
|
super._ready()
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
func _on_deploy_layer_ready() -> void:
|
func _on_deploy_layer_ready() -> void:
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
metadata/_edit_horizontal_guides_ = [158.0, 88.0]
|
metadata/_edit_horizontal_guides_ = [158.0, 88.0]
|
||||||
|
|
||||||
[node name="Ground" parent="." instance=ExtResource("1_bitx7")]
|
[node name="Ground" parent="." instance=ExtResource("1_bitx7")]
|
||||||
|
scene_name = "c01_s06"
|
||||||
|
|
||||||
[node name="AnimationPlayer" parent="Ground" index="0"]
|
[node name="AnimationPlayer" parent="Ground" index="0"]
|
||||||
script = ExtResource("2_fkfhi")
|
script = ExtResource("2_fkfhi")
|
||||||
@ -30,11 +31,13 @@ centered = false
|
|||||||
|
|
||||||
[node name="portal_left" parent="Ground/DeployLayer" index="0"]
|
[node name="portal_left" parent="Ground/DeployLayer" index="0"]
|
||||||
position = Vector2(144, 20)
|
position = Vector2(144, 20)
|
||||||
|
immediately = false
|
||||||
target_scene = "c01_s05"
|
target_scene = "c01_s05"
|
||||||
target_portal = "right"
|
target_portal = "right"
|
||||||
|
|
||||||
[node name="portal_right" parent="Ground/DeployLayer" index="1"]
|
[node name="portal_right" parent="Ground/DeployLayer" index="1"]
|
||||||
position = Vector2(1886, 28)
|
position = Vector2(1886, 28)
|
||||||
|
immediately = false
|
||||||
|
|
||||||
[node name="男孩" type="AnimatedSprite2D" parent="Ground/DeployLayer" index="2"]
|
[node name="男孩" type="AnimatedSprite2D" parent="Ground/DeployLayer" index="2"]
|
||||||
position = Vector2(547.5, 0.5)
|
position = Vector2(547.5, 0.5)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
[node name="S01" type="Node2D"]
|
[node name="S01" type="Node2D"]
|
||||||
|
|
||||||
[node name="Ground" parent="." instance=ExtResource("1_gdcov")]
|
[node name="Ground" parent="." instance=ExtResource("1_gdcov")]
|
||||||
|
scene_name = "c02_s01"
|
||||||
|
|
||||||
[node name="AnimationPlayer" parent="Ground" index="0"]
|
[node name="AnimationPlayer" parent="Ground" index="0"]
|
||||||
script = ExtResource("2_uuwn3")
|
script = ExtResource("2_uuwn3")
|
||||||
@ -38,7 +39,7 @@ dialogue = "c02"
|
|||||||
position = Vector2(135, 56)
|
position = Vector2(135, 56)
|
||||||
|
|
||||||
[node name="MainPlayer" parent="Ground" index="5"]
|
[node name="MainPlayer" parent="Ground" index="5"]
|
||||||
position = Vector2(78, 40)
|
position = Vector2(78, 88)
|
||||||
|
|
||||||
[node name="FGSprite2D" parent="Ground/ParallaxForeground/FGParallaxLayer" index="0"]
|
[node name="FGSprite2D" parent="Ground/ParallaxForeground/FGParallaxLayer" index="0"]
|
||||||
texture = null
|
texture = null
|
||||||
|
@ -11,6 +11,8 @@ func _default_data() -> Dictionary:
|
|||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
super._ready()
|
super._ready()
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
func _on_deploy_layer_ready() -> void:
|
func _on_deploy_layer_ready() -> void:
|
||||||
|
@ -43,6 +43,7 @@ size = Vector2(35, 70)
|
|||||||
[node name="S02" type="Node2D"]
|
[node name="S02" type="Node2D"]
|
||||||
|
|
||||||
[node name="Ground" parent="." instance=ExtResource("1_wrr6r")]
|
[node name="Ground" parent="." instance=ExtResource("1_wrr6r")]
|
||||||
|
scene_name = "c02_s02"
|
||||||
|
|
||||||
[node name="AnimationPlayer" parent="Ground" index="0"]
|
[node name="AnimationPlayer" parent="Ground" index="0"]
|
||||||
libraries = {
|
libraries = {
|
||||||
|
@ -9,6 +9,8 @@ func _default_data() -> Dictionary:
|
|||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
super._ready()
|
super._ready()
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
func _on_deploy_layer_ready() -> void:
|
func _on_deploy_layer_ready() -> void:
|
||||||
|
@ -23,6 +23,7 @@ size = Vector2(40, 70)
|
|||||||
[node name="S03" type="Node2D"]
|
[node name="S03" type="Node2D"]
|
||||||
|
|
||||||
[node name="Ground" parent="." instance=ExtResource("1_lheeb")]
|
[node name="Ground" parent="." instance=ExtResource("1_lheeb")]
|
||||||
|
scene_name = "c02_s03"
|
||||||
|
|
||||||
[node name="AnimationPlayer" parent="Ground" index="0"]
|
[node name="AnimationPlayer" parent="Ground" index="0"]
|
||||||
script = ExtResource("2_l2oec")
|
script = ExtResource("2_l2oec")
|
||||||
@ -41,7 +42,7 @@ position = Vector2(629, 2)
|
|||||||
|
|
||||||
[node name="Npc" parent="Ground/DeployLayer" index="2" instance=ExtResource("2_r5smg")]
|
[node name="Npc" parent="Ground/DeployLayer" index="2" instance=ExtResource("2_r5smg")]
|
||||||
position = Vector2(465, 23)
|
position = Vector2(465, 23)
|
||||||
frame_progress = 0.799802
|
frame_progress = 0.514003
|
||||||
character_name = "张胖子"
|
character_name = "张胖子"
|
||||||
dialogue_title = "张胖子_01"
|
dialogue_title = "张胖子_01"
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ ambient_light_energy = 2.0
|
|||||||
position = Vector2(1120, 5)
|
position = Vector2(1120, 5)
|
||||||
|
|
||||||
[node name="MainPlayer" parent="Ground" index="5"]
|
[node name="MainPlayer" parent="Ground" index="5"]
|
||||||
position = Vector2(25, 40)
|
position = Vector2(25, 88)
|
||||||
|
|
||||||
[node name="BGParallaxLayer" parent="Ground/ParallaxForeground" index="0"]
|
[node name="BGParallaxLayer" parent="Ground/ParallaxForeground" index="0"]
|
||||||
use_parent_material = true
|
use_parent_material = true
|
||||||
|
@ -9,6 +9,8 @@ func _default_data() -> Dictionary:
|
|||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
super._ready()
|
super._ready()
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
func _on_deploy_layer_ready() -> void:
|
func _on_deploy_layer_ready() -> void:
|
||||||
|
@ -62,6 +62,17 @@ func _ready() -> void:
|
|||||||
footstep_timer.timeout.connect(_on_footstep_timer_timeout)
|
footstep_timer.timeout.connect(_on_footstep_timer_timeout)
|
||||||
footstep_timer.stop()
|
footstep_timer.stop()
|
||||||
# SceneManager.focus_player(self)
|
# SceneManager.focus_player(self)
|
||||||
|
_check_character_status()
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
if is_node_ready():
|
||||||
|
_check_character_status()
|
||||||
|
|
||||||
|
|
||||||
|
func _check_character_status():
|
||||||
|
# 检查角色锁定状态
|
||||||
|
running_locked = ArchiveManager.archive.player_running_locked
|
||||||
|
|
||||||
|
|
||||||
func _on_footstep_timer_timeout():
|
func _on_footstep_timer_timeout():
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
[gd_scene load_steps=5 format=3 uid="uid://cekhj65axie0p"]
|
[gd_scene load_steps=5 format=3 uid="uid://cekhj65axie0p"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scene/prop/prop_inspector.gd" id="1_2wpwe"]
|
[ext_resource type="Script" path="res://scene/prop/prop_inspector.gd" id="1_2wpwe"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://f186lvt5y2ql" path="res://asset/art/ui/prop/遮罩.png" id="2_j83lq"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cvgw2mxrlr6io" path="res://asset/art/scene/c02/s02_走道/ux_进门鼠疫海报yz.png" id="2_wr575"]
|
[ext_resource type="Texture2D" uid="uid://cvgw2mxrlr6io" path="res://asset/art/scene/c02/s02_走道/ux_进门鼠疫海报yz.png" id="2_wr575"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cgghff16powfg" path="res://asset/art/ui/prop遮罩.png" id="3_uf004"]
|
|
||||||
|
|
||||||
[sub_resource type="LabelSettings" id="LabelSettings_5qe7a"]
|
[sub_resource type="LabelSettings" id="LabelSettings_5qe7a"]
|
||||||
line_spacing = 1.0
|
line_spacing = 1.0
|
||||||
@ -25,7 +25,7 @@ grow_horizontal = 2
|
|||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
texture = ExtResource("3_uf004")
|
texture = ExtResource("2_j83lq")
|
||||||
|
|
||||||
[node name="CenterContainer" type="CenterContainer" parent="."]
|
[node name="CenterContainer" type="CenterContainer" parent="."]
|
||||||
anchors_preset = 8
|
anchors_preset = 8
|
||||||
@ -108,6 +108,6 @@ unique_name_in_owner = true
|
|||||||
modulate = Color(1, 1, 1, 0)
|
modulate = Color(1, 1, 1, 0)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
text = "Q: 退出 E: 阅读"
|
text = "Q: ui_退出 E: ui_阅读"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
vertical_alignment = 1
|
vertical_alignment = 1
|
||||||
|
49
util/lru.gd
Normal file
49
util/lru.gd
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
@tool
|
||||||
|
class_name LRU extends RefCounted
|
||||||
|
|
||||||
|
# LRU 算法
|
||||||
|
var cache_size = 1
|
||||||
|
# keys. 新的在后面,旧的在前面
|
||||||
|
var lru_list = []
|
||||||
|
# key -> value
|
||||||
|
var cache = {}
|
||||||
|
var cache_mutex = Mutex.new()
|
||||||
|
|
||||||
|
|
||||||
|
func _init(size := 8) -> void:
|
||||||
|
cache_size = size
|
||||||
|
|
||||||
|
|
||||||
|
func _get(key: Variant) -> Variant:
|
||||||
|
var v = null
|
||||||
|
cache_mutex.lock()
|
||||||
|
if cache.has(key):
|
||||||
|
lru_list.erase(key)
|
||||||
|
lru_list.append(key)
|
||||||
|
v = cache[key]
|
||||||
|
cache_mutex.unlock()
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
func _set(key: StringName, value: Variant) -> bool:
|
||||||
|
cache_mutex.lock()
|
||||||
|
if cache.has(key):
|
||||||
|
lru_list.erase(key)
|
||||||
|
if cache[key] != value:
|
||||||
|
_release_value(cache[key])
|
||||||
|
cache[key] = value
|
||||||
|
lru_list.append(key)
|
||||||
|
if lru_list.size() > cache_size:
|
||||||
|
var k = lru_list.pop_front()
|
||||||
|
_release_value(cache[k])
|
||||||
|
cache.erase(k)
|
||||||
|
cache_mutex.unlock()
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func _release_value(v: Variant) -> void:
|
||||||
|
if v is Node:
|
||||||
|
if not v.is_inside_tree() and is_instance_valid(v):
|
||||||
|
v.queue_free()
|
||||||
|
elif not v is RefCounted:
|
||||||
|
v.free()
|
Loading…
Reference in New Issue
Block a user