2025-01-05 11:25:13 +00:00
|
|
|
@tool
|
2025-01-03 08:07:35 +00:00
|
|
|
class_name Ground2D extends Node2D
|
2024-12-25 12:24:34 +00:00
|
|
|
|
2025-01-21 07:58:21 +00:00
|
|
|
@export var scene_name := ""
|
2025-01-21 10:08:16 +00:00
|
|
|
# 用于在 debug 时态下,指定进入的 portal
|
2025-01-21 10:52:36 +00:00
|
|
|
@export_enum("left", "right", "1", "2", "3", "4", "5", "6", "7", "8", "9")
|
|
|
|
var default_portal := "left"
|
2025-01-13 08:09:57 +00:00
|
|
|
@export_group("Player", "player_")
|
2025-01-26 13:11:38 +00:00
|
|
|
@export var player_y_fixed := true:
|
|
|
|
set(val):
|
|
|
|
player_y_fixed = val
|
|
|
|
if is_node_ready():
|
|
|
|
_reset_player_y()
|
2025-01-20 13:45:47 +00:00
|
|
|
@export var player_y := 70:
|
2025-01-14 00:56:51 +00:00
|
|
|
set(val):
|
|
|
|
player_y = val
|
|
|
|
if is_node_ready():
|
2025-01-26 13:11:38 +00:00
|
|
|
_reset_player_y()
|
2025-01-27 15:13:37 +00:00
|
|
|
@export var replace_player_to_portal := false:
|
2025-01-15 04:02:11 +00:00
|
|
|
set(val):
|
2025-01-27 15:13:37 +00:00
|
|
|
replace_player_to_portal = false
|
2025-01-21 13:49:37 +00:00
|
|
|
if is_node_ready():
|
2025-01-27 15:13:37 +00:00
|
|
|
move_player_to_portal(default_portal)
|
2025-01-13 08:09:57 +00:00
|
|
|
@export_group("Sound")
|
2025-06-15 09:31:43 +00:00
|
|
|
@export_enum("none", "ghost", "硬地面", "室外", "crawling", "盒子猫")
|
2025-04-20 13:35:13 +00:00
|
|
|
var footstep_type: String = "硬地面":
|
2025-01-13 08:09:57 +00:00
|
|
|
set(val):
|
|
|
|
footstep_type = val
|
|
|
|
if is_node_ready():
|
|
|
|
_load_footstep_audio()
|
|
|
|
|
2025-01-30 04:50:52 +00:00
|
|
|
@onready var player_line = %PlayerLine2D as Line2D
|
2025-01-14 00:56:51 +00:00
|
|
|
@onready var player = %MainPlayer as MainPlayer
|
2025-01-05 11:25:13 +00:00
|
|
|
@onready var directional_light := %DirectionalLight2D as DirectionalLight2D
|
2025-01-15 04:02:11 +00:00
|
|
|
@onready var bg_sprite = %BGSprite2D as Sprite2D
|
2024-12-25 12:24:34 +00:00
|
|
|
@onready var foreground = %ParallaxForeground as ParallaxBackground
|
2025-01-21 13:49:37 +00:00
|
|
|
@onready var camera_focus_marker = %CameraFocusMarker as CameraFocusMarker
|
2024-12-25 12:24:34 +00:00
|
|
|
|
2025-01-14 00:56:51 +00:00
|
|
|
@onready var footstep_audio = %FootstepAudioPlayer as RandomAudioStreamPlayer
|
2024-12-25 12:24:34 +00:00
|
|
|
|
2025-01-13 08:09:57 +00:00
|
|
|
const FOOTSTEP_AUDIO = {
|
|
|
|
#"wood": preload("res://config/audio/footstep/footstep_wood.tres"),
|
|
|
|
#"carpet": preload("res://config/audio/footstep/footstep_carpet.tres"),
|
|
|
|
"concrete": preload("res://config/audio/footstep/footstep_concrete.tres"),
|
|
|
|
#"grass": preload("res://config/audio/footstep/footstep_grass.tres"),
|
|
|
|
#"snow": preload("res://config/audio/footstep/footstep_snow.tres"),
|
|
|
|
"ghost": preload("res://config/audio/sfx/footstep_ghost.tres"),
|
2025-04-20 13:35:13 +00:00
|
|
|
"硬地面": preload("res://config/audio/sfx/footstep_硬地面.tres"),
|
|
|
|
"室外": preload("res://config/audio/sfx/footstep_室外.tres"),
|
2025-01-13 08:09:57 +00:00
|
|
|
"crawling": preload("res://config/audio/sfx/footstep_crawling.tres"),
|
2025-06-15 09:31:43 +00:00
|
|
|
# 待替换
|
|
|
|
"盒子猫": preload("res://config/audio/footstep/footstep_concrete.tres"),
|
2025-01-13 08:09:57 +00:00
|
|
|
}
|
2025-01-06 08:06:20 +00:00
|
|
|
|
2025-06-04 11:46:27 +00:00
|
|
|
var restarting = false
|
2025-01-06 08:06:20 +00:00
|
|
|
|
2025-06-04 11:46:27 +00:00
|
|
|
func _enter_tree() -> void:
|
2025-01-21 10:08:16 +00:00
|
|
|
# 仅在编辑器中调试时,通过 main 场景启动
|
|
|
|
if GlobalConfig.DEBUG and (not Engine.is_editor_hint()) and (not get_parent() is GroundLoader):
|
2025-06-04 11:46:27 +00:00
|
|
|
print("restarting...")
|
2025-01-21 10:08:16 +00:00
|
|
|
call_deferred("_restart_from_main")
|
2025-06-04 11:46:27 +00:00
|
|
|
restarting= true
|
|
|
|
return
|
|
|
|
if camera_focus_marker:
|
|
|
|
camera_focus_marker.enabled = true
|
|
|
|
|
|
|
|
func _ready() -> void:
|
|
|
|
if restarting:
|
|
|
|
print("restarting: skip ground _ready()")
|
2025-01-21 10:08:16 +00:00
|
|
|
return
|
2025-06-14 08:46:32 +00:00
|
|
|
foreground.layer = GlobalConfig.CANVAS_LAYER_FG
|
2025-01-21 07:58:21 +00:00
|
|
|
# 检查 scene_name 是否合法
|
|
|
|
scene_name = scene_name.strip_edges()
|
2025-01-21 13:49:37 +00:00
|
|
|
if get_parent().name.begins_with("S") and (not scene_name or scene_name.length() != 7):
|
2025-01-21 07:58:21 +00:00
|
|
|
printerr("scene_name is not valid")
|
2025-01-14 00:56:51 +00:00
|
|
|
if Engine.is_editor_hint():
|
|
|
|
return
|
2025-06-14 08:46:32 +00:00
|
|
|
# 隐藏 player_line
|
|
|
|
player_line.visible = false
|
2025-01-15 04:02:11 +00:00
|
|
|
_set_camera_and_player_boundary()
|
2025-01-14 00:56:51 +00:00
|
|
|
_load_footstep_audio()
|
2025-01-21 13:49:37 +00:00
|
|
|
# marker 默认就在 foucs player 状态
|
|
|
|
# camera_focus_marker.focus_node(player)
|
2025-01-03 13:29:22 +00:00
|
|
|
# %ColorRectTop.visible = true
|
|
|
|
# %ColorRectBottom.visible = true
|
2025-01-21 10:08:16 +00:00
|
|
|
# 如果 debug 模式下不通过 GroundLoader 启动,则插入到 main 以下
|
2025-06-07 09:04:08 +00:00
|
|
|
_setup_player_light()
|
2025-01-21 10:08:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
func _restart_from_main():
|
2025-06-17 03:39:55 +00:00
|
|
|
ArchiveManager.archive.current_scene = scene_name
|
|
|
|
ArchiveManager.archive.entrance_portal = default_portal
|
|
|
|
get_tree().change_scene_to_packed(preload("res://scene/main.tscn"))
|
|
|
|
|
|
|
|
# var main = get_tree().current_scene
|
|
|
|
# # if not main.is_node_ready():
|
|
|
|
# # await main.ready
|
|
|
|
# var ground_loader = main.get_node("./GroundLoader") as GroundLoader
|
|
|
|
# # ground_loader.ignore_archive = true
|
|
|
|
# ground_loader.ignore_archive = false
|
|
|
|
# ground_loader.force_archive_scene = scene_name
|
|
|
|
# ground_loader.force_archive_portal = default_portal
|
2024-12-25 12:24:34 +00:00
|
|
|
|
|
|
|
|
2025-01-26 13:11:38 +00:00
|
|
|
func _reset_player_y():
|
2025-01-20 13:45:47 +00:00
|
|
|
# 从屏幕下边缘算起
|
2025-01-26 13:11:38 +00:00
|
|
|
if player_y_fixed:
|
|
|
|
player.set_y_from_ground(158.0 - player_y)
|
2025-01-15 04:02:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
func _set_camera_and_player_boundary():
|
|
|
|
# set current_boarder by bg size
|
2025-01-30 04:50:52 +00:00
|
|
|
var camera_rect = Rect2(0, -158, 564, 316)
|
|
|
|
var player_rect = Rect2(0, -158, 564, 316)
|
2025-01-15 04:02:11 +00:00
|
|
|
if bg_sprite.texture and not Engine.is_editor_hint():
|
|
|
|
var size = bg_sprite.texture.get_size() * bg_sprite.scale
|
|
|
|
# camera rect
|
2025-01-30 04:50:52 +00:00
|
|
|
var camera_size = size
|
|
|
|
camera_size.x += bg_sprite.position.x
|
|
|
|
camera_size = Vector2(max(564.0, camera_size.x), max(camera_size.y, 316.0))
|
2025-01-15 04:02:11 +00:00
|
|
|
var camera_upleft = Vector2(0, -camera_size.y / 2.0)
|
2025-01-30 04:50:52 +00:00
|
|
|
camera_rect = Rect2(camera_upleft, camera_size)
|
|
|
|
# player rect should be set centered, with 30px x padding
|
2025-02-04 13:30:43 +00:00
|
|
|
player_rect.position.x = player_line.get_point_position(0).x + player_line.global_position.x
|
|
|
|
player_rect.size.x = player_line.get_point_position(1).x - player_line.get_point_position(0).x
|
2025-01-30 04:50:52 +00:00
|
|
|
SceneManager.set_camera_boundary(camera_rect)
|
|
|
|
SceneManager.set_player_boundary(player_rect)
|
|
|
|
if GlobalConfig.DEBUG:
|
|
|
|
print("_set_camera_and_player_boundary:", camera_rect, player_rect)
|
2025-01-15 04:02:11 +00:00
|
|
|
|
|
|
|
|
2025-01-13 08:09:57 +00:00
|
|
|
func _load_footstep_audio():
|
2025-01-05 11:25:13 +00:00
|
|
|
# foot step sound
|
2024-12-25 12:24:34 +00:00
|
|
|
footstep_audio.audio_collections.clear()
|
2025-01-13 08:09:57 +00:00
|
|
|
if footstep_type != "none":
|
|
|
|
var audio = FOOTSTEP_AUDIO[footstep_type] as AudioStreamCollection
|
2025-01-05 11:25:13 +00:00
|
|
|
footstep_audio.audio_collections.append(audio)
|
2025-01-13 08:09:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
func play_footstep_sound() -> void:
|
|
|
|
if not footstep_audio.audio_collections.is_empty():
|
|
|
|
footstep_audio.play_random()
|
2025-01-16 12:24:21 +00:00
|
|
|
|
|
|
|
|
2025-01-21 13:49:37 +00:00
|
|
|
func move_player_to_portal(portal_name: String) -> void:
|
2025-02-06 12:19:45 +00:00
|
|
|
var node_path = NodePath("DeployLayer/portal_" + portal_name)
|
|
|
|
var portal_node = get_node_or_null(node_path) as Portal2D
|
2025-01-31 10:44:30 +00:00
|
|
|
if portal_node and player:
|
2025-01-21 10:08:16 +00:00
|
|
|
player.global_position.x = portal_node.global_position.x
|
2025-01-30 04:50:52 +00:00
|
|
|
if portal_name == "left":
|
|
|
|
player.set_facing_direction(Vector2.RIGHT)
|
|
|
|
elif portal_name == "right":
|
|
|
|
player.set_facing_direction(Vector2.LEFT)
|
|
|
|
_reset_player_y()
|
2025-01-21 10:08:16 +00:00
|
|
|
if GlobalConfig.DEBUG:
|
|
|
|
print("move player to portal:", portal_name, portal_node.global_position)
|
2025-02-06 12:19:45 +00:00
|
|
|
elif player:
|
|
|
|
printerr(scene_name, " portal not found: ", node_path)
|
2025-01-21 10:08:16 +00:00
|
|
|
else:
|
2025-02-06 12:19:45 +00:00
|
|
|
printerr("move_player_to_portal player not ready")
|
2025-01-21 13:49:37 +00:00
|
|
|
# 传送后,重置 camera 位置
|
|
|
|
camera_focus_marker.reset_position_immediately()
|
2025-06-07 09:04:08 +00:00
|
|
|
|
|
|
|
func _setup_player_light():
|
2025-06-14 08:46:32 +00:00
|
|
|
# 强制显示 directional_light
|
|
|
|
directional_light.visible = true
|
2025-06-07 09:04:08 +00:00
|
|
|
# 设置角色身上光源
|
|
|
|
if directional_light.blend_mode == Light2D.BLEND_MODE_SUB and directional_light.energy > 0.6:
|
|
|
|
player.enable_light = true
|
|
|
|
else:
|
|
|
|
player.enable_light = false
|
|
|
|
print("_setup_player_light player.enable_light=", player.enable_light)
|