758 lines
31 KiB
Lua
758 lines
31 KiB
Lua
-- 《崩坏童话:蜜糖村》全部像素素材生成脚本(Aseprite Lua)
|
||
-- 运行:aseprite -b --script tools/gen_art.lua
|
||
-- 输出:public/assets/*.png + art/*.aseprite(源文件)
|
||
-- 全部素材为本脚本逐像素绘制的原创内容,无任何外部素材。
|
||
|
||
local pc = app.pixelColor
|
||
local function C(hex, a)
|
||
a = a or 255
|
||
local r = tonumber(hex:sub(1, 2), 16)
|
||
local g = tonumber(hex:sub(3, 4), 16)
|
||
local b = tonumber(hex:sub(5, 6), 16)
|
||
return pc.rgba(r, g, b, a)
|
||
end
|
||
|
||
-- ============ 糖果色板(村庄)+ 灰白色板(白色层) ============
|
||
local PAL = {
|
||
outline = C("5a4232"),
|
||
black = C("2a2420"),
|
||
white = C("ffffff"),
|
||
-- 草地/植物
|
||
grass = C("8fd05a"), grassD = C("79b94a"), grassL = C("a5e070"),
|
||
leaf = C("5da53f"), leafD = C("4a8a32"), trunk = C("8a5a34"), trunkD = C("6e4526"),
|
||
-- 路面/石
|
||
path = C("e8d5a8"), pathD = C("cbb488"), stone = C("c8c0a8"), stoneD = C("a8a088"),
|
||
-- 水
|
||
water = C("7ec8e8"), waterD = C("5fb0d8"), waterL = C("b8e6f8"),
|
||
-- 花
|
||
pink = C("ff9ecb"), red = C("e05858"), yellow = C("ffd94a"), berry = C("e8497a"),
|
||
-- 建筑
|
||
wall = C("fff1d0"), wallD = C("e8d8b0"), roof = C("f4924a"), roofD = C("d97733"),
|
||
wood = C("c98a4b"), woodD = C("a86a34"), woodL = C("e0aa6a"),
|
||
-- 室内
|
||
floor = C("e6c896"), floorD = C("d4b47e"), clinic = C("eaf2ec"), clinicD = C("d0e0d6"),
|
||
inwall = C("f6e8c8"), inwallD = C("e0cca0"),
|
||
-- 灰白层
|
||
wgray = C("e8e8ea"), wgrayD = C("cfcfd4"), wgrayDD = C("aeaeb6"), wdark = C("8a8a92"),
|
||
-- 其他
|
||
fog = C("e8ecf0"), fogD = C("cdd6de"),
|
||
metal = C("9aa4ac"), blue = C("5a88c8"), sky = C("8ecae6"),
|
||
}
|
||
|
||
-- ============ 绘制助手 ============
|
||
local function makeCtx(img, ox, oy)
|
||
local ctx = {}
|
||
function ctx.px(x, y, c) img:putPixel(ox + x, oy + y, c) end
|
||
function ctx.rect(x, y, w, h, c)
|
||
for j = y, y + h - 1 do for i = x, x + w - 1 do img:putPixel(ox + i, oy + j, c) end end
|
||
end
|
||
function ctx.hline(x, y, w, c) ctx.rect(x, y, w, 1, c) end
|
||
function ctx.vline(x, y, h, c) ctx.rect(x, y, 1, h, c) end
|
||
function ctx.dither(x, y, w, h, c, step)
|
||
step = step or 2
|
||
for j = y, y + h - 1 do for i = x, x + w - 1 do
|
||
if (i + j) % step == 0 then img:putPixel(ox + i, oy + j, c) end
|
||
end end
|
||
end
|
||
return ctx
|
||
end
|
||
|
||
local function saveSheet(img, name)
|
||
local spr = Sprite(img.width, img.height, ColorMode.RGB)
|
||
spr.cels[1].image = img
|
||
spr:saveAs("art/" .. name .. ".aseprite")
|
||
spr:saveCopyAs("public/assets/" .. name .. ".png")
|
||
spr:close()
|
||
end
|
||
|
||
-- ============ 瓦片集:10 列 × 8 行 = 80 瓦(16×16) ============
|
||
local T = {}
|
||
|
||
T[0] = function(c) -- 草地1
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.px(3, 4, PAL.grassL); c.px(11, 9, PAL.grassL); c.px(6, 13, PAL.grassD); c.px(13, 2, PAL.grassD)
|
||
end
|
||
T[1] = function(c) -- 草地2(草茎)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.px(4, 5, PAL.grassD); c.px(4, 4, PAL.grassD); c.px(10, 10, PAL.grassD); c.px(10, 9, PAL.grassD)
|
||
c.px(13, 5, PAL.grassL); c.px(2, 12, PAL.grassL)
|
||
end
|
||
T[2] = function(c) -- 草地+白花
|
||
T[0](c); c.px(5, 6, PAL.white); c.px(4, 5, PAL.white); c.px(6, 5, PAL.white); c.px(5, 4, PAL.white); c.px(5, 5, PAL.yellow)
|
||
c.px(12, 12, PAL.white)
|
||
end
|
||
T[3] = function(c) -- 草地+粉花
|
||
T[1](c); c.px(11, 4, PAL.pink); c.px(10, 3, PAL.pink); c.px(12, 3, PAL.pink); c.px(11, 2, PAL.pink); c.px(11, 3, PAL.yellow)
|
||
c.px(3, 10, PAL.pink)
|
||
end
|
||
T[4] = function(c) -- 石板路
|
||
c.rect(0, 0, 16, 16, PAL.path)
|
||
c.hline(0, 7, 16, PAL.pathD); c.vline(7, 0, 8, PAL.pathD); c.vline(3, 8, 8, PAL.pathD); c.vline(12, 8, 8, PAL.pathD)
|
||
c.px(2, 3, PAL.pathD); c.px(10, 12, PAL.pathD)
|
||
end
|
||
T[5] = function(c) -- 石板路2
|
||
c.rect(0, 0, 16, 16, PAL.path)
|
||
c.hline(0, 3, 16, PAL.pathD); c.hline(0, 11, 16, PAL.pathD); c.vline(5, 4, 7, PAL.pathD); c.vline(11, 12, 4, PAL.pathD); c.vline(11, 0, 3, PAL.pathD)
|
||
end
|
||
T[6] = function(c) -- 路缘(草→路)
|
||
c.rect(0, 0, 16, 8, PAL.grass); c.rect(0, 8, 16, 8, PAL.path)
|
||
c.hline(0, 7, 16, PAL.grassD); c.hline(0, 8, 16, PAL.pathD)
|
||
c.px(3, 6, PAL.grassL); c.px(11, 12, PAL.pathD)
|
||
end
|
||
T[7] = function(c) -- 湖水1
|
||
c.rect(0, 0, 16, 16, PAL.water)
|
||
c.hline(2, 4, 4, PAL.waterL); c.hline(9, 10, 4, PAL.waterL); c.hline(5, 13, 3, PAL.waterD)
|
||
end
|
||
T[8] = function(c) -- 湖水2
|
||
c.rect(0, 0, 16, 16, PAL.water)
|
||
c.hline(8, 3, 4, PAL.waterD); c.hline(1, 9, 4, PAL.waterL); c.hline(11, 14, 3, PAL.waterL)
|
||
end
|
||
T[9] = function(c) -- 岸边(上草下水)
|
||
c.rect(0, 0, 16, 6, PAL.grass); c.rect(0, 6, 16, 10, PAL.water)
|
||
c.hline(0, 5, 16, PAL.grassD); c.hline(0, 6, 16, PAL.waterL)
|
||
end
|
||
T[10] = function(c) -- 花丛
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(1, 2, 14, 12, PAL.leaf)
|
||
c.px(1, 2, PAL.grass); c.px(14, 2, PAL.grass); c.px(1, 13, PAL.grass); c.px(14, 13, PAL.grass)
|
||
c.px(4, 5, PAL.pink); c.px(8, 4, PAL.yellow); c.px(12, 6, PAL.white); c.px(3, 9, PAL.yellow)
|
||
c.px(7, 8, PAL.pink); c.px(11, 10, PAL.pink); c.px(5, 12, PAL.white); c.px(10, 12, PAL.yellow)
|
||
end
|
||
T[11] = function(c) -- 莓果丛(有果)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 3, 12, 11, PAL.leaf); c.rect(3, 2, 10, 13, PAL.leaf)
|
||
c.dither(3, 3, 10, 10, PAL.leafD, 3)
|
||
c.px(5, 5, PAL.berry); c.px(10, 4, PAL.berry); c.px(7, 8, PAL.berry); c.px(11, 9, PAL.berry); c.px(4, 10, PAL.berry)
|
||
end
|
||
T[12] = function(c) -- 莓果丛(已采)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 3, 12, 11, PAL.leaf); c.rect(3, 2, 10, 13, PAL.leaf)
|
||
c.dither(3, 3, 10, 10, PAL.leafD, 3)
|
||
end
|
||
T[13] = function(c) -- 树·左上
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(4, 2, 12, 14, PAL.leaf)
|
||
c.px(4, 2, PAL.grass); c.px(5, 2, PAL.grass); c.px(4, 3, PAL.grass)
|
||
c.dither(5, 4, 11, 12, PAL.leafD, 4); c.px(8, 5, PAL.grassL); c.px(12, 8, PAL.grassL)
|
||
end
|
||
T[14] = function(c) -- 树·右上
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(0, 2, 12, 14, PAL.leaf)
|
||
c.px(11, 2, PAL.grass); c.px(10, 2, PAL.grass); c.px(11, 3, PAL.grass)
|
||
c.dither(0, 4, 11, 12, PAL.leafD, 4); c.px(4, 6, PAL.grassL)
|
||
end
|
||
T[15] = function(c) -- 树·左下
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(4, 0, 12, 6, PAL.leaf); c.dither(4, 0, 12, 6, PAL.leafD, 4)
|
||
c.px(4, 5, PAL.grass)
|
||
c.rect(10, 6, 6, 10, PAL.trunk); c.vline(10, 6, 10, PAL.trunkD)
|
||
end
|
||
T[16] = function(c) -- 树·右下
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(0, 0, 12, 6, PAL.leaf); c.dither(0, 0, 12, 6, PAL.leafD, 4)
|
||
c.px(11, 5, PAL.grass)
|
||
c.rect(0, 6, 6, 10, PAL.trunk); c.vline(5, 6, 10, PAL.trunkD)
|
||
end
|
||
T[17] = function(c) -- 小灌木
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(3, 5, 10, 9, PAL.leaf); c.rect(4, 4, 8, 11, PAL.leaf)
|
||
c.dither(4, 5, 8, 8, PAL.leafD, 3)
|
||
end
|
||
T[18] = function(c) -- 房屋外墙
|
||
c.rect(0, 0, 16, 16, PAL.wall)
|
||
c.hline(0, 15, 16, PAL.wallD); c.vline(0, 0, 16, PAL.wallD)
|
||
c.px(4, 4, PAL.wallD); c.px(11, 9, PAL.wallD)
|
||
end
|
||
T[19] = function(c) -- 外墙+窗
|
||
T[18](c)
|
||
c.rect(4, 4, 8, 8, PAL.woodD); c.rect(5, 5, 6, 6, PAL.sky)
|
||
c.vline(7, 5, 6, PAL.woodD); c.hline(5, 8, 6, PAL.woodD)
|
||
c.px(6, 6, PAL.waterL)
|
||
end
|
||
T[20] = function(c) -- 门
|
||
c.rect(0, 0, 16, 16, PAL.wall)
|
||
c.rect(3, 1, 10, 15, PAL.wood); c.rect(4, 2, 8, 14, PAL.woodL)
|
||
c.vline(4, 2, 14, PAL.wood); c.px(10, 9, PAL.woodD); c.hline(4, 2, 8, PAL.wood)
|
||
end
|
||
T[21] = function(c) -- 屋顶·左
|
||
c.rect(0, 0, 16, 16, PAL.roof)
|
||
c.hline(0, 0, 16, PAL.roofD); c.hline(0, 5, 16, PAL.roofD); c.hline(0, 10, 16, PAL.roofD); c.hline(0, 15, 16, PAL.roofD)
|
||
c.vline(0, 0, 16, PAL.roofD)
|
||
end
|
||
T[22] = function(c) -- 屋顶·右
|
||
c.rect(0, 0, 16, 16, PAL.roof)
|
||
c.hline(0, 0, 16, PAL.roofD); c.hline(0, 5, 16, PAL.roofD); c.hline(0, 10, 16, PAL.roofD); c.hline(0, 15, 16, PAL.roofD)
|
||
c.vline(15, 0, 16, PAL.roofD)
|
||
end
|
||
T[23] = function(c) -- 屋檐
|
||
c.rect(0, 0, 16, 8, PAL.roof); c.hline(0, 7, 16, PAL.roofD); c.hline(0, 6, 16, PAL.roofD)
|
||
c.rect(0, 8, 16, 8, PAL.wall); c.hline(0, 8, 16, PAL.wallD)
|
||
end
|
||
T[24] = function(c) -- 木地板
|
||
c.rect(0, 0, 16, 16, PAL.floor)
|
||
c.hline(0, 4, 16, PAL.floorD); c.hline(0, 9, 16, PAL.floorD); c.hline(0, 14, 16, PAL.floorD)
|
||
c.px(5, 2, PAL.floorD); c.px(12, 7, PAL.floorD); c.px(3, 12, PAL.floorD)
|
||
end
|
||
T[25] = function(c) -- 木地板2
|
||
c.rect(0, 0, 16, 16, PAL.floor)
|
||
c.hline(0, 2, 16, PAL.floorD); c.hline(0, 7, 16, PAL.floorD); c.hline(0, 12, 16, PAL.floorD)
|
||
c.px(9, 4, PAL.floorD); c.px(2, 9, PAL.floorD)
|
||
end
|
||
T[26] = function(c) -- 诊所地砖
|
||
c.rect(0, 0, 16, 16, PAL.clinic)
|
||
c.hline(0, 7, 16, PAL.clinicD); c.vline(7, 0, 16, PAL.clinicD); c.hline(0, 15, 16, PAL.clinicD); c.vline(15, 0, 16, PAL.clinicD)
|
||
end
|
||
T[27] = function(c) -- 室内墙
|
||
c.rect(0, 0, 16, 16, PAL.inwall)
|
||
c.dither(0, 0, 16, 16, PAL.inwallD, 8)
|
||
end
|
||
T[28] = function(c) -- 室内墙裙
|
||
c.rect(0, 0, 16, 10, PAL.inwall)
|
||
c.rect(0, 10, 16, 6, PAL.wood); c.hline(0, 10, 16, PAL.woodD)
|
||
end
|
||
T[29] = function(c) -- 地毯
|
||
c.rect(0, 0, 16, 16, PAL.pink)
|
||
c.rect(1, 1, 14, 14, C("ffc4de")); c.rect(3, 3, 10, 10, PAL.pink)
|
||
c.px(7, 7, PAL.white); c.px(8, 8, PAL.white)
|
||
end
|
||
T[30] = function(c) -- 床头(枕头)
|
||
c.rect(0, 0, 16, 16, PAL.wood)
|
||
c.rect(1, 1, 14, 15, C("f8f4e8"))
|
||
c.rect(3, 3, 10, 7, PAL.white); c.hline(3, 9, 10, C("d8d4c8"))
|
||
c.hline(1, 0, 14, PAL.woodD)
|
||
end
|
||
T[31] = function(c) -- 床尾(被子)
|
||
c.rect(0, 0, 16, 16, PAL.wood)
|
||
c.rect(1, 0, 14, 15, C("8ec8e0"))
|
||
c.hline(1, 3, 14, C("6fb0d0")); c.hline(1, 8, 14, C("6fb0d0")); c.hline(1, 13, 14, C("6fb0d0"))
|
||
c.hline(1, 15, 14, PAL.woodD)
|
||
end
|
||
T[32] = function(c) -- 柜台
|
||
c.rect(0, 0, 16, 16, PAL.wood)
|
||
c.rect(0, 0, 16, 6, PAL.woodL); c.hline(0, 6, 16, PAL.woodD)
|
||
c.vline(0, 0, 16, PAL.woodD); c.vline(15, 0, 16, PAL.woodD); c.hline(0, 15, 16, PAL.woodD)
|
||
end
|
||
T[33] = function(c) -- 烤炉
|
||
c.rect(0, 0, 16, 16, PAL.stoneD)
|
||
c.rect(1, 1, 14, 14, PAL.stone)
|
||
c.rect(3, 6, 10, 7, PAL.black)
|
||
c.rect(4, 8, 8, 4, C("f4924a")); c.px(6, 9, PAL.yellow); c.px(9, 10, PAL.yellow)
|
||
c.hline(3, 3, 10, PAL.stoneD)
|
||
end
|
||
T[34] = function(c) -- 货架(空)
|
||
c.rect(0, 0, 16, 16, PAL.wood)
|
||
c.rect(1, 1, 14, 14, PAL.woodL)
|
||
c.hline(1, 5, 14, PAL.woodD); c.hline(1, 10, 14, PAL.woodD); c.hline(1, 14, 14, PAL.woodD)
|
||
c.vline(0, 0, 16, PAL.woodD); c.vline(15, 0, 16, PAL.woodD)
|
||
end
|
||
T[35] = function(c) -- 货架(同一商品重复排列,标签空白)
|
||
T[34](c)
|
||
for _, y in ipairs({ 2, 7, 11 }) do
|
||
c.rect(2, y, 3, 3, PAL.berry); c.rect(6, y, 3, 3, PAL.berry); c.rect(10, y, 3, 3, PAL.berry)
|
||
c.px(3, y, PAL.white); c.px(7, y, PAL.white); c.px(11, y, PAL.white)
|
||
end
|
||
end
|
||
T[36] = function(c) -- 桌子
|
||
c.rect(0, 0, 16, 16, PAL.floor)
|
||
c.rect(2, 3, 12, 9, PAL.woodL); c.hline(2, 11, 12, PAL.woodD)
|
||
c.vline(3, 12, 3, PAL.woodD); c.vline(12, 12, 3, PAL.woodD)
|
||
c.hline(2, 3, 12, PAL.wood)
|
||
end
|
||
T[37] = function(c) -- 椅子
|
||
c.rect(0, 0, 16, 16, PAL.floor)
|
||
c.rect(4, 3, 8, 3, PAL.wood)
|
||
c.rect(4, 6, 8, 6, PAL.woodL)
|
||
c.vline(4, 12, 3, PAL.woodD); c.vline(11, 12, 3, PAL.woodD)
|
||
end
|
||
T[38] = function(c) -- 井·顶(小屋顶)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 2, 12, 6, PAL.roofD); c.rect(3, 1, 10, 2, PAL.roof)
|
||
c.vline(3, 8, 8, PAL.trunkD); c.vline(12, 8, 8, PAL.trunkD)
|
||
end
|
||
T[39] = function(c) -- 井·底(石圈)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 2, 12, 12, PAL.stone)
|
||
c.rect(4, 4, 8, 8, PAL.black)
|
||
c.px(3, 3, PAL.stoneD); c.px(12, 3, PAL.stoneD); c.px(3, 12, PAL.stoneD); c.px(12, 12, PAL.stoneD)
|
||
c.hline(2, 2, 12, PAL.stoneD)
|
||
end
|
||
T[40] = function(c) -- 雾(轻)
|
||
c.rect(0, 0, 16, 16, PAL.fog)
|
||
c.dither(0, 0, 16, 16, PAL.fogD, 3)
|
||
end
|
||
T[41] = function(c) -- 雾(浓)
|
||
c.rect(0, 0, 16, 16, PAL.fogD)
|
||
c.dither(0, 0, 16, 16, PAL.fog, 2); c.dither(1, 0, 16, 16, C("bcc8d2"), 5)
|
||
end
|
||
T[42] = function(c) -- 白色层·墙
|
||
c.rect(0, 0, 16, 16, PAL.wgray)
|
||
c.hline(0, 12, 16, PAL.wgrayD); c.rect(0, 13, 16, 3, PAL.wgrayDD)
|
||
end
|
||
T[43] = function(c) -- 白色层·地
|
||
c.rect(0, 0, 16, 16, PAL.wgrayD)
|
||
c.hline(0, 7, 16, PAL.wgrayDD); c.vline(7, 0, 16, PAL.wgrayDD)
|
||
end
|
||
T[44] = function(c) -- 白色层·门
|
||
c.rect(0, 0, 16, 16, PAL.wgray)
|
||
c.rect(3, 1, 10, 15, PAL.wgrayDD); c.rect(4, 2, 8, 14, PAL.wgrayD)
|
||
c.px(10, 9, PAL.wdark)
|
||
end
|
||
T[45] = function(c) -- 长椅·左
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 4, 14, 3, PAL.woodL); c.rect(2, 7, 14, 4, PAL.wood)
|
||
c.vline(3, 11, 3, PAL.woodD); c.hline(2, 7, 14, PAL.woodD)
|
||
end
|
||
T[46] = function(c) -- 长椅·右
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(0, 4, 14, 3, PAL.woodL); c.rect(0, 7, 14, 4, PAL.wood)
|
||
c.vline(12, 11, 3, PAL.woodD); c.hline(0, 7, 14, PAL.woodD)
|
||
end
|
||
T[47] = function(c) -- 公告板·左
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 1, 14, 12, PAL.wood); c.rect(4, 3, 12, 8, C("f8f0d8"))
|
||
c.hline(5, 5, 8, PAL.stoneD); c.hline(5, 7, 6, PAL.stoneD); c.hline(5, 9, 9, PAL.stoneD)
|
||
c.vline(4, 13, 3, PAL.trunkD)
|
||
end
|
||
T[48] = function(c) -- 公告板·右
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(0, 1, 14, 12, PAL.wood); c.rect(0, 3, 12, 8, C("f8f0d8"))
|
||
c.hline(1, 5, 8, PAL.stoneD); c.hline(1, 7, 9, PAL.stoneD); c.hline(1, 9, 5, PAL.stoneD)
|
||
c.vline(11, 13, 3, PAL.trunkD)
|
||
end
|
||
T[49] = function(c) -- 邮筒
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(4, 2, 8, 10, PAL.red); c.rect(5, 1, 6, 2, C("c04040"))
|
||
c.rect(6, 5, 4, 2, PAL.black)
|
||
c.vline(6, 12, 3, C("c04040")); c.vline(9, 12, 3, C("c04040"))
|
||
end
|
||
T[50] = function(c) -- 栅栏·横
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.hline(0, 6, 16, PAL.woodL); c.hline(0, 7, 16, PAL.wood); c.hline(0, 10, 16, PAL.woodL); c.hline(0, 11, 16, PAL.wood)
|
||
c.rect(2, 4, 2, 10, PAL.wood); c.rect(12, 4, 2, 10, PAL.wood)
|
||
c.px(2, 4, PAL.woodL); c.px(12, 4, PAL.woodL)
|
||
end
|
||
T[51] = function(c) -- 栅栏·柱
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(6, 2, 3, 12, PAL.wood); c.px(6, 2, PAL.woodL); c.px(7, 2, PAL.woodL)
|
||
end
|
||
T[52] = function(c) -- 路牌
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 3, 12, 6, PAL.woodL); c.hline(3, 5, 10, PAL.woodD); c.hline(3, 7, 7, PAL.woodD)
|
||
c.rect(7, 9, 2, 6, PAL.wood)
|
||
end
|
||
T[53] = function(c) -- 野餐布1
|
||
c.rect(0, 0, 16, 16, C("f8f0e0"))
|
||
for j = 0, 15 do for i = 0, 15 do
|
||
if (math.floor(i / 4) + math.floor(j / 4)) % 2 == 0 then c.px(i, j, C("f0a0a8")) end
|
||
end end
|
||
end
|
||
T[54] = function(c) -- 野餐布2(有食物)
|
||
T[53](c)
|
||
c.rect(5, 5, 6, 6, C("fff8e8")); c.px(7, 7, PAL.berry); c.px(9, 8, PAL.berry); c.px(6, 9, PAL.yellow)
|
||
end
|
||
T[55] = function(c) -- 花坛(盛开)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(1, 1, 14, 14, PAL.stoneD); c.rect(2, 2, 12, 12, C("8a6a48"))
|
||
c.px(4, 4, PAL.pink); c.px(8, 5, PAL.yellow); c.px(11, 4, PAL.red); c.px(5, 8, PAL.yellow)
|
||
c.px(9, 9, PAL.pink); c.px(12, 8, PAL.white); c.px(4, 11, PAL.red); c.px(8, 12, PAL.pink); c.px(11, 11, PAL.yellow)
|
||
end
|
||
T[56] = function(c) -- 花田·土
|
||
c.rect(0, 0, 16, 16, C("a8825a"))
|
||
c.hline(0, 3, 16, C("94714c")); c.hline(0, 8, 16, C("94714c")); c.hline(0, 13, 16, C("94714c"))
|
||
end
|
||
T[57] = function(c) -- 花田·苗
|
||
T[56](c)
|
||
c.px(3, 2, PAL.leaf); c.px(3, 1, PAL.leaf); c.px(9, 7, PAL.leaf); c.px(9, 6, PAL.leaf); c.px(13, 12, PAL.leaf); c.px(13, 11, PAL.leaf)
|
||
c.px(4, 1, PAL.pink); c.px(10, 6, PAL.yellow)
|
||
end
|
||
T[58] = function(c) -- 彩带(挂起)
|
||
c.rect(0, 0, 16, 16, pc.rgba(0, 0, 0, 0))
|
||
for i = 0, 15 do
|
||
local y = math.floor(2 + 2 * math.sin(i / 4))
|
||
c.px(i, y + 1, PAL.woodD)
|
||
end
|
||
c.px(2, 4, PAL.red); c.px(2, 5, PAL.red); c.px(6, 5, PAL.yellow); c.px(6, 6, PAL.yellow)
|
||
c.px(10, 4, PAL.pink); c.px(10, 5, PAL.pink); c.px(14, 5, PAL.sky); c.px(14, 6, PAL.sky)
|
||
end
|
||
T[59] = function(c) -- 灯笼杆
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(7, 2, 2, 12, PAL.trunk)
|
||
c.rect(5, 2, 6, 5, PAL.yellow); c.rect(6, 1, 4, 1, PAL.roofD); c.px(7, 4, C("fff0a0")); c.px(8, 4, C("fff0a0"))
|
||
end
|
||
T[60] = function(c) -- 湖水·波光
|
||
T[7](c)
|
||
c.px(4, 6, PAL.white); c.px(11, 8, PAL.white); c.hline(7, 2, 3, PAL.waterL)
|
||
end
|
||
T[61] = function(c) -- 室内窗
|
||
T[27](c)
|
||
c.rect(3, 3, 10, 8, PAL.woodD); c.rect(4, 4, 8, 6, PAL.sky)
|
||
c.vline(7, 4, 6, PAL.woodD); c.px(5, 5, PAL.waterL)
|
||
end
|
||
T[62] = function(c) -- 白色层·病床头
|
||
c.rect(0, 0, 16, 16, PAL.wgrayD)
|
||
c.rect(1, 1, 14, 15, PAL.wgray)
|
||
c.rect(3, 3, 10, 6, PAL.white); c.hline(3, 8, 10, PAL.wgrayD)
|
||
c.hline(1, 0, 14, PAL.wgrayDD)
|
||
end
|
||
T[63] = function(c) -- 白色层·病床尾
|
||
c.rect(0, 0, 16, 16, PAL.wgrayD)
|
||
c.rect(1, 0, 14, 15, C("dfe2e6"))
|
||
c.hline(1, 4, 14, PAL.wgrayD); c.hline(1, 9, 14, PAL.wgrayD)
|
||
c.hline(1, 15, 14, PAL.wgrayDD)
|
||
end
|
||
T[64] = function(c) -- 桌(诊所/办公)
|
||
c.rect(0, 0, 16, 16, PAL.clinic)
|
||
c.rect(1, 3, 14, 9, PAL.woodL); c.hline(1, 11, 14, PAL.woodD); c.hline(1, 3, 14, PAL.wood)
|
||
c.rect(3, 5, 6, 4, PAL.white); c.hline(4, 6, 4, PAL.stoneD); c.hline(4, 7, 3, PAL.stoneD)
|
||
c.vline(2, 12, 3, PAL.woodD); c.vline(13, 12, 3, PAL.woodD)
|
||
end
|
||
T[65] = function(c) -- 日历(墙面)
|
||
T[27](c)
|
||
c.rect(4, 2, 8, 11, PAL.white); c.rect(4, 2, 8, 3, PAL.red)
|
||
c.hline(5, 7, 6, PAL.stoneD); c.hline(5, 9, 6, PAL.stoneD); c.rect(7, 10, 3, 2, PAL.black)
|
||
end
|
||
T[66] = function(c) -- 柜台+配方纸
|
||
T[32](c)
|
||
c.rect(4, 1, 7, 5, C("f8f0d8")); c.hline(5, 2, 5, PAL.stoneD); c.hline(5, 4, 4, PAL.stoneD)
|
||
end
|
||
T[67] = function(c) -- 木箱
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 3, 12, 12, PAL.wood); c.rect(3, 4, 10, 10, PAL.woodL)
|
||
c.hline(3, 8, 10, PAL.wood); c.vline(8, 4, 10, PAL.wood)
|
||
end
|
||
T[68] = function(c) -- 篮子
|
||
c.rect(0, 0, 16, 16, PAL.floor)
|
||
c.rect(3, 6, 10, 8, PAL.woodL); c.hline(3, 6, 10, PAL.woodD); c.hline(3, 13, 10, PAL.woodD)
|
||
c.dither(4, 8, 8, 5, PAL.wood, 2)
|
||
c.px(6, 5, PAL.berry); c.px(9, 5, PAL.berry)
|
||
end
|
||
T[69] = function(c) -- 花坛(干涸·待浇水)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(1, 1, 14, 14, PAL.stoneD); c.rect(2, 2, 12, 12, C("b09068"))
|
||
c.px(5, 5, C("8a7a5a")); c.px(10, 7, C("8a7a5a")); c.px(6, 10, C("8a7a5a"))
|
||
end
|
||
T[70] = function(c) -- 白色层·窗
|
||
T[42](c)
|
||
c.rect(4, 2, 8, 7, PAL.wgrayDD); c.rect(5, 3, 6, 5, C("c8ccd4")); c.vline(7, 3, 5, PAL.wgrayDD)
|
||
end
|
||
T[71] = function(c) -- 门垫
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.rect(2, 4, 12, 8, C("c8a878")); c.rect(3, 5, 10, 6, C("dcc094"))
|
||
end
|
||
T[72] = function(c) -- 高草
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
for i = 1, 14, 3 do c.vline(i, 6, 8, PAL.grassD); c.vline(i + 1, 8, 6, PAL.grassL) end
|
||
end
|
||
T[73] = function(c) -- 广场中心砖
|
||
c.rect(0, 0, 16, 16, PAL.path)
|
||
c.rect(2, 2, 12, 12, C("f0c88a")); c.rect(5, 5, 6, 6, PAL.path)
|
||
c.px(7, 7, PAL.roofD); c.px(8, 8, PAL.roofD)
|
||
end
|
||
T[74] = function(c) -- 白色层·帘
|
||
c.rect(0, 0, 16, 16, PAL.wgray)
|
||
for i = 0, 15, 3 do c.vline(i, 0, 16, C("d8dade")) end
|
||
c.hline(0, 0, 16, PAL.wgrayDD)
|
||
end
|
||
T[75] = function(c) -- 白色层·监护仪
|
||
c.rect(0, 0, 16, 16, PAL.wgrayD)
|
||
c.rect(3, 2, 10, 9, PAL.wdark); c.rect(4, 3, 8, 6, C("354048"))
|
||
c.px(5, 6, C("7ae0a0")); c.px(6, 5, C("7ae0a0")); c.px(7, 6, C("7ae0a0")); c.px(8, 6, C("7ae0a0")); c.px(9, 4, C("7ae0a0")); c.px(10, 6, C("7ae0a0"))
|
||
c.rect(6, 11, 4, 4, PAL.wgrayDD)
|
||
end
|
||
T[76] = function(c) -- 石墙(村界)
|
||
c.rect(0, 0, 16, 16, PAL.stone)
|
||
c.hline(0, 5, 16, PAL.stoneD); c.hline(0, 11, 16, PAL.stoneD)
|
||
c.vline(4, 0, 5, PAL.stoneD); c.vline(10, 6, 5, PAL.stoneD); c.vline(6, 12, 4, PAL.stoneD)
|
||
end
|
||
T[77] = function(c) -- 雾中草地(边缘)
|
||
c.rect(0, 0, 16, 16, PAL.grass)
|
||
c.dither(0, 0, 16, 16, PAL.fog, 2)
|
||
end
|
||
T[78] = function(c) -- 黑
|
||
c.rect(0, 0, 16, 16, PAL.black)
|
||
end
|
||
T[79] = function(c) -- 纯白灰
|
||
c.rect(0, 0, 16, 16, PAL.wgray)
|
||
end
|
||
|
||
local tilesImg = Image(160, 128, ColorMode.RGB)
|
||
for idx = 0, 79 do
|
||
local col, row = idx % 10, math.floor(idx / 10)
|
||
T[idx](makeCtx(tilesImg, col * 16, row * 16))
|
||
end
|
||
saveSheet(tilesImg, "tiles")
|
||
|
||
-- ============ 主角:16×24 × 16 帧(下/上/左/右 × 4) ============
|
||
local SKIN = C("f6d2a8")
|
||
local HAIR = C("6b4632")
|
||
local SHIRT = C("e87858")
|
||
local SHIRT_D = C("cc5f42")
|
||
local PANTS = C("4a6a9a")
|
||
local SHOE = C("7a4a2a")
|
||
|
||
-- 画一帧主角;dir: 0下 1上 2左 3右;f: 0..3 行走帧(0 兼待机)
|
||
local function paintPlayer(c, dir, f)
|
||
-- 头(x4..11, y0..7):发 0..2,脸 3..7
|
||
c.rect(4, 0, 8, 3, HAIR)
|
||
c.px(4, 0, pc.rgba(0, 0, 0, 0)); c.px(11, 0, pc.rgba(0, 0, 0, 0))
|
||
if dir == 1 then
|
||
c.rect(4, 3, 8, 5, HAIR) -- 背面全是头发
|
||
c.px(4, 7, SKIN); c.px(11, 7, SKIN)
|
||
else
|
||
c.rect(4, 3, 8, 5, SKIN)
|
||
c.vline(4, 3, 2, HAIR); c.vline(11, 3, 2, HAIR) -- 刘海两侧
|
||
if dir == 0 then
|
||
c.px(6, 5, PAL.black); c.px(9, 5, PAL.black)
|
||
c.px(7, 7, PAL.black); c.px(8, 7, PAL.black) -- 永远的微笑
|
||
c.px(6, 6, C("f8b8a0")); c.px(9, 6, C("f8b8a0"))
|
||
elseif dir == 2 then
|
||
c.rect(9, 3, 3, 5, HAIR) -- 侧脸:后脑
|
||
c.px(6, 5, PAL.black); c.px(5, 7, PAL.black); c.px(6, 7, PAL.black)
|
||
elseif dir == 3 then
|
||
c.rect(4, 3, 3, 5, HAIR)
|
||
c.px(9, 5, PAL.black); c.px(9, 7, PAL.black); c.px(10, 7, PAL.black)
|
||
end
|
||
end
|
||
-- 身体(y8..16)
|
||
c.rect(5, 8, 6, 9, SHIRT)
|
||
c.hline(5, 16, 6, SHIRT_D)
|
||
-- 手臂:随帧摆动
|
||
local sway = ({ 0, 1, 0, -1 })[f + 1]
|
||
if dir == 0 or dir == 1 then
|
||
c.vline(4, 9 + (sway > 0 and 1 or 0), 5, SHIRT_D); c.px(4, 14 + (sway > 0 and 1 or 0), SKIN)
|
||
c.vline(11, 9 + (sway < 0 and 1 or 0), 5, SHIRT_D); c.px(11, 14 + (sway < 0 and 1 or 0), SKIN)
|
||
else
|
||
c.vline(dir == 2 and 7 or 8, 9 + math.abs(sway), 5, SHIRT_D)
|
||
c.px(dir == 2 and 7 or 8, 14 + math.abs(sway), SKIN)
|
||
end
|
||
-- 腿(y17..20)与鞋(y21..23)
|
||
local lLift = (f == 1) and 1 or 0
|
||
local rLift = (f == 3) and 1 or 0
|
||
c.rect(5, 17, 3, 4 - lLift, PANTS)
|
||
c.rect(8, 17, 3, 4 - rLift, PANTS)
|
||
c.rect(5, 21 - lLift, 3, 2, SHOE)
|
||
c.rect(8, 21 - rLift, 3, 2, SHOE)
|
||
end
|
||
|
||
local playerImg = Image(256, 24, ColorMode.RGB)
|
||
for dir = 0, 3 do
|
||
for f = 0, 3 do
|
||
paintPlayer(makeCtx(playerImg, (dir * 4 + f) * 16, 0), dir, f)
|
||
end
|
||
end
|
||
saveSheet(playerImg, "player")
|
||
|
||
-- ============ 主角头像:24×24(微笑 / 真实的脸) ============
|
||
local function paintPortrait(c, real)
|
||
c.rect(0, 0, 24, 24, C("f8ecd0")) -- 背景
|
||
c.rect(4, 2, 16, 6, HAIR) -- 头发
|
||
c.px(4, 2, C("f8ecd0")); c.px(19, 2, C("f8ecd0"))
|
||
c.rect(4, 8, 16, 12, SKIN) -- 脸
|
||
c.vline(4, 8, 4, HAIR); c.vline(5, 8, 2, HAIR)
|
||
c.vline(19, 8, 4, HAIR); c.vline(18, 8, 2, HAIR)
|
||
c.rect(6, 20, 12, 4, SHIRT) -- 肩
|
||
if real then
|
||
-- 真实的脸:疲惫——平直的嘴、眼下阴影、微乱的头发
|
||
c.px(3, 4, HAIR); c.px(20, 5, HAIR); c.px(2, 5, HAIR)
|
||
c.rect(8, 12, 2, 2, PAL.black); c.rect(14, 12, 2, 2, PAL.black)
|
||
c.hline(8, 15, 2, C("c8a080")); c.hline(14, 15, 2, C("c8a080")) -- 眼袋
|
||
c.hline(10, 18, 4, C("9a6a52")) -- 平直疲惫的嘴
|
||
else
|
||
-- 永远的微笑
|
||
c.rect(8, 12, 2, 2, PAL.black); c.rect(14, 12, 2, 2, PAL.black)
|
||
c.px(7, 14, C("f8b8a0")); c.px(16, 14, C("f8b8a0")) -- 腮红
|
||
c.px(9, 17, C("9a6a52")); c.px(14, 17, C("9a6a52"))
|
||
c.hline(10, 18, 4, C("9a6a52")) -- 上弯的微笑
|
||
end
|
||
end
|
||
local p1 = Image(24, 24, ColorMode.RGB); paintPortrait(makeCtx(p1, 0, 0), false); saveSheet(p1, "portrait_smile")
|
||
local p2 = Image(24, 24, ColorMode.RGB); paintPortrait(makeCtx(p2, 0, 0), true); saveSheet(p2, "portrait_real")
|
||
|
||
-- ============ 具名 NPC:16×24 × 4 帧(smile/flat/off/blink) ============
|
||
-- off 档与 smile 档仅差 1–2 像素(右眼低 1 像素),绝不画成鬼脸。
|
||
local function paintAnimal(c, spec, expr)
|
||
local top = spec.headTop or 2
|
||
-- 头
|
||
c.rect(2, top, 12, 10, spec.fur)
|
||
c.px(2, top, pc.rgba(0, 0, 0, 0)); c.px(13, top, pc.rgba(0, 0, 0, 0))
|
||
c.px(2, top + 9, pc.rgba(0, 0, 0, 0)); c.px(13, top + 9, pc.rgba(0, 0, 0, 0))
|
||
-- 口鼻
|
||
c.rect(5, top + 5, 6, 4, spec.muzzle)
|
||
-- 眼睛
|
||
local ey = top + 4
|
||
if expr == "blink" then
|
||
c.px(5, ey + 1, PAL.black); c.px(10, ey + 1, PAL.black)
|
||
else
|
||
c.px(5, ey, PAL.black); c.px(5, ey + 1, PAL.black)
|
||
local roff = (expr == "off") and 1 or 0 -- 崩坏档:右眼低 1 像素
|
||
c.px(10, ey + roff, PAL.black); c.px(10, ey + 1 + roff, PAL.black)
|
||
end
|
||
-- 鼻子
|
||
if spec.nose then c.px(7, top + 6, PAL.black); c.px(8, top + 6, PAL.black) end
|
||
-- 嘴:微笑(小 U)或平直
|
||
local my = top + 8
|
||
if expr == "flat" then
|
||
c.hline(6, my, 4, PAL.black)
|
||
else
|
||
c.px(6, my - 1, PAL.black); c.px(9, my - 1, PAL.black); c.px(7, my, PAL.black); c.px(8, my, PAL.black)
|
||
end
|
||
-- 身体
|
||
c.rect(4, 12, 8, 8, spec.cloth)
|
||
-- 手
|
||
c.vline(3, 13, 4, spec.fur); c.vline(12, 13, 4, spec.fur)
|
||
-- 脚
|
||
c.rect(4, 20, 3, 3, spec.furD); c.rect(9, 20, 3, 3, spec.furD)
|
||
if spec.extra then spec.extra(c, expr) end
|
||
end
|
||
|
||
local NPCS = {
|
||
{ file = "npc_afu", fur = C("c49058"), furD = C("a87840"), muzzle = C("ecd0a8"), cloth = C("e0b060"), nose = true,
|
||
extra = function(c) -- 狗村长:垂耳+红领巾
|
||
c.rect(1, 3, 2, 5, C("a87840")); c.rect(13, 3, 2, 5, C("a87840"))
|
||
c.hline(4, 12, 8, PAL.red); c.px(7, 13, PAL.red); c.px(8, 13, PAL.red)
|
||
end },
|
||
{ file = "npc_yuanyuan", fur = C("f7f2ea"), furD = C("ddd4c8"), muzzle = C("ffffff"), cloth = C("f8c8d8"), headTop = 4,
|
||
extra = function(c) -- 兔面包师:长耳+围裙
|
||
c.rect(4, 0, 2, 4, C("f7f2ea")); c.px(5, 1, C("f8b8c8")); c.px(5, 2, C("f8b8c8"))
|
||
c.rect(10, 0, 2, 4, C("f7f2ea")); c.px(10, 1, C("f8b8c8")); c.px(10, 2, C("f8b8c8"))
|
||
c.rect(5, 14, 6, 6, C("fff8f0")); c.px(6, 10, C("f0a0b0")) -- 围裙+腮红
|
||
c.px(9, 10, C("f0a0b0"))
|
||
end },
|
||
{ file = "npc_dabao", fur = C("9a6b42"), furD = C("7e5530"), muzzle = C("c89a68"), cloth = C("5a88c8"), nose = true,
|
||
extra = function(c) -- 熊邮差:圆耳+挎包带
|
||
c.rect(3, 0, 3, 2, C("9a6b42")); c.rect(10, 0, 3, 2, C("9a6b42"))
|
||
c.px(4, 1, C("c89a68")); c.px(11, 1, C("c89a68"))
|
||
for i = 0, 6 do c.px(4 + i, 13 + i > 19 and 19 or 13 + math.floor(i * 0.9), C("3a5a88")) end
|
||
end },
|
||
{ file = "npc_mimi", fur = C("c8c0d8"), furD = C("a8a0c0"), muzzle = C("ece8f4"), cloth = C("e8a04a"), nose = true,
|
||
extra = function(c) -- 猫店主:尖耳+胡须
|
||
c.px(3, 1, C("c8c0d8")); c.rect(3, 2, 2, 1, C("c8c0d8")); c.px(4, 1, C("c8c0d8"))
|
||
c.px(12, 1, C("c8c0d8")); c.rect(11, 2, 2, 1, C("c8c0d8")); c.px(11, 1, C("c8c0d8"))
|
||
c.hline(1, 8, 2, C("8a84a0")); c.hline(13, 8, 2, C("8a84a0"))
|
||
end },
|
||
{ file = "npc_fu", fur = C("d8b088"), furD = C("bc9268"), muzzle = C("f0d8b8"), cloth = C("f4f4f4"), nose = true,
|
||
extra = function(c) -- 鹿医生:小角+白大褂
|
||
c.px(4, 1, C("8a6a4a")); c.px(4, 0, C("8a6a4a")); c.px(3, 0, C("8a6a4a"))
|
||
c.px(11, 1, C("8a6a4a")); c.px(11, 0, C("8a6a4a")); c.px(12, 0, C("8a6a4a"))
|
||
c.vline(7, 12, 8, C("d8d8d8")) -- 大褂门襟
|
||
end },
|
||
{ file = "npc_gui", fur = C("a8c078"), furD = C("88a058"), muzzle = C("c8d8a0"), cloth = C("7a9a4a"),
|
||
extra = function(c) -- 龟爷爷:龟壳纹+老花镜
|
||
c.hline(5, 14, 6, C("5f7c38")); c.hline(5, 17, 6, C("5f7c38")); c.vline(7, 13, 6, C("5f7c38"))
|
||
local gy = 2 + 4
|
||
c.px(4, gy, C("6a6a6a")); c.px(6, gy, C("6a6a6a")); c.px(9, gy, C("6a6a6a")); c.px(11, gy, C("6a6a6a"))
|
||
c.px(7, gy, C("6a6a6a")); c.px(8, gy, C("6a6a6a"))
|
||
end },
|
||
}
|
||
|
||
for _, spec in ipairs(NPCS) do
|
||
local img = Image(64, 24, ColorMode.RGB)
|
||
local exprs = { "smile", "flat", "off", "blink" }
|
||
for i, e in ipairs(exprs) do
|
||
paintAnimal(makeCtx(img, (i - 1) * 16, 0), spec, e)
|
||
end
|
||
saveSheet(img, spec.file)
|
||
end
|
||
|
||
-- ============ 双子鸟:16×16 × 2 帧(闭嘴/张嘴) ============
|
||
local function paintBird(c, open)
|
||
local B = C("6ab0e8")
|
||
local BD = C("4a90c8")
|
||
c.rect(4, 5, 8, 7, B) -- 身体
|
||
c.rect(8, 2, 6, 6, B) -- 头
|
||
c.px(11, 4, PAL.black) -- 眼
|
||
c.rect(2, 6, 3, 4, BD) -- 尾
|
||
c.rect(5, 7, 4, 3, BD) -- 翅
|
||
if open then
|
||
c.px(14, 5, PAL.yellow); c.px(15, 4, PAL.yellow); c.px(15, 6, PAL.yellow)
|
||
else
|
||
c.px(14, 5, PAL.yellow); c.px(15, 5, PAL.yellow)
|
||
end
|
||
c.vline(7, 12, 2, PAL.yellow); c.vline(10, 12, 2, PAL.yellow) -- 脚
|
||
end
|
||
local birdImg = Image(32, 16, ColorMode.RGB)
|
||
paintBird(makeCtx(birdImg, 0, 0), false)
|
||
paintBird(makeCtx(birdImg, 16, 0), true)
|
||
saveSheet(birdImg, "bird")
|
||
|
||
-- ============ 灰麻雀(E3 结局,一只真的鸟):16×16 ============
|
||
local function paintSparrow(c)
|
||
local G = C("9a9088")
|
||
local GD = C("6e6660")
|
||
c.rect(4, 6, 8, 6, G)
|
||
c.rect(8, 3, 6, 5, G)
|
||
c.px(11, 5, PAL.black)
|
||
c.rect(2, 7, 3, 3, GD)
|
||
c.rect(5, 8, 4, 2, GD)
|
||
c.px(14, 6, C("7a6a58")); c.px(15, 6, C("7a6a58"))
|
||
c.vline(7, 12, 2, GD); c.vline(10, 12, 2, GD)
|
||
end
|
||
local sparrowImg = Image(16, 16, ColorMode.RGB)
|
||
paintSparrow(makeCtx(sparrowImg, 0, 0))
|
||
saveSheet(sparrowImg, "sparrow")
|
||
|
||
-- ============ 群演 ×5:16×16 × 2 帧循环 ============
|
||
local function paintCritter(c, spec, f)
|
||
local bob = f -- 第二帧整体下移 1px 形成循环
|
||
c.rect(4, 6 + bob, 8, 6 - bob, spec.body)
|
||
c.rect(5, 2 + bob, 6, 5, spec.body)
|
||
c.px(6, 4 + bob, PAL.black); c.px(9, 4 + bob, PAL.black)
|
||
c.px(7, 6 + bob, spec.snout); c.px(8, 6 + bob, spec.snout)
|
||
c.rect(4, 12, 3, 2, spec.dark); c.rect(9, 12, 3, 2, spec.dark)
|
||
if spec.extra then spec.extra(c, f) end
|
||
end
|
||
local CRITTERS = {
|
||
{ file = "extra1", body = C("e0904a"), dark = C("b87030"), snout = C("f8c890"), -- 松鼠:大尾巴
|
||
extra = function(c, f) c.rect(12, 1 + f, 3, 9, C("b87030")); c.px(13, 2 + f, C("e0904a")) end },
|
||
{ file = "extra2", body = C("b09068"), dark = C("8a6a48"), snout = C("e8cca8"), -- 刺猬:背刺
|
||
extra = function(c, f) for i = 4, 11, 2 do c.px(i, 1 + f + (i % 4 == 0 and 0 or 1), C("6e5236")) end end },
|
||
{ file = "extra3", body = C("f4e04a"), dark = C("d8b830"), snout = C("f4a030"), -- 鸭子:扁嘴
|
||
extra = function(c, f) c.px(6, 5 + f, C("f4a030")); c.px(9, 5 + f, C("f4a030")) end },
|
||
{ file = "extra4", body = C("b8b8c4"), dark = C("8e8e9c"), snout = C("e8c8c8"), -- 老鼠:圆耳
|
||
extra = function(c, f) c.rect(4, 0 + f, 2, 2, C("b8b8c4")); c.rect(10, 0 + f, 2, 2, C("b8b8c4")) end },
|
||
{ file = "extra5", body = C("7ac86a"), dark = C("58a048"), snout = C("aee89e"), -- 青蛙:凸眼
|
||
extra = function(c, f) c.px(5, 1 + f, C("7ac86a")); c.px(10, 1 + f, C("7ac86a")) end },
|
||
}
|
||
for _, spec in ipairs(CRITTERS) do
|
||
local img = Image(32, 16, ColorMode.RGB)
|
||
paintCritter(makeCtx(img, 0, 0), spec, 0)
|
||
paintCritter(makeCtx(img, 16, 0), spec, 1)
|
||
saveSheet(img, spec.file)
|
||
end
|
||
|
||
-- ============ 向日葵表盘:24×24 × 14 帧 ============
|
||
-- 帧 0..12 = 点亮花瓣数;帧 13 = 满格+花心黑籽
|
||
local function paintSunflower(c, lit, seeds)
|
||
local cx, cy = 11.5, 11.5
|
||
for k = 0, 11 do
|
||
local ang = (k / 12) * math.pi * 2 - math.pi / 2
|
||
local col = (k < lit) and PAL.yellow or C("7a7264")
|
||
local colD = (k < lit) and C("e0b830") or C("635c50")
|
||
for r = 7, 10 do
|
||
local x = math.floor(cx + math.cos(ang) * r + 0.5)
|
||
local y = math.floor(cy + math.sin(ang) * r + 0.5)
|
||
c.px(x, y, r > 9 and colD or col)
|
||
local px2 = math.floor(cx + math.cos(ang + 0.14) * r + 0.5)
|
||
local py2 = math.floor(cy + math.sin(ang + 0.14) * r + 0.5)
|
||
c.px(px2, py2, col)
|
||
end
|
||
end
|
||
-- 花心
|
||
for j = -4, 4 do for i = -4, 4 do
|
||
if i * i + j * j <= 18 then c.px(12 + i, 12 + j, C("9a6a2a")) end
|
||
end end
|
||
for j = -3, 3 do for i = -3, 3 do
|
||
if i * i + j * j <= 9 then c.px(12 + i, 12 + j, C("b8843a")) end
|
||
end end
|
||
if seeds then -- 过熟的黑籽
|
||
c.px(11, 11, PAL.black); c.px(13, 12, PAL.black); c.px(12, 14, PAL.black)
|
||
c.px(10, 13, PAL.black); c.px(14, 10, PAL.black); c.px(12, 11, C("4a3a20"))
|
||
end
|
||
end
|
||
local sunImg = Image(24 * 14, 24, ColorMode.RGB)
|
||
for f = 0, 12 do paintSunflower(makeCtx(sunImg, f * 24, 0), f, false) end
|
||
paintSunflower(makeCtx(sunImg, 13 * 24, 0), 12, true)
|
||
saveSheet(sunImg, "sunflower")
|
||
|
||
print("ALL ART GENERATED OK")
|