---
name: godot-farming-system
description: Godot 4 种植系统设计，包含植物数据结构、生长阶段、浇水机制、TileMap应用。
---

# Godot 种植系统设计

## 概述

种植系统采用事件驱动架构，通过全局信号实现地图逻辑与游戏逻辑的解耦，支持多种植物的种植、浇水和生长阶段管理。

## 1. 架构设计

### 1.1 分层架构

```
┌─────────────────────────────────────────┐
│         UI 层 (FarmUI)                   │
│  - 工具选择、植物种子选择                 │
├─────────────────────────────────────────┤
│         状态机层 (StateMachine)           │
│  - 玩家状态切换、工具使用状态             │
├─────────────────────────────────────────┤
│         逻辑层 (GlobalPlants)             │
│  - 植物数据管理、浇水状态、生命周期        │
├─────────────────────────────────────────┤
│         地图层 (TileMap)                  │
│  - GroundMap / EarthMap / PlantsMap      │
└─────────────────────────────────────────┘
```

### 1.2 核心信号

```gdscript
# 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 植物数据结构

```gdscript
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 浇水状态管理

```gdscript
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 植物地图逻辑

```gdscript
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 植物生命周期更新

```gdscript
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 定时器循环

```gdscript
func plant_loop():
    await get_tree().create_timer(1).timeout
    update_plants_map_life.emit()
    plant_loop()
```

## 5. 泥土视觉效果

```gdscript
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    │
└────────┬────────┘ └────────┬────────┘ └──────────┬──────────┘
         │                  │                      │
         ▼                  ▼                      ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐
│ 草地 → 泥土     │ │ 记录浇水位置    │ │ 泥土 → 植物         │
└─────────────────┘ └─────────────────┘ └─────────────────────┘
```
