geometry-tower-defense/docs/IconColorDesgin.md

4.6 KiB
Raw Blame History

使用的 5 个属性:

  • AttackDamage(MuzzleComp)
  • DamageRandomRate(MuzzleComp)
  • RotateSpeed(BearingComp)
  • AttackRange(BearingComp)
  • AttackSpeed(BaseComp)

下面我给你一套专门为这 5 个属性设计的稳定映射方案,目标是:

  • 不出现“未使用 RGB 位导致底色聚集”
  • 不出现颜色难以区分
  • 不随数值微调产生大跳变
  • 能一眼看出“偏伤害 / 偏射速 / 偏范围”等方向

一、先定颜色语义(非常关键)

我们先给每个属性一个语义色相Hue,并且颜色间隔拉开,避免混淆。

属性 含义倾向 Hue建议
AttackDamage 爆发/力量
DamageRandomRate 波动/暴击感 30°
RotateSpeed 灵活/机动 200°青蓝
AttackRange 空间/覆盖 120°绿
AttackSpeed 频率/连发 270°

解释:

  • 伤害 → 红(直觉最强)
  • 范围 → 绿(覆盖感)
  • 攻速 → 紫(科技感/高频)
  • 旋转 → 青蓝(灵活)
  • 随机伤害 → 橙(不稳定爆发)

Hue 间隔 > 60°视觉上足够区分。


二、不要直接映射到 RGB而是走 HSV

Step 1归一化

对每个属性:

x_i = clamp01((value_i - min_i) / (max_i - min_i))

⚠️ 不要用当前组件的 min/max要用全局平衡区间。


三、核心算法:主导属性 + 混合属性

1 找出前两名属性

i1 = argmax(x_i)
i2 = secondMax(x_i)

2 Hue 插值

w = x_i2 / (x_i1 + x_i2 + 0.0001f)
hue = lerp(Hue[i1], Hue[i2], w)

这能避免“单一属性颜色单调”的问题。

例如:

  • 高伤害 + 高攻速 → 红紫之间
  • 高范围 + 高旋转 → 绿青之间

四、饱和度Saturation

饱和度表达“专精度”。

purity = x_i1 - x_i2
sat = lerp(0.45f, 0.9f, clamp01(purity * 1.5f))
  • 越单一专精 → 越鲜艳
  • 属性均衡 → 稍微偏灰

这样“杂牌组件”会看起来更灰一点,专精流派更亮。


五、明度Value

明度表达“整体强度”。

intensity = (x1 + x2 + x3 + x4 + x5) / 5f
val = lerp(0.55f, 0.95f, intensity)

强度越高越亮。

⚠️ 不要让 val 太低,否则会看起来像“禁用状态”。


六、品质不要改 Hue

品质建议只影响:

  • 外描边颜色
  • 发光
  • 明度偏移
  • 图标底板

例如:

品质 处理方式
val × 0.9
绿 无变化
外发光
val ×1.05 + 外发光
双层发光 + 轻微高对比

不要把红品质直接改成红色,那会和 AttackDamage 冲突。


七、避免“颜色基地”的关键

你之前的问题是:

某些属性没有值 → RGB 位没用 → 颜色集中

用现在方案:

  • 即便某些属性接近 0Hue 仍由主导属性决定
  • 不会出现“默认黑色/灰色聚集”

另外建议:

sat = max(sat, 0.4f);
val = max(val, 0.6f);

避免太灰太暗。


八、额外增强:组件类型偏移

你有三类组件(枪口/轴承/底座),可以轻微加一个 hue 偏移:

  • 枪口:+0°
  • 轴承:+15°
  • 底座:-15°

这样即便数值类似,也能区分结构类型。


九、完整伪代码(你可以直接用)

Color GenerateColor(float[] normalizedStats, ComponentType type)
{
    float[] hueMap = { 0f, 30f, 200f, 120f, 270f };

    int i1 = MaxIndex(normalizedStats);
    int i2 = SecondMaxIndex(normalizedStats);

    float w = normalizedStats[i2] /
              (normalizedStats[i1] + normalizedStats[i2] + 0.0001f);

    float hue = Mathf.Lerp(hueMap[i1], hueMap[i2], w);

    float purity = normalizedStats[i1] - normalizedStats[i2];
    float sat = Mathf.Lerp(0.45f, 0.9f, Mathf.Clamp01(purity * 1.5f));

    float intensity = normalizedStats.Average();
    float val = Mathf.Lerp(0.55f, 0.95f, intensity);

    if (type == ComponentType.Axis) hue += 15f;
    if (type == ComponentType.Base) hue -= 15f;

    return Color.HSVToRGB(hue / 360f, sat, val);
}

十、视觉稳定性测试建议

做一个小测试场景:

  • 随机生成 200 个组件

  • 打印颜色到网格

  • 看是否:

    • 有大量颜色过于相似
    • 有大面积灰色
    • 是否能一眼区分“偏伤害”“偏范围”等

结论

你不应该:

把 5 个属性硬塞进 RGB 位

你应该:

用 Hue 表达方向 用 Saturation 表达专精 用 Value 表达强度 用外观表达品质