十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Godot 2D游戏开发实战:2小时搭建平台跳跃+瓦片地图+敌人AI

Godot 2D游戏开发实战:2小时搭建平台跳跃+瓦片地图+敌人AI 平台跳跃、瓦片地图、敌人AI这三个词组合在一起基本就是2D游戏开发入门里最经典的一条路。很多人在Godot教程里搜到的内容要么只讲移动要么只讲瓦片很难一口气把一个能玩的小关卡串起来。这篇教程更像一次实测记录我会按实际开发顺序拆解从创建项目、绘制瓦片地图、写玩家移动和跳跃到给敌人加巡逻和追击最后把死亡和重生逻辑接好。如果你刚开始接触Godot希望一次跑通完整流程可以直接照着做。标题里的2h不是卡死时间而是给出一个紧凑节奏。如果已经有一点Godot基础一个下午绰绰有余如果完全零基础重点是把每一步背后的原因理解到位而不是追求两小时跑完。我更建议不要跳步特别是物理碰撞和输入映射这两块后面几乎所有问题都跟它们有关。1. 先把瓦片地图、敌人AI和平台跳跃拆开看1.1 这个教程解决什么问题平台跳跃类游戏的需求很固定角色左右移动、跳跃、踩敌人或者避开敌人、从地图掉落、到达终点。用Godot做的时候会用到几个非常基础的节点CharacterBody2D负责角色和敌人的物理移动TileMapLayer负责关卡地形Area2D负责触发尖刺和死亡判定RayCast2D负责敌人检测墙壁和悬崖。很多新手一上来就想做完整Demo结果卡在节点路径、物理层、输入映射这些细节上。这篇教程把每个环节拆成独立步骤每一步都能单独验证。先跑通一条再扩展成完整关卡会顺很多。1.2 2小时到底能完成到什么程度如果一切正常两小时左右可以完成一个包含左右移动、跳跃、简单地形、一个自动巡逻敌人、一个死亡重生的迷你关卡。注意这里说的是迷你关卡不是带美术资源、多关卡、复杂敌人AI的商业Demo。我建议把目标定成“能跑通手感正常”而不是“功能多”。做游戏开发最容易犯的错就是第一版想塞太多东西。先做一小块地图放一个敌人跑完死亡和重生流程这个小型闭环比单纯堆节点有价值得多。2. 环境准备Godot版本、项目创建、输入映射2.1 下载哪个版本创建2D项目Godot 4.x和3.x的API差异比较大。很多旧教程还在用3.x的写法放到4.x里会直接报错。这篇教程的代码和节点结构都按Godot 4.x的用法来写下载时选择标准版即可不需要额外组件。第一次打开Godot先创建一个2D项目。项目路径尽量不要带中文和空格否则后面导入素材、导出游戏时容易出奇怪问题。创建完成后场景面板里默认有一个Node2D根节点可以重命名为Main作为整个关卡的主场景。在这里先只做一件事把项目设置里的主场景指定成Main.tscn。后面每次运行就从这个场景开始。可以在项目设置里找到“Application/Run/Main Scene”来配置。2.2 输入映射左右移动和跳跃键平台跳跃最核心的输入只有三个动作向左、向右、跳跃。不要直接在主循环里判断键盘键位更标准的做法是在项目设置里配置Input动作。打开项目设置里的“Input Map”新建几个动作left绑定A键和左方向键right绑定D键和右方向键jump绑定空格键和上方向键脚本里用Input.get_axis(left, right)获取移动方向返回-1到1之间的值用Input.is_action_just_pressed(jump)检测跳跃按下。这样做的原因是玩家按键后你只需要关心动作名不需要关心具体是键盘、手柄还是触屏后面改键位也不用动代码。如果角色按了方向键没有反应最先检查的就是输入映射。动作名写错、快捷键没保存、脚本里单词拼错这三类问题占输入失效的大多数。3. 瓦片地图TileMap搭建从TileSet到物理层3.1 准备瓦片素材并切割成TileSet瓦片地图就是把一张大地图素材切成很多小块再像拼图一样拼出关卡。Godot里需要先创建TileSet资源再在TileSet里把素材图切割成格子。导入素材后在TileSet编辑器中设置Tile Size。常见尺寸是16x16、32x32具体看你的素材图。选择图片后点击“自动切片”Godot会根据Tile Size把图片切成多个瓦片。这里最容易忽略的是物理层。瓦片本身只是一张图片如果不设置物理碰撞角色走到上面会直接穿透。所以需要在TileSet里打开物理图层Physics Layer框选哪些瓦片作为地面给它们加上碰撞形状并把碰撞形状调整到瓦片范围内。判断标准很简单运行场景角色落在瓦片上能站稳跳起来落到平台上也掉不下去。3.2 在TileMapLayer上绘制关卡Godot 4.x里使用TileMapLayer节点来绘制瓦片地图。注意旧版Godot 3.x是TileMap节点新版改成了TileMapLayer两者名称不同网上搜教程时要注意版本。在场景里添加TileMapLayer节点把前面做好的TileSet资源拖进去。然后选择绘制工具在编辑器里直接画出地面、平台、装饰物。绘制时建议分图层不要把地面和装饰都画在一个TileMapLayer里。一个专门画可碰撞的地面一个画花花草草等装饰。装饰层的Z Index可以设高一点这样角色经过时看起来更有层次。3.3 常见瓦片问题排查瓦片相关的问题我遇到过最多的有三个角色穿过瓦片掉下去先检查TileSet的物理层有没有设置碰撞形状有没有被误删。瓦片对不齐检查Tile Size是否和素材像素一致。比如素材是32x32你却设成16x16画面会乱。角色站在边缘会抖动碰撞形状太大可以稍微缩小一格同时把玩家的碰撞体也缩小一点。先处理瓦片和碰撞再调玩家代码。很多人一上来就改物理参数结果越改越乱。地图数据如果不对后面全都白搭。4. 玩家角色CharacterBody2D的移动、跳跃和手感4.1 玩家节点结构和物理碰撞玩家场景用CharacterBody2D作为根节点它适合用来做受物理约束但由代码控制移动的角色比如平台跳跃的主角。Player场景结构大致是CharacterBody2D根节点Sprite2D显示角色图片CollisionShape2D碰撞形状碰撞体不要太大否则容易卡在平台边缘。常见的做法是让碰撞体比精灵稍微小一圈尤其是角色脚下避免站在地面时“视觉上站不稳”。还要注意碰撞层设置。玩家和地面、玩家和敌人都要正确设置Layer和Mask。最简单的做法玩家放在图层1地面放在图层2敌人放在图层3。玩家Mask勾上地面和敌人这样角色既能站在地面上也会被敌人碰到。4.2 脚本逻辑重力、移动、跳跃下面是玩家角色的GDScript示例Godot 4.x写法extends CharacterBody2D export var speed: float 200.0 export var jump_velocity: float -300.0 var gravity: float 600.0 func _physics_process(delta): # 如果不在空中就逐渐加速下落 if not is_on_floor(): velocity.y gravity * delta # 读取左右输入 var direction : Input.get_axis(left, right) if direction ! 0: velocity.x direction * speed else: velocity.x move_toward(velocity.x, 0, speed) # 在地面时按下跳跃 if Input.is_action_just_pressed(jump) and is_on_floor(): velocity.y jump_velocity move_and_slide()这段代码有四个关键点。第一物理过程写在_physics_process而不是_process里因为物理帧是固定频率避免不同电脑帧率不同导致速度不一致。第二velocity.y gravity * delta模拟重力。玩家没在地面时加速下落。第三Input.get_axis(left, right)返回-1、0或1表示向左、不动、向右。第四move_and_slide()是实际执行移动和碰撞处理的方法。它会在有碰撞体时自动调整位置让角色沿着地面滑动。4.3 跳跃参数和手感优化jump_velocity是负数因为Godot里Y轴向下负值表示向上。不要直接照抄某个固定值应该根据你的瓦片尺寸和期望跳跃高度来调。我一般会这样估算如果希望跳到100像素高到达最高点用时0.2秒那么跳跃初速度大约就是-2 * 100 / 0.2 -1000。这个数值不一定完美但可以当作起点再根据手感微调。手感优化方面入门阶段可以先不深入但有一个点值得提前知道跳跃缓冲jump buffer玩家快落地时提前按跳跃落地瞬间自动起跳操作感更顺。跳跃裁剪jump cut跳跃中松开跳跃键角色下落更快操作更灵活。这两个功能其实不复杂但作为2小时实战先把基础跑通更重要。我每次做测试都会先问自己一个问题角色移动卡不卡跳跃跟不跟手。如果不跟手先确认是不是物理帧率不稳再考虑手感参数。5. 敌人AI巡逻、转向、检测玩家5.1 敌人节点与基础巡逻敌人的基础行为很简单向左走碰到墙壁掉头碰到悬崖掉头。用CharacterBody2D同样可以处理。节点结构CharacterBody2DSprite2DCollisionShape2DRayCast2D用于检测前方地面RayCast2D用于检测墙壁敌人脚本示例extends CharacterBody2D export var patrol_speed: float 50.0 var direction : 1.0 var gravity: float 600.0 func _physics_process(delta): if not is_on_floor(): velocity.y gravity * delta velocity.x direction * patrol_speed move_and_slide() if is_on_wall(): direction * -1这里用is_on_wall()检测角色是否碰到墙壁。碰到后把方向取反就实现了最简单的巡逻。5.2 用RayCast2D检测墙壁和悬崖如果敌人只会在开阔地巡逻is_on_wall()就够。但平台跳跃关卡有很多平台敌人可能走到边缘掉下去。这时需要RayCast2D。给敌人添加两个RayCast2D一个朝前方下方发射检测前方是否还有地面。一个朝前方发射检测是否撞墙。代码逻辑变成如果前方没有地面或者碰到墙壁就掉头。if is_on_wall() or not $FloorCheck.is_colliding(): direction * -1注意RayCast2D不是默认一直检测需要设置enabled为true。而且射线检测依赖物理帧有时需要在_physics_process里调用force_raycast_update()确保结果是最新的。5.3 加一个简单的追击逻辑追击不一定要用复杂状态机。最简单的方式当玩家进入一定范围敌人切换成追击状态提高移动速度。可以在敌人脚本里保留巡逻方向和追击方向两个逻辑var player get_node(../Player) if player and position.distance_to(player.position) 150: # 追击朝玩家方向移动速度提高 direction sign(player.position.x - position.x) velocity.x direction * chase_speed else: # 巡逻保持原方向 velocity.x direction * patrol_speedsign()返回正负号用来判断玩家在左边还是右边。这个方案够简单适合入门。不过要注意节点路径。如果玩家不是../Player这段代码会报错。更稳妥的做法是给玩家加一个Group比如叫player然后用get_tree().get_first_node_in_group(player)获取玩家节点。6. 把关卡串起来死亡、重生、信号和输出验证6.1 用Area2D做尖刺和死亡判定平台跳跃游戏里死亡来源一般是两种碰到敌人、碰到尖刺或掉落深渊。最简单的方式是使用Area2D作为伤害区域。在尖刺位置添加Area2D添加CollisionShape2D覆盖尖刺区域勾选Area2D的body_entered信号。当有物理体进入时触发信号。脚本里不直接操作而是用信号连接func _on_hazard_body_entered(body): if body.is_in_group(player): get_tree().reload_current_scene()给玩家添加Group是在场景树里选中Player节点在“Groups”里输入player并添加。这样避免把尖刺和敌人写死绑定到某个节点。为什么用reload_current_scene()因为这是最快重置状态的方法。玩家位置、敌人位置、道具状态全部恢复初始状态不用手动写一堆重置逻辑。缺点是如果游戏很大重新加载会花时间但作为小关卡完全够用。6.2 接上信号和关卡重启除了尖刺敌人也可以是伤害触发源。有两种做法敌人本身带Area2D子节点把Area2D作为伤害区域。在玩家碰撞敌人时通过is_on_floor()判断是否“踩中敌人”踩中就消灭敌人。第一种做法简单直接推荐入门阶段使用。敌人脚本里加上区域检测玩家进入就触发死亡。如果希望玩家踩到敌人头顶能消灭敌人可以改成判断玩家速度和位置。常见逻辑是玩家在下落时碰到敌人且玩家的Y轴速度方向是向下就判定“踩中”敌人消失玩家再跳一次。这个逻辑稍微复杂建议把基础死亡和重生跑通之后再扩展。6.3 调试和发布怎么判断项目是否正常项目写完不能只看“能打开”就算完。我会用一套固定顺序检查从出生点跑到终点确认角色移动和跳跃正常。故意跳进尖刺和深渊确认死亡和重生触发。观察敌人巡逻确认墙壁和悬崖检测生效。检查Output面板有没有红色报错。看帧率是否稳定。如果卡顿优先检查是否有循环创建节点或物理碰撞太多。如果出现角色无法移动先检查输入映射和脚本里的动作名。如果出现角色穿过地面先检查TileSet物理层。如果敌人不动先检查节点路径和RayCast2D的enabled属性。这些问题的排查顺序基本是先看输入配置再看节点结构再看物理碰撞层最后才考虑改参数。发布时选择“Project/Export”需要先配置导出模板。导出配置不多但要注意输入映射和路径不能有中文否则不同平台下容易出现资源加载问题。这样一个迷你平台跳跃关卡就串起来了。看起来简单实际已经把2D游戏开发里最常用的几个机制都过了一遍瓦片地图、物理移动、碰撞信号、敌人AI和场景重载。真正落地时最该盯住的不是功能列表而是输入映射、物理层和节点路径这几个容易被忽略的地方。先把单关卡跑稳再去加多关卡、多敌人和复杂攻击方式会更容易把控。
返回列表