Skip to content

玄学放置 · 像素图标体系

起因

第一版用 emoji 当学科图标(📖 📐 ⚖️ 等等),看起来太"应付"了,跟暗色科技风的整体调子完全不搭。游戏化产品的图标如果没有自己的视觉语言,整个画面就会松散。

决定换成 16×16 的像素艺术。这个尺寸是经过取舍的:太小(8×8)画不下细节,太大(32×32)开发成本指数级上升。16×16 是经典像素风格的"甜区",能塞下足够辨识度的元素,又不会让每个图标的字符画变成一项工程。

渲染方式:SVG 而不是 PNG

放置游戏里图标会出现在多种尺寸场景:侧栏 22px、学科面板 44px、装备槽 30px、人物剪影 120px。如果用 PNG,要么准备多套尺寸切图、要么放大失真,前者维护成本高,后者直接糊掉。

最终选了<rect> 渲染像素艺术

vue
<svg viewBox="0 0 16 16" :width="size" :height="size"
     shape-rendering="crispEdges">
  <rect v-for="(p, i) in pixels" :key="i"
        :x="p.x" :y="p.y" width="1" height="1" :fill="p.color" />
</svg>

关键点是 shape-rendering="crispEdges" 这个属性,它告诉浏览器渲染时不要做反锯齿,保证像素块边缘永远锐利。配合 viewBox 始终保持 16×16,在任何尺寸下放大都不会糊。

数据驱动:字符画 + 调色板

图标本体用字符画存储,每张 16 行字符串:

js
math: {
  palette: { 1: '#5eead4', 2: '#0d9488', 3: '#134e4a' },
  art: [
    '................',
    '..1111111111111.',
    '..2222222222222.',
    '......11....11..',
    '......11....11..',
    // ...
  ]
}

. 表示透明像素,其他字符通过 palette 映射颜色。这种格式有几个好处:

  • 所见即所得:字符画在编辑器里直接能看出大致形状,调整时不用反复跑预览
  • 数据短小:每张图 16×16=256 字符 + 一个调色板对象,远小于 PNG
  • 可批量处理:用脚本扫描 ICONS 字典就能批量做导出、变体、过滤等操作

每个图标 3-5 色独立调色板,避免全局色板膨胀,也方便每个图标走自己的色彩主题。

PixelIcon 组件

parseIcon(name) 把字符画转换成 {x, y, color} 数组,组件渲染时遍历输出 <rect>

vue
<PixelIcon name="math" :size="32" glow glow-color="#5eead4" />

新增了一个 glow 选项:选中态自动加 drop-shadow 外发光,颜色用学科主题色。这是放置游戏画面的常见手法——选中即发光,提示状态变化。

八大学科的视觉语言

每个学科都选了一个最具代表性的元素,并给它一个独有的色板:

学科主题元素色板
语言翻开的古籍 + 朱红封边米黄 / 朱红 / 暗红
数学π 符号青亮 / 青深
政治天平金色系
历史卷轴 + 文字纹米纸 / 墨字 / 卷边
地理地球 + 海陆分布海蓝 / 陆绿 / 深边
物理原子 + 双轨道 + 金核蓝弧 / 金核
化学锥形烧瓶 + 紫液 + 气泡紫液 / 气泡黄
生物叶脉浅绿 / 中绿 / 深绿

设计时刻意避免直接复制 emoji 的具象表达。比如「政治」用天平而不是 ⚖️ 的具体细节,「化学」用一个简化的锥形瓶轮廓配紫色液体而不是真实试管的复杂结构——16×16 的像素必须舍弃细节、抓住一眼可辨的剪影。

玄学:神秘感的设计

「玄学」作为隐藏学科(项目代号 metaphysics 的彩蛋),需要传达"看不见但存在"的神秘感。我用了三个元素叠加:

  • 水晶球:球体由金色辉光(#fbbf24)外圈包裹亮紫(#ddd6fe)内核
  • 全知之眼:球心嵌一只眼,瞳孔用亮金 #fef9c3,营造窥视感
  • 紫黑底座:深紫 #1e1b4b 与紫光主体形成层次
.......2........
......242.......
.....22422......
....2244422.....
...224111422....
..22411115422...
..24111515142...   ← 中央是眼睛
..24115525142...
..24111515142...
..22411115422...
...224111422....
....2244422.....
.....33333......
....3333333.....

任务列表也强化彩蛋向:「夜观天象」「抽一张塔罗」「冥想悟道」(最后一个是单次最高收益,呼应"玄学回报最高"的梗)。

集成到业务

替换 emoji 的代价比想象中小:

diff
- <span>{{ subject.icon }}</span>
+ <PixelIcon :name="subject.iconKey" :size="22"
+            :glow="isSelected" :glow-color="subject.color" />

mock 数据里 icon: '📐' 改成 iconKey: 'math',业务字段从"图标字面值"变成"图标资源 key"。这一改让后续扩展(变体、动画、特效)有了空间——以后做"罕见装备闪光特效"时,只需要在 PixelIcon 里加一种新的 effect 就行,业务层的 iconKey 不用动。

后续扩展点

像素艺术架构搭完之后,复用面会越来越宽:

  • 装备图标(铅笔、橡皮、画笔、校服等)用同一套架构,新加一个 entry 就行
  • 人物剪影也可以用 16×16(虽然小,但放大到 120px 已经足够辨识)
  • favicon 直接复用「玄学」图标的字符画数据,无需额外作图
  • 后续可写一个导出脚本,把所有图标批量产出 SVG 文件作为素材包

这套"字符画 + 调色板 + 单一组件渲染"的小架构,是这个项目里最划算的一次抽象——前期一次投入,后面几乎所有视觉资产都能受益。

总结

像素图标看似只是视觉问题,但在游戏化产品里它会决定整体画面的"专业感"。这次的关键设计:

  • 用 SVG 渲染而不是 PNG,解决多尺寸场景的清晰度问题
  • 字符画 + 调色板作为底层数据结构,比直接画 SVG 更易编辑
  • 业务层只引用 key,把图标实现细节封死在 PixelIcon 内
  • 统一架构容纳所有图标类型(学科、装备、道具、人物)

下一篇会聊装备物品系统的搭建,以及一个比较关键的设计转向:把任务从"每个学科同时挂机"改为"全局只能挂机一个"。