谢夏戈 @ xiexiage.com

游戏场景

May 12

这一章我们来完善游戏世界:搭建舞台、调整摄像机、加边界。

创建游戏场景

小鸟做好了,但现在还没有一个「舞台」让它表演。我们需要创建一个游戏主场景,把小鸟放进去,再加一个摄像机来"看"它。

新建场景,根节点选 Node2D,保存为 scenes/game.tscn03-game-scene-创建游戏场景

使用到的节点:

  • Node2D — 游戏主场景
    • Camera2D — 摄像机(决定屏幕看到哪里)

调整摄像机位置

调整摄像机(固定)位置: 03-game-scene-调整摄像机位置

导入“小鸟”角色

把之前做好的 bird.tscn 拖进场景中,小鸟就出现了: 03-game-scene-导入bird

设置【主场景】然后测试

然后把 game.tscn 设置为【主场景】,点击运行游戏: 03-game-scene-设置主场景

这时候小鸟就在游戏场景里了,点击【鼠标左键】或【空格键】小鸟就会起飞!

确保你已经按上一章配置了【fly】按键映射!

03-game-scene-运行游戏

不过现在不按按键的话,小鸟就会一直往下掉,掉到屏幕外面去。别急,接下来我们会给游戏场景加上边界。

添加边界

为了让小鸟不会掉出屏幕,我们给游戏世界加上底部边界。

使用到的节点:

  • StaticBody2D — 静态物理体(不动,但能碰撞)
    • CollisionShape2D — 碰撞形状
      • WorldBoundaryShape2D — 选择这个形状(世界边界)

03-game-scene-边界

然后选择 StaticBody2D 节点往下拖到边缘底部,因为后续要在该节点里加入【死亡区域(Killzone)】,这样才能触发游戏结束的代码。

03-game-scene-边界2

  1. 先选择 StaticBody2D 节点
  2. 然后点击上方的【编辑所选节点】
    1. 避免拖拽时不小心选中 CollisionShape2D 节点
  3. 然后往下拖拽到摄像机和画面边缘。

测试运行

会发现几个问题,不过都不是问题!

  1. 小鸟在原地高低移动,没有往前飞!但是这是正常的,就是要小鸟在原地高低移动。后续我们只要设置背景和障碍物往左移动就会让玩家以为【小鸟】在往右👉飞。
  2. 小鸟没有点击【fly】就会倒地,但是游戏没有结束,别着急,后面就会完善代码!
  3. 与原版的小鸟有所不同,原本的《Flappy Bird》小鸟在飞的时候会有种“头重脚轻”的感觉:就是在飞的时候仰头,不飞的时候头垂下。在玩家连点的时候有种“扑腾”的感觉。

所以接下来我们就先来优化小鸟的代码脚本,让它可以“扑腾”

优化小鸟的旋转

在原版 Flappy Bird 里,小鸟不是一直直挺挺的 — 往上飞的时候头会抬起来,往下掉的时候头会低下去,看起来更生动。

我们来实现这个效果,思路很简单:

  • 往上飞 → 头朝上(抬头 -30°)
  • 往下掉 → 头朝下(低头 90°)
  • 旋转要平滑过渡,不能一下子就转过去(那样看起来很僵硬)

bird.gd 里加一个旋转函数:

extends CharacterBody2D

@export var gravity_scale := 2.0
@export var jump_force := -400.0
@export var max_fall_speed := 1000.0
@export var rotate_speed := 4.0   # 旋转过渡速度(越大越快)

func _physics_process(delta: float) -> void:
    # 重力
    if not is_on_floor():
        velocity += get_gravity() * delta * gravity_scale

    # 限速
    if velocity.y > max_fall_speed:
        velocity.y = max_fall_speed

    # 跳跃
    if Input.is_action_just_pressed("fly"):
        velocity.y = 0
        velocity.y = jump_force

    # 旋转
    handle_rotation(delta)
    move_and_slide()

func handle_rotation(delta: float) -> void:
    var target_rotation = 0.0

    if velocity.y < 0:
        # 往上飞 → 抬头
        target_rotation = deg_to_rad(-30)
    else:
        # 往下掉 → 低头
        target_rotation = deg_to_rad(90)

    # lerp_angle:让旋转平滑过渡,不会一下子"弹"过去
    rotation = lerp_angle(rotation, target_rotation, rotate_speed * delta)

lerp_angle 的作用就像是给旋转加了"缓动",从当前角度慢慢转到目标角度,而不是瞬间跳过去。rotate_speed 越大转得越快,可以自己调到手感合适为止。

再次测试!

再次运行游戏,看看小鸟是不是有了那种「扑腾扑腾」的灵动感?是不是和原版《Flappy Bird》一个味儿了 ✨

2023-PRESENT © 谢夏戈