| name | godot-farming-system |
| description | Godot 4 种植系统设计,包含植物数据结构、生长阶段、浇水机制、TileMap应用。 |
Godot 种植系统设计
概述
种植系统采用事件驱动架构,通过全局信号实现地图逻辑与游戏逻辑的解耦,支持多种植物的种植、浇水和生长阶段管理。
1. 架构设计
1.1 分层架构
┌─────────────────────────────────────────┐
│ UI 层 (FarmUI) │
│ - 工具选择、植物种子选择 │
├─────────────────────────────────────────┤
│ 状态机层 (StateMachine) │
│ - 玩家状态切换、工具使用状态 │
├─────────────────────────────────────────┤
│ 逻辑层 (GlobalPlants) │
│ - 植物数据管理、浇水状态、生命周期 │
├─────────────────────────────────────────┤
│ 地图层 (TileMap) │
│ - GroundMap / EarthMap / PlantsMap │
└─────────────────────────────────────────┘
1.2 核心信号
# globals/global_plants.gd
signal dig_earth(pos: Vector2) # 挖掘土地信号
signal plant_plant(pos: Vector2) # 种植植物信号
signal water_earth(pos: Vector2) # 浇水土地信号
signal update_earth_map_tiles # 更新泥土贴图信号
signal update_plants_map_life # 更新植物生命周期信号
2. 数据层设计
2.1 植物数据结构
var plants = [
{
"name": "玉米",
"source_id": 0,
"life": [
{
"coord": Vector2i(0, 1),
"require_time": 1
},
{
"coord": Vector2i(1, 1),
"require_time": 1
},
]
},
]
| 字段 | 类型 | 说明 |
|---|
name | String | 植物名称 |
source_id | int | 瓦片源ID |
life | Array | 生长阶段数组 |
coord | Vector2i | 精灵图坐标 |
require_time | int | 该阶段所需时间(秒) |
2.2 浇水状态管理
var watered_pos: Array[Vector2i] = []
func on_water_earth(pos: Vector2):
var water_pos = earth_map.local_to_map(ground_map.to_local(pos))
if not GlobalPlants.watered_pos.has(water_pos):
GlobalPlants.watered_pos.append(water_pos)
GlobalPlants.update_earth_map_tiles.emit()
3. 地图层设计
3.1 三层 TileMap 结构
PlantMap (场景)
├── GroundMap # 草地层(可挖掘的草地)
├── EarthMap # 泥土层(挖掘后的土地)
└── PlantsMap # 植物层(生长的植物)
3.2 植物地图逻辑
func on_dig_earth(pos: Vector2):
var dig_pos = ground_map.local_to_map(ground_map.to_local(pos))
var ground_tile_data = ground_map.get_cell_tile_data(GroundGrassLayer, dig_pos)
if ground_tile_data == null:
return
var can_dig = ground_tile_data.get_custom_data("can_dig")
if !can_dig:
return
var earth_tile_data = earth_map.get_cell_tile_data(EarthDirtLayer, dig_pos)
if earth_tile_data != null:
return
earth_map.set_cells_terrain_connect(EarthDirtLayer, [dig_pos], 0, 0)
func on_plant_plant(pos: Vector2):
var plant_pos = earth_map.local_to_map(ground_map.to_local(pos))
var earth_tile_data = earth_map.get_cell_tile_data(EarthDirtLayer, plant_pos)
var plant_tile_data = plants_map.get_cell_tile_data(PlantsLayer, plant_pos)
if earth_tile_data == null or plant_tile_data != null:
return
var plant = GlobalPlants.plants[GlobalPlants.current_plant]
plants_map.set_cell(PlantsLayer, plant_pos, plant.source_id, plant.life[0].coord)
plant_tile_data = plants_map.get_cell_tile_data(PlantsLayer, plant_pos)
plant_tile_data.set_custom_data("plant", GlobalPlants.current_plant)
plant_tile_data.set_custom_data("life", 0)
plant_tile_data.set_custom_data("require_time", plant.life[0]["require_time"])
4. 生长系统设计
4.1 植物生命周期更新
func on_update_plants_map_life():
var used_rect = get_used_rect()
for x in used_rect.size.x:
for y in used_rect.size.y:
var coord = Vector2i(x + used_rect.position.x, y + used_rect.position.y)
if not GlobalPlants.watered_pos.has(coord):
continue
var tile_data = get_cell_tile_data(PlantLayer, coord)
if tile_data == null:
continue
var plant_id = tile_data.get_custom_data("plant")
var life = tile_data.get_custom_data("life")
var require_time = tile_data.get_custom_data("require_time")
require_time -= 1
if require_time > 0:
tile_data.set_custom_data("require_time", require_time)
continue
var plant = GlobalPlants.plants[plant_id]
var plant_life = plant.life as Array
life += 1
if life < plant_life.size():
var next_life = plant_life[life]
set_cell(PlantLayer, coord, plant.source_id, next_life.coord)
tile_data = get_cell_tile_data(PlantLayer, coord)
tile_data.set_custom_data("require_time", next_life.require_time)
tile_data.set_custom_data("life", life)
tile_data.set_custom_data("plant", plant_id)
4.2 定时器循环
func plant_loop():
await get_tree().create_timer(1).timeout
update_plants_map_life.emit()
plant_loop()
5. 泥土视觉效果
func _tile_data_runtime_update(_layer: int, coords: Vector2i, tile_data: TileData) -> void:
if GlobalPlants.watered_pos.has(coords):
tile_data.modulate = Color(.73, .58, .48, 1.0)
else:
tile_data.modulate = Color.WHITE
6. TileSet 自定义数据配置
| 自定义数据 | 所属层 | 说明 |
|---|
can_dig | GroundMap | 草地是否可挖掘 |
plant | PlantsMap | 植物类型ID |
life | PlantsMap | 当前生长阶段 |
require_time | PlantsMap | 距离下一阶段所需时间 |
7. 种植流程图
┌─────────────┐ E键 ┌──────────────┐
│ Idle │ ──────────> │ UseTool │
└─────────────┘ └──────┬───────┘
│
┌──────────────┴──────────────┐
│ GlobalTool.current_tool │
└──────────────┬──────────────┘
┌─────────────────┬──────┴───────┬─────────────────┐
"hoe" 挖掘 "kettle" 浇水 "seed" 种植 "axe" 劈砍
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐
│ dig_earth.emit │ │ water_earth.emit│ │ plant_plant.emit │
└────────┬────────┘ └────────┬────────┘ └──────────┬──────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐
│ 草地 → 泥土 │ │ 记录浇水位置 │ │ 泥土 → 植物 │
└─────────────────┘ └─────────────────┘ └─────────────────────┘