extends Area3D # Портал на другую карту: шаг в рамку — переход. Для сети игрок попадает в «комнату» новой карты. @export var target_map := "backrooms" @export var target_scene := "res://maps/backrooms/backrooms.tscn" @export var pack_name := "" # Пакет с картой (качается при первом входе); пусто — карта уже в игре @export var title := "BACKROOMS" @export var color := Color(1.0, 0.85, 0.25) @export var frame_size := Vector2(2.6, 3.6) @export var trigger_size := Vector3(3.2, 3.6, 3.0) # Зона входа шире рамки, чтобы не обойти сбоку var _used := false var _glow: StandardMaterial3D func _ready() -> void: collision_layer = 0 collision_mask = 1 var cs := CollisionShape3D.new() var shape := BoxShape3D.new() shape.size = trigger_size cs.shape = shape cs.position.y = trigger_size.y * 0.5 add_child(cs) _build_visuals() body_entered.connect(_on_body_entered) MapLoader.enter_failed.connect(func(): _used = false) # Не скачалось — можно зайти ещё раз func _build_visuals() -> void: var w := frame_size.x var h := frame_size.y var frame_mat := StandardMaterial3D.new() frame_mat.albedo_color = color.darkened(0.5) frame_mat.emission_enabled = true frame_mat.emission = color frame_mat.emission_energy_multiplier = 1.5 _add_box(Vector3(0.2, h, 0.2), Vector3(-w * 0.5 - 0.1, h * 0.5, 0), frame_mat) _add_box(Vector3(0.2, h, 0.2), Vector3(w * 0.5 + 0.1, h * 0.5, 0), frame_mat) _add_box(Vector3(w + 0.4, 0.2, 0.2), Vector3(0, h + 0.1, 0), frame_mat) _glow = StandardMaterial3D.new() _glow.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED _glow.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA _glow.cull_mode = BaseMaterial3D.CULL_DISABLED _glow.albedo_color = Color(color, 0.35) var quad := QuadMesh.new() quad.size = frame_size quad.material = _glow var plane := MeshInstance3D.new() plane.mesh = quad plane.position.y = h * 0.5 plane.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF add_child(plane) var label := Label3D.new() label.text = title label.billboard = BaseMaterial3D.BILLBOARD_ENABLED label.pixel_size = 0.01 label.font_size = 64 label.outline_size = 12 label.modulate = color label.position.y = h + 0.8 add_child(label) var light := OmniLight3D.new() light.light_color = color light.light_energy = 1.5 light.omni_range = 9.0 light.position.y = h * 0.5 light.shadow_enabled = false add_child(light) func _add_box(size: Vector3, pos: Vector3, mat: Material) -> void: var mesh := BoxMesh.new() mesh.size = size mesh.material = mat var mi := MeshInstance3D.new() mi.mesh = mesh mi.position = pos mi.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF add_child(mi) func _process(_delta: float) -> void: _glow.albedo_color.a = 0.3 + 0.12 * sin(Time.get_ticks_msec() * 0.004) func _on_body_entered(body: Node3D) -> void: if _used or not body.is_in_group("local_player") or body.get("is_dead"): return _used = true MapLoader.enter(target_map, target_scene, pack_name, title)