diff --git a/README.md b/README.md index b4daa79..2dbacf5 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,12 @@ | 按键 | 作用 | |---|---| | `A` / `D` | 左右移动 | -| `空格` | 跳跃(单段,空中不能二段跳) | +| `空格` | (当前已停用,输入映射里的 `jump` 键位为空) | | `S` 按住 | 显示投掷抛物线预览 | | `S` 松开 | 投出钥匙 | | `W` | 传送到扔出去的钥匙位置,并把它捡回来 | | `Z` | 消耗一个回血道具:回一颗心 + 5 秒无敌盾 | -| `F` | 切换飞行(**仅编辑器 / 调试版可用**,见下方说明) | +| `F` | 切换飞行(**隐藏技能**,藏在右上角「房★主★有★神★器★」面板里,见下方说明) | | `R` / `Enter` | 死亡后重新开始 | --- @@ -49,6 +49,9 @@ - **重力**:`get_gravity()`,只在 `not is_on_floor()` 时累加到 `velocity.y` - **水平移动**:`Input.get_axis("move_left", "move_right")` 取方向,用 `move_toward()` 做加速 / 减速插值,手感比直接赋值柔和 - **跳跃**:`Input.is_action_just_pressed("jump")` 配合 `is_on_floor()`,因此**只有踩在地面上才能起跳**,天然不会二段跳 + - ⚠️ 目前输入映射里的 `jump` **没有绑定任何按键**(空格被空置了),所以这段代码暂时不会触发。 + 想恢复:`项目 → 项目设置 → 输入映射 → jump → 添加按键 → 空格`,或者把 `project.godot` 里 + `jump` 的 `"events"` 改回 `[Object(InputEventKey, ... "physical_keycode":32 ...)]`。 - **朝向**:根据 `velocity.x` 的正负翻转 `Sprite2D.flip_h` ### ② 瓦片地图 @@ -92,10 +95,12 @@ - 按 `W`:瞬移到钥匙所在位置并收回它 - 因为预测和实际飞行调用的是**同一个 `simulate_trajectory()` 函数**,"弧线显示能落到的地方"就等于"钥匙真正落到的地方"(实测偏差 0.000 px) -**技能 B —— 飞行**(`player_controller.gd`) +**技能 B —— 飞行(隐藏技能)**(`player_controller.gd`) -- 按 `F` 切换飞行状态,`W` / `S` 控制升降,`A` / `D` 平移 -- 为了不影响正式玩法的难度平衡,**只在编辑器 / 调试版生效**(`OS.is_debug_build()`),导出正式版按键无效 +- 按 `F` 切换飞行状态,方向键 ↑ / ↓ 控制升降(`S` 也可以下降),`A` / `D` 平移 +- 屏幕上不会有任何提示,它是藏在右上角 **「房★主★有★神★器★」** 按钮里的彩蛋: + 点开面板就能看到飞行开关和跳关按钮(键盘 `1` / `2` / `3` 跳关,`Esc` 关闭面板) +- 这个面板由自动加载单例 `scripts/cheat_panel.gd` 提供,**三个关卡都有,正式版里也能用** - 如果想在导出版里也开放,把 `fly_available()` 里的 `OS.is_debug_build()` 去掉即可: ```gdscript func fly_available() -> bool: diff --git a/project.godot b/project.godot index e58a9c0..fa4e08e 100644 --- a/project.godot +++ b/project.godot @@ -17,7 +17,7 @@ config/icon="res://icon.svg" [autoload] -LevelSkip="*res://scenes/level_skip.tscn" +CheatPanel="*res://scenes/cheat_panel.tscn" [display] @@ -45,8 +45,7 @@ move_right={ } jump={ "deadzone": 0.2, -"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) -] +"events": [] } warp_to_key={ "deadzone": 0.2, diff --git a/scenes/cheat_panel.tscn b/scenes/cheat_panel.tscn new file mode 100644 index 0000000..7fd92b3 --- /dev/null +++ b/scenes/cheat_panel.tscn @@ -0,0 +1,77 @@ +[gd_scene load_steps=4 format=3] + +[ext_resource type="Script" path="res://scripts/cheat_panel.gd" id="1_cheat"] + +[sub_resource type="SystemFont" id="SystemFont_cjk"] +font_names = PackedStringArray("Microsoft YaHei UI", "Microsoft YaHei", "SimHei", "Noto Sans CJK SC", "sans-serif") + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_panel"] +content_margin_left = 10.0 +content_margin_top = 10.0 +content_margin_right = 10.0 +content_margin_bottom = 10.0 +bg_color = Color(0.07, 0.08, 0.13, 0.92) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(1, 0.82, 0.35, 0.85) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[node name="CheatPanel" type="CanvasLayer"] +process_mode = 3 +layer = 40 +script = ExtResource("1_cheat") + +[node name="OpenButton" type="Button" parent="."] +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -178.0 +offset_top = 6.0 +offset_right = -6.0 +offset_bottom = 28.0 +theme_override_colors/font_color = Color(1, 0.88, 0.5, 1) +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 11 +text = "房★主★有★神★器★" + +[node name="Panel" type="PanelContainer" parent="."] +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -178.0 +offset_top = 32.0 +offset_right = -6.0 +offset_bottom = 168.0 +theme_override_styles/panel = SubResource("StyleBoxFlat_panel") + +[node name="VBox" type="VBoxContainer" parent="Panel"] +theme_override_constants/separation = 6 + +[node name="Title" type="Label" parent="Panel/VBox"] +theme_override_colors/font_color = Color(1, 0.85, 0.4, 1) +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 12 +text = "神 器" +horizontal_alignment = 1 + +[node name="FlyButton" type="Button" parent="Panel/VBox"] +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 11 +text = "飞行:关(F)" + +[node name="Row" type="HBoxContainer" parent="Panel/VBox"] +theme_override_constants/separation = 5 + +[node name="JumpHint" type="Label" parent="Panel/VBox/Row"] +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 11 +text = "跳关" +vertical_alignment = 1 + +[node name="CloseButton" type="Button" parent="Panel/VBox"] +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 11 +text = "关闭(Esc)" diff --git a/scenes/level3.tscn b/scenes/level3.tscn index 03f3abf..0d6d83a 100644 --- a/scenes/level3.tscn +++ b/scenes/level3.tscn @@ -226,7 +226,7 @@ position = Vector2(288, 37) [node name="CoinGoldRound_01" parent="Level/PrefabInstances/Collectibles" unique_id=926105584 instance=ExtResource("17_16ffm")] z_index = 5 -position = Vector2(447, 130) +position = Vector2(432, 127) [node name="CoinGoldRound_02" parent="Level/PrefabInstances/Collectibles" unique_id=1674416025 instance=ExtResource("17_16ffm")] z_index = 5 diff --git a/scenes/level_skip.tscn b/scenes/level_skip.tscn deleted file mode 100644 index 61427da..0000000 --- a/scenes/level_skip.tscn +++ /dev/null @@ -1,29 +0,0 @@ -[gd_scene load_steps=3 format=3] - -[ext_resource type="Script" path="res://scripts/level_skip.gd" id="1_skip"] - -[sub_resource type="SystemFont" id="SystemFont_cjk"] -font_names = PackedStringArray("Microsoft YaHei UI", "Microsoft YaHei", "SimHei", "Noto Sans CJK SC", "sans-serif") - -[node name="LevelSkip" type="CanvasLayer"] -process_mode = 3 -layer = 30 -script = ExtResource("1_skip") - -[node name="Buttons" type="HBoxContainer" parent="."] -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -130.0 -offset_top = 6.0 -offset_right = -6.0 -offset_bottom = 32.0 -theme_override_constants/separation = 4 - -[node name="Hint" type="Label" parent="Buttons"] -theme_override_colors/font_color = Color(1, 1, 1, 0.85) -theme_override_colors/font_outline_color = Color(0, 0, 0, 0.8) -theme_override_constants/outline_size = 3 -theme_override_fonts/font = SubResource("SystemFont_cjk") -theme_override_font_sizes/font_size = 11 -text = "跳关" -vertical_alignment = 1 diff --git a/scripts/cheat_panel.gd b/scripts/cheat_panel.gd new file mode 100644 index 0000000..79d0b8c --- /dev/null +++ b/scripts/cheat_panel.gd @@ -0,0 +1,111 @@ +extends CanvasLayer + +## 「房★主★有★神★器★」:把两个调试功能(飞行 / 跳关)藏在一个彩蛋按钮里。 +## +## 平时屏幕上只有右上角一个小小的「房★主★有★神★器★」按钮, +## 点一下才弹出面板,里面是飞行开关和跳关按钮。 +## 面板打开时键盘 1/2/3 也能跳关,Esc 或再点一次按钮关闭。 +## 正式版里也能用(这是刻意留的彩蛋,不是调试残留)。 + +@export var levels: Array[String] = [ + "res://scenes/main.tscn", + "res://scenes/level2.tscn", + "res://scenes/level3.tscn", +] +## 是否显示那个彩蛋按钮(关掉的话就只能靠别的方式打开面板了) +@export var show_button: bool = true + +var _panel: Control = null +var _open_button: Button = null +var _fly_button: Button = null +var _player: Node = null +var _open: bool = false + + +func _ready() -> void: + visible = true + _panel = get_node_or_null("Panel") + _open_button = get_node_or_null("OpenButton") + _fly_button = get_node_or_null("Panel/VBox/FlyButton") + + if _open_button != null: + _open_button.visible = show_button + _open_button.pressed.connect(toggle_panel) + + var close := get_node_or_null("Panel/VBox/CloseButton") + if close != null: + close.pressed.connect(toggle_panel) + + if _fly_button != null: + _fly_button.pressed.connect(toggle_fly) + + var row := get_node_or_null("Panel/VBox/Row") + if row != null: + var index := 1 + for path in levels: + var btn := Button.new() + btn.text = str(index) + btn.custom_minimum_size = Vector2(26.0, 24.0) + btn.focus_mode = Control.FOCUS_NONE + btn.add_theme_font_size_override("font_size", 12) + btn.pressed.connect(jump_to.bind(path)) + row.add_child(btn) + index += 1 + + if _panel != null: + _panel.visible = false + + +func _process(_delta: float) -> void: + if _fly_button == null: + return + if _player == null or not is_instance_valid(_player): + _player = get_tree().get_first_node_in_group("player") + if _player == null: + _fly_button.text = "飞行(F)" + return + _fly_button.text = "飞行:开(F)" if bool(_player.flying) else "飞行:关(F)" + + +func _unhandled_input(event: InputEvent) -> void: + if not _open: + return + var key := event as InputEventKey + if key == null or not key.pressed or key.echo: + return + if key.physical_keycode == KEY_ESCAPE: + toggle_panel() + return + var n := 0 + match key.physical_keycode: + KEY_1: + n = 1 + KEY_2: + n = 2 + KEY_3: + n = 3 + KEY_4: + n = 4 + KEY_5: + n = 5 + if n >= 1 and n <= levels.size(): + jump_to(levels[n - 1]) + + +func toggle_panel() -> void: + _open = not _open + if _panel != null: + _panel.visible = _open + + +func toggle_fly() -> void: + if _player == null or not is_instance_valid(_player): + _player = get_tree().get_first_node_in_group("player") + if _player == null or not _player.has_method("set_flying"): + return + _player.set_flying(not bool(_player.flying)) + + +func jump_to(path: String) -> void: + get_tree().paused = false + get_tree().change_scene_to_file(path) diff --git a/scripts/level_skip.gd b/scripts/level_skip.gd deleted file mode 100644 index 94cecd5..0000000 --- a/scripts/level_skip.gd +++ /dev/null @@ -1,59 +0,0 @@ -extends CanvasLayer - -## 测试用跳关:右上角一排数字按钮,点一下直接跳到对应关卡; -## 键盘上按 1 / 2 / 3 也一样。 -## 只在编辑器 / 调试版里显示,导出的正式版会自动隐藏(和飞行一个规矩)。 - -@export var levels: Array[String] = [ - "res://scenes/main.tscn", - "res://scenes/level2.tscn", - "res://scenes/level3.tscn", -] -## 强制在正式版里也显示(一般别开) -@export var always_show: bool = false - - -func _ready() -> void: - visible = always_show or OS.is_debug_build() - if not visible: - set_process_unhandled_input(false) - return - - var box := get_node_or_null("Buttons") - if box == null: - return - var index := 1 - for path in levels: - var btn := Button.new() - btn.text = str(index) - btn.custom_minimum_size = Vector2(24.0, 24.0) - btn.focus_mode = Control.FOCUS_NONE - btn.add_theme_font_size_override("font_size", 12) - btn.pressed.connect(jump_to.bind(path)) - box.add_child(btn) - index += 1 - - -func _unhandled_input(event: InputEvent) -> void: - var key := event as InputEventKey - if key == null or not key.pressed or key.echo: - return - var n := 0 - match key.physical_keycode: - KEY_1, KEY_KP_1: - n = 1 - KEY_2, KEY_KP_2: - n = 2 - KEY_3, KEY_KP_3: - n = 3 - KEY_4, KEY_KP_4: - n = 4 - KEY_5, KEY_KP_5: - n = 5 - if n >= 1 and n <= levels.size(): - jump_to(levels[n - 1]) - - -func jump_to(path: String) -> void: - get_tree().paused = false - get_tree().change_scene_to_file(path) diff --git a/scripts/player_controller.gd b/scripts/player_controller.gd index d9310bd..fc61e96 100644 --- a/scripts/player_controller.gd +++ b/scripts/player_controller.gd @@ -357,7 +357,8 @@ func _build_throw_visuals() -> void: # ---------------------------------------------------------------- 测试用飞行 func fly_available() -> bool: - return debug_fly and OS.is_debug_build() + # 这是藏在「房★主★有★神★器★」面板里的隐藏技能,正式版里也能用 + return debug_fly func set_flying(on: bool) -> void: @@ -368,10 +369,13 @@ func set_flying(on: bool) -> void: func handle_fly_movement() -> void: - # get_axis(负方向, 正方向),屏幕坐标里 y 向下为正,所以空格(跳跃)要放在负方向 + # 跳跃键已经停用了,所以调试飞行改用方向键上下(S 也保留作下降)来控制升降 + var vertical := Input.get_axis("ui_up", "ui_down") + if is_zero_approx(vertical) and Input.is_action_pressed("squat"): + vertical = 1.0 var direction := Vector2( Input.get_axis("move_left", "move_right"), - Input.get_axis("jump", "squat") + vertical ) if direction == Vector2.ZERO: velocity = Vector2.ZERO