跳到主要内容

基于网格的移动系统

MCE 使用构建在 Unity Tilemap 之上的基于图块的网格移动系统。玩家和 NPC 在离散的网格上一次移动一个图块,碰撞检测、地形效果和跨地图过渡都由网格系统处理。

一步是如何被解析的

实际运行中的网格

玩家始终恰好位于一个图块上。没有半步,也没有图块内的位置, 正因为如此,遭遇、碰撞和跨地图过渡才是可判定的,而不是 近似的。

核心组件​

GridController​

GridController 是每个场景的图块网格管理器。它与 Unity 的 Grid 位于同一个 GameObject 上(它需要一个 Grid),并且:

  • 找到场景的 Tilemap,并跨它们回答图块查询,从排序顺序最高的到最低的。
  • 从项目的 TileData 资产读取每个图块的移动类型(参见自定义图块类型)。
  • 跟踪注册在网格上的角色和演员。
  • 保存场景的 SceneInfo(见下文)。
  • 回答碰撞查询:角色能否移动到这个图块,能否从这个图块出发?

每个地图场景在其网格根节点上有一个 GridController。

MCECharacterController​

MCECharacterController 处理网格上任意角色(玩家、NPC 或怪物)的移动:

  • 对齐网格的移动:角色每一步恰好移动一个图块。
  • 四方向移动:上、下、左、右。没有斜向移动。
  • 精灵渲染:更新精灵朝向和行走动画。
  • 碰撞检查:每次移动之前查询 GridController。
  • 移动速度:Speed,单位为秒每图块(默认 0.25)。

PlayerCharacter​

PlayerCharacter 在控制器之上添加玩家专属功能:

  • 输入处理(键盘和手柄)。
  • 交互触发(面对 NPC/对象时按下动作键)。
  • 野生遭遇处理、驱虫步数和步数计数器(GlobalGameData.StepsTaken,它同时驱动孵蛋周期和亲密度)。
  • 奔跑、骑行和游泳。
  • 跟随怪物的协调以及表情快捷键。

GlobalGridManager​

GlobalGridManager 处理跨地图导航:

  • 保存已加载网格的列表,并找到在某个世界位置有图块的网格,使角色能从一张地图走进相邻的地图。
  • 以叠加方式加载当前地图的邻居,以及这些邻居的邻居(两跳深度),因此穿过中间的地图不会卸载你来的那张。
  • 当角色从一个网格跨到另一个网格时,移交玩家。

图块类型​

每个图块资产都有一个移动类型(TileType),在 TileData 资产中分配:

TileType说明
NonExistent图块没有数据;视为虚空
Walkable普通地面
NonWalkable实心障碍物(墙壁、树木、岩石)
Jumpable断崖:通过朝一个方向跳跃越过
Bridge桥面,层叠在其下方内容之上
BridgeEntrance地面与桥之间的过渡图块
Water需要游泳才能渡过的水
Waterfall可以攀爬的垂直水流
Slippery冰面:角色会一直滑行,直到撞上障碍物
WalkableNotBikable步行可通过,但自行车不行

在类型之上,图块行为(图块预制体上的组件)添加逻辑:EncounterTile 标记野生遭遇区域,OneWayJumpableTile 设置断崖方向,ForceCharacterToKeepMoving 制作传送带和洋流,还有 TallGrass、LadderUp、WaterfallEdge、WhirlwindInDirection 等。它们都在自定义图块类型中有说明。

设置地图​

步骤 1:创建 Tilemap 结构​

MCE 地图使用标准的 Unity Tilemap 层级:

Grid (Grid + GridController)
└── Ground (Tilemap, TilemapRenderer, sorting order 0)
└── GroundOverlay (Tilemap, TilemapRenderer, sorting order 1)
└── Above ... (more Tilemaps as needed)
└── Actors (NPC GameObjects)

没有需要单独绘制的碰撞瓦片地图:阻止移动的是你所绘制图块的 TileType。

步骤 2:绘制地图​

使用地图编辑器覆盖层,或 Unity 的 Tile Palette(Window > 2D > Tile Palette)来绘制你的地图:

  1. Ground 图层:基础地形(道路、草地、泥土、水边)。
  2. 覆盖图层:地面之上的装饰(花、岩石、阴影)以及绘制在玩家之上的内容(树冠)。
  3. 遭遇图块:预制体带有 EncounterTile、野生怪物出现的图块。

步骤 3:添加 GridController​

  1. 选择 Grid 根 GameObject。
  2. 添加 GridController 组件。
  3. 控制器通过依赖注入接收项目的 TileData 资产;请确保你绘制的每个图块都已在其中以正确的 TileType 注册(资产上的 Populate 和 CheckInvalid 按钮可以帮上忙)。未注册的图块被视为可行走并记录一条警告。

步骤 4:配置 SceneInfo​

每个地图场景都需要一个指向 SceneInfoAsset 的 SceneInfo 组件(通过 Hub 的 Database 选项卡中的 New Scene Info 创建)。把该组件分配给 GridController 的 Scene Info 字段。该资产包含:

字段说明
Scene此信息所描述的场景
Localizable Name Key地点的显示名称(显示在页眉中)
Neighbours / Neighbour Offsets与此地图相连的地图及其位置,以图块为单位(无缝跨越)
Background Music此地图的音乐
Is Affected By Sky、Default Weather、Allowed Weathers昼夜光照与天气
Can Open Storage Here、Can Fly From Here、Can Teleport From Here、Can Escape Rope From Here、Can Fish Here玩家在此处可以做什么
Is Dungeon、Is Dark地下城地图在每个图块上使用 Cave 遭遇
Region、Tags地区以及游戏逻辑使用的场景标签(例如 “Cave”、“Town”、“Route”)
Encounters、Battle Scenarios Per Encounter、Own Encounter Chances地图的野生遭遇:参见野生遭遇

特殊地形​

桥​

桥让角色可以走过原本无法通行的图块(比如水):

  1. 为桥使用排序顺序更高的瓦片地图图层。
  2. 给桥的图块设置 Bridge 类型,给踏上桥的图块设置 BridgeEntrance。
  3. 角色踏上桥时会在桥的图层上行走。

桥的逻辑处理 Z 排序 —— 角色渲染在水之上,但在桥的栏杆之下(OverBridgeBodySortOrder)。

湿滑图块(冰面)​

在冰面图块上,角色会沿着移动方向滑行,直到撞上墙壁或非冰面图块:

  1. 给冰面图块设置 Slippery 类型。
  2. MCECharacterController 会覆盖输入并继续沿原移动方向前进。
  3. 添加墙壁或障碍物来创建冰面谜题布局。

断崖​

断崖是单向图块 —— 角色可以向下跳,但不能爬回去:

  1. 给图块设置 Jumpable 类型,并在其预制体上添加 OneWayJumpableTile 行为。
  2. 设置它的 Jump Direction。
  3. 角色越过断崖时会播放跳跃动画。

瀑布​

瀑布可以借助相应的能力攀爬:

  1. 给瀑布图块设置 Waterfall 类型(边缘可以使用 WaterfallEdge)。
  2. 当玩家面向瀑布并使用攀爬能力时,角色会上升。

跨地图过渡​

无缝连接​

对于直接相连的地图(一号道路在北边缘延伸到二号道路),在每张地图的 Neighbours 中列出另一张,并用以图块为单位的 Neighbour Offsets 来确定其位置。GlobalGridManager 以叠加方式加载邻居,角色只需从一个网格走进另一个网格:当当前网格在目标位置没有图块时,管理器会寻找一个有该图块的已加载网格。邻居的图块如果是墙壁(NonWalkable)或虚空(NonExistent),仍会阻止这一步。

传送点(门、洞穴、传送)​

要把玩家移到另一个地方:

  1. 在门或入口图块上放置一个 TriggerActor(TriggerActor 不阻挡移动,并在玩家踏入时运行图)。
  2. 在其 CommandGraph 中添加一个 TeleportPlayer 节点,把目的地设为场景位置(目标 SceneInfoAsset 和图块)。在线时,服务器会先验证传送。
  3. 可选地在其周围添加 OpenDoor、FadeScreenToBlack 和声音来装饰过渡。

导入的地图由导入器的场景集成为你放置传送点。

玩家移动配置​

移动速度是角色的 Speed 字段,单位为秒每图块(默认 0.25,即每秒四个图块)。角色的状态会缩放每图块的时间:

状态每图块时间的倍率
行走1
奔跑(IsRunning)0.33
骑行(IsBiking)0.15
游泳(IsSwimming)0.66
跳跃跳跃以一步时间的 1.5 倍播放

步数计数器(GlobalGameData.StepsTaken)随每一步递增,并驱动孵蛋周期和亲密度跳动。

怪物跟随者​

MCE 支持跟随者系统,玩家队伍中的第一只怪物会在世界中走在他身后:

  • MonsterFollowerController 管理跟随者的位置和精灵。
  • 跟随者保持在玩家身后一个图块,并在过场动画之后追上来。
  • 跟随者精灵按物种和形态在 MonsterEntry 中配置(WorldIdleSprite* 和 WorldWalkingSprite* 字段)。
  • 玩家可以与跟随者互动(面向它并按下动作键)来查看反应;导入的游戏可以带来自己的对话表,跟随者还可以显示情绪气泡。
跟随者精灵

如果某个怪物物种没有分配世界用的跟随者精灵,跟随者就不会出现。请手动将其创建为四方向行走循环图集。

最佳实践​

  1. 保持图块类型一致。在 TileData 中注册每个绘制的图块,并对同一种地形使用相同的类型。
  2. 双向测试传送连接。确保你能从 A 到 B,也能从 B 回到 A。
  3. 使用场景标签来处理逻辑。不要硬编码地图名称,而是将地图标记为 “Cave”、“Water”、“Forest” 等。
  4. 优化大型地图。非常大的瓦片地图会影响性能。考虑用 Neighbours 将其拆分为多个相连的场景。
  5. 用手柄测试。网格移动在键盘和手柄上都应该感觉灵敏。