xiandie/scene/ground/ground.gd

158 lines
5.1 KiB
GDScript3
Raw Normal View History

@tool
class_name Ground2D extends Node2D
@export var scene_name := ""
# 用于在 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_")
@export var player_y_fixed := true
@export var player_y := 70:
2025-01-14 00:56:51 +00:00
set(val):
player_y = val
if is_node_ready():
_reset_player_positon()
@export var reset_player_pos := false:
set(val):
reset_player_pos = false
_reset_player_positon()
2025-01-21 10:52:36 +00:00
@export var camera_focus_marker: CameraFocusMarker
2025-01-13 08:09:57 +00:00
@export_group("Sound")
@export_enum("none", "ghost", "walking", "running", "crawling", "concrete")
var footstep_type: String = "concrete":
set(val):
footstep_type = val
if is_node_ready():
_load_footstep_audio()
2025-01-14 00:56:51 +00:00
@onready var player = %MainPlayer as MainPlayer
@onready var directional_light := %DirectionalLight2D as DirectionalLight2D
@onready var bg_sprite = %BGSprite2D as Sprite2D
@onready var foreground = %ParallaxForeground as ParallaxBackground
@onready var camera = %Camera2D as Camera2D
2025-01-14 00:56:51 +00:00
@onready var footstep_audio = %FootstepAudioPlayer as RandomAudioStreamPlayer
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"),
"walking": preload("res://config/audio/sfx/footstep_walking.tres"),
"running": preload("res://config/audio/sfx/footstep_running.tres"),
"crawling": preload("res://config/audio/sfx/footstep_crawling.tres"),
}
2025-01-06 08:06:20 +00:00
func _ready() -> void:
# 仅在编辑器中调试时,通过 main 场景启动
if GlobalConfig.DEBUG and (not Engine.is_editor_hint()) and (not get_parent() is GroundLoader):
call_deferred("_restart_from_main")
return
# 检查 scene_name 是否合法
scene_name = scene_name.strip_edges()
if not scene_name or scene_name.length() != 7:
printerr("scene_name is not valid")
return
_reset_player_positon()
2025-01-14 00:56:51 +00:00
if Engine.is_editor_hint():
return
foreground.layer = GlobalConfig.CANVAS_LAYER_FG
_set_camera_and_player_boundary()
2025-01-14 00:56:51 +00:00
_load_footstep_audio()
focus_player()
# %ColorRectTop.visible = true
# %ColorRectBottom.visible = true
# 如果 debug 模式下不通过 GroundLoader 启动,则插入到 main 以下
func _restart_from_main():
var main = load("res://scene/main.tscn").instantiate()
# if not main.is_node_ready():
# await main.ready
var ground_loader = main.get_node("./GroundLoader") as GroundLoader
2025-01-21 10:52:36 +00:00
# ground_loader.ignore_archive = true
ground_loader.ignore_archive = false
2025-01-21 10:52:36 +00:00
ground_loader.force_archive_scene = scene_name
ground_loader.force_archive_portal = default_portal
get_node("/root").add_child(main)
2025-01-21 10:52:36 +00:00
# ground_loader.transition_to_scene(scene_name, default_portal, true)
get_parent().queue_free()
func _enter_tree() -> void:
if camera:
camera.enabled = true
func _reset_player_positon():
player.position.x = $DeployLayer/portal_left.position.x
# 从屏幕下边缘算起
player.set_y_from_ground(158.0 - player_y)
func _set_camera_and_player_boundary():
# set current_boarder by bg size
if bg_sprite.texture and not Engine.is_editor_hint():
var size = bg_sprite.texture.get_size() * bg_sprite.scale
# camera rect
var camera_size = Vector2(max(564.0, size.x), max(size.y, 316.0))
var camera_upleft = Vector2(0, -camera_size.y / 2.0)
var camera_rect = Rect2(camera_upleft, camera_size)
# player rect should be set centered, with 30px x padding
var up_left = Vector2(0, -size.y / 2.0)
size.x -= 36.0
up_left.x = bg_sprite.position.x + 18.0
var player_rect = Rect2(up_left, size)
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-13 08:09:57 +00:00
func _load_footstep_audio():
# foot step sound
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
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()
var focus_mutex := Mutex.new()
func get_player() -> MainPlayer:
return player
func focus_node(node: CanvasItem) -> void:
if node.is_ancestor_of(camera_focus_marker):
return
focus_mutex.lock()
var parent = camera_focus_marker.get_parent()
if parent:
parent.remove_child(camera_focus_marker)
node.add_child(camera_focus_marker)
focus_mutex.unlock()
func focus_player() -> void:
focus_node(player)
func move_player_to_portal(portal_name := default_portal) -> void:
var portal_node = get_node_or_null("DeployLayer/portal_" + portal_name) as Node2D
if portal_node:
player.global_position.x = portal_node.global_position.x
if GlobalConfig.DEBUG:
print("move player to portal:", portal_name, portal_node.global_position)
else:
printerr(scene_name + " portal not found: " + portal_name)