项目火星番茄农场系统

农场系统

作物从一颗种子长成可收获植株的全过程 —— 分节生长、病害可视化、成熟判定。

进行中C++蓝图

要解决的问题

种田系统最难的不是「长出来」,而是让它长得像活的:

  • 一根茎要从幼苗慢慢抽长,而不是几帧之间突然变大
  • 叶子要随机、要不对称,否则一排种下去像复制粘贴
  • 缺水、缺肥、生病的状态要看得见,玩家不用点开面板才知道
  • 成熟了要能被收获,收获要真的产出东西

数据结构

作物的定义放在 DT_Farmables 里,每行对应一种可种植植物:

USTRUCT(BlueprintType)
struct FPlantData : public FTableRowBase
{
    GENERATED_BODY()

    /** 显示名 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    FText DisplayName;

    /** 从播种到成熟需要经过的生长阶段数 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    int32 GrowthStages = 4;

    /** 每个阶段需要的水分累积量 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    TArray<float> StageWaterCost;

    /** 成熟后产出的物品与数量 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    TMap<FName, int32> HarvestYield;

    /** 病害抗性 0~1,越高越不容易生病 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    float DiseaseResistance = 0.5f;
};

用 DataTable 而不是散落的蓝图变量,是因为配方会一直改 —— 到最后一定会出现「策划想加第 12 种作物」这种事,那时候你希望它只是往表里加一行。

分节生长

植株不是一整个模型缩放的,而是按节拼出来的:

  • BP_PlantStem_Segment —— 单节茎段,负责自己的长度插值与叶序偏移
  • BP_Farming_Master —— 按 GrowthStages 生成对应数量的节,逐节驱动生长

每一节记录自己是第几节,据此计算:

  • 长度缩放(越往上越短,符合真实作物比例)
  • 叶片的旋转与相位偏移(用节序号做伪随机种子,保证每次生成结果一致)
  • 生长插值曲线(缓入缓出,避免匀速的机械感)

这样一根茎的形态是算出来的而不是摆出来的,改一个参数整片田的观感都会变。

病害可视化

病害不是弹个 UI 图标,而是直接长在叶子上 —— 用材质表现:

状态 表现
缺水 叶片向叶脉收拢、颜色向灰绿偏移
缺肥 叶缘泛黄,从外圈向内扩散
真菌感染 随机斑块,斑块随时间扩大并互相吞噬

M_FoliageDiseaseVisualEffect 接收一个病害强度标量,内部混合三种表现。 好处是不需要在蓝图层写一堆分支 —— 浇水、施肥、喷药都只是改这个标量。

目前的进展

  • FPlantData 结构 + DT_Farmables 表
  • 分节生长逻辑,幼苗到成熟四阶段
  • 病害材质与三种病理表现
  • 病害传播(相邻植株互相感染)
  • 收获产出与背包对接