# 平台闯关 · Pixel Platformer 一个用 **Godot 4.7** 制作的 2D 像素风平台跳跃游戏。 --- ## 运行方式 1. 用 Godot 4.7 打开本目录(选择 `project.godot`) 2. 按 `F5` 运行 主场景:`scenes/main.tscn` --- ## 操作 | 按键 | 作用 | |---|---| | `A` / `D` | 左右移动 | | `空格` | 跳跃(单段,空中不能二段跳) | | `S` 按住 | 显示投掷抛物线预览 | | `S` 松开 | 投出钥匙 | | `W` | 传送到扔出去的钥匙位置,并把它捡回来 | | `Z` | 消耗一个回血道具:回一颗心 + 5 秒无敌盾 | | `F` | 切换飞行(**隐藏技能**,藏在右上角「房★主★有★神★器★」面板里,见下方说明) | | `R` / `Enter` | 死亡后重新开始 | --- ## 玩法 - **生命值**:共 3 颗心。碰到尖刺扣 1 颗心并被打回出生点,生命归零后进入死亡界面。 - **收集物**:地图上有 3 个金色小球,走过去自动拾取,变成"回血道具"。 - **回血**:按 `Z` 消耗一个道具,回一颗心并获得 5 秒无敌盾。 - **钥匙**:走过去自动捡起;按住 `S` 时实时显示抛物线轨迹和落点;松开投出。按 `W` 可以直接瞬移到钥匙处并收回它。 - **弹簧**:踩上去弹起约 57px(普通跳跃约 20px)。 - **隐藏通道**:关卡里有几处"看着是石壁、其实能直接穿过去"的暗道。 --- ## 对应作业要求 ### ① 玩家移动控制代码 `scripts/player_controller.gd` - 节点类型 `CharacterBody2D`,每帧结束调用 `move_and_slide()` - **重力**:`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()`,因此**只有踩在地面上才能起跳**,天然不会二段跳 - **朝向**:根据 `velocity.x` 的正负翻转 `Sprite2D.flip_h` ### ② 瓦片地图 - 用了 **3 层 `TileMapLayer`**: - `TerrainBase` — 主体地形 - `TerrainDetailsA` / `TerrainDetailsB` — 前景装饰(z_index 1 / 2) - `TileSet` 使用 18×18 的图集(`assets/game/tilesets/`),逐个图块配置了**物理碰撞多边形**;草地单向平台用 `one_way` 实现 - 隐藏通道的做法:在地形层上用 `erase_cell()` 把指定格子挖空,再在那个位置盖一张**完全没有碰撞的 `Sprite2D`**(贴图借用旁边墙块),于是画面上仍然是完整石壁、人却能穿过去 ### ③ 碰撞体的区别与使用场景 项目里四种碰撞方式都用到了: | 类型 | 用在哪 | 为什么选它 | |---|---|---| | `CharacterBody2D` | 玩家 | 需要主动移动、被地形阻挡、能踩在地面和箱子上 | | `StaticBody2D` | 木箱、弹簧、树干、路牌、传送箱 | 不动的实体障碍,玩家能站上去、撞得到 | | `Area2D` | 金币、尖刺、弹簧触发区、钥匙 | 只需要"碰到就触发",**不产生物理推挤**,所以能穿过去 | | `TileMapLayer` 物理层 | 大面积地面 | 重复地形太多,用瓦片自带碰撞最省事,不用摆几百个 CollisionShape2D | **碰撞层约定**: | 层号 | 用途 | |---|---| | 1 | 世界实体(地形、木箱、树干、路牌、弹簧、传送箱) | | 2 | 玩家 | | 4 | 危险物(尖刺) | | 8 | 交互触发区(弹簧、传送箱的检测区) | | 16 | 收集物(金币、宝石、钥匙) | 玩家的 `collision_mask` 只有 layer 1,所以只和"世界实体"发生物理碰撞,不会被金币、尖刺挡住。 ### ④ 角色技能 **技能 A —— 投掷钥匙 + 传送**(`scripts/key.gd`) - 走过去自动捡起钥匙 - 按住 `S`:用**与玩家完全相同的碰撞掩码**做抛物线模拟,实时画出轨迹和落点标记 - 松开 `S`:把钥匙按同样的初速度扔出去 - 按 `W`:瞬移到钥匙所在位置并收回它 - 因为预测和实际飞行调用的是**同一个 `simulate_trajectory()` 函数**,"弧线显示能落到的地方"就等于"钥匙真正落到的地方"(实测偏差 0.000 px) **技能 B —— 飞行(隐藏技能)**(`player_controller.gd`) - 按 `F` 切换飞行状态,`空格` / `S` 控制升降(方向键 ↑ / ↓ 也可以),`A` / `D` 平移 - 屏幕上不会有任何提示,它是藏在右上角 **「房★主★有★神★器★」** 按钮里的彩蛋: 点开面板就能看到飞行开关和跳关按钮(键盘 `1` / `2` / `3` 跳关,`Esc` 关闭面板) - 这个面板由自动加载单例 `scripts/cheat_panel.gd` 提供,**三个关卡都有,正式版里也能用** - 如果想在导出版里也开放,把 `fly_available()` 里的 `OS.is_debug_build()` 去掉即可: ```gdscript func fly_available() -> bool: return debug_fly ``` --- ## 目录结构 ``` ├─ project.godot 引擎配置(输入映射、窗口、渲染) ├─ scripts/ │ ├─ player_controller.gd 玩家:移动、跳跃、生命值、投掷、飞行 │ ├─ key.gd 钥匙:拾取 / 飞行 / 落地、轨迹模拟 │ ├─ spring.gd 弹簧:踩上去弹起 │ ├─ hazard.gd 危险物:碰到扣血 │ ├─ collectible.gd 收集物:走过去拾取 │ ├─ hidden_passages.gd 隐藏通道:挖空地砖 + 盖假墙 │ ├─ hud.gd 左上角:心 + 道具数 + 护盾倒计时 │ └─ death_screen.gd 死亡界面:渐黑 + 重新开始 ├─ scenes/ │ ├─ main.tscn 主场景(关卡) │ ├─ player.tscn 玩家 │ ├─ hud.tscn 状态显示 │ ├─ death_screen.tscn 死亡界面 │ └─ prefabs/ 预制件:金币、钥匙、弹簧、尖刺、木箱、树、路牌 └─ assets/ ├─ game/ 实际使用的素材 └─ kenney/ Kenney 原始素材库 ``` --- ## 素材来源 - 图形素材:**Kenney — Pixel Platformer (1.2)** - 授权:**CC0**(可商用、可修改,无需署名) - 来源:https://kenney.nl - 详见 `LICENSE_KENNEY.txt` --- ## 版本控制 本项目使用 git 进行版本管理。