-- gen_player.lua: generate player sprite sheet (16x24 frames). -- Layout: 4 cols x 4 rows. Row order: walk-down, walk-up, walk-left, walk-right. -- Each row 4 frames: frame 0 = idle, 1-3 = walk frames. -- Produces assets/sprites/player.png local FW = 16 local FH = 24 local COLS = 4 local ROWS = 4 local W = COLS*FW local H = ROWS*FH app.command.NewFile{ width=W, height=H, colorMode=ColorMode.RGB } local spr = app.activeSprite local img = app.activeImage for y=0,H-1 do for x=0,W-1 do img:drawPixel(x,y, app.pixelColor.rgba(0,0,0,0)) end end local function px(x,y,c) img:drawPixel(x,y,c) end local function rect(ox,oy,w,h,c) for y=oy,oy+h-1 do for x=ox,ox+w-1 do px(x,y,c) end end end -- gender-neutral candy palette local skin = app.pixelColor.rgba(255,214,176,255) local skinS = app.pixelColor.rgba(224,176,140,255) local hair = app.pixelColor.rgba(150,110,80,255) -- chestnut local hairD = app.pixelColor.rgba(110,80,56,255) local shirt = app.pixelColor.rgba(120,200,230,255) -- sky blue local shirtD = app.pixelColor.rgba(86,160,200,255) local pants = app.pixelColor.rgba(110,90,150,255) -- muted purple local pantsD = app.pixelColor.rgba(80,64,116,255) local shoe = app.pixelColor.rgba(90,70,60,255) local eye = app.pixelColor.rgba(60,40,40,255) local cheek = app.pixelColor.rgba(255,170,170,255) local mouth = app.pixelColor.rgba(200,110,110,255) -- draw a character frame at ox,oy facing dir, walk phase p (0=idle, 1-3) local function frame(ox, oy, dir, p) -- common body -- head (cols 4..11, rows 1..9) rect(ox+5, oy+1, 6, 7, skin) -- hair cap depending on direction if dir == "up" then -- back of head: hair covers rect(ox+5, oy+1, 6, 6, hair) rect(ox+5, oy+1, 6, 2, hairD) else rect(ox+4, oy+1, 8, 3, hair) rect(ox+5, oy+0, 6, 2, hair) rect(ox+4, oy+1, 8, 1, hairD) end -- face details for down if dir == "down" then px(ox+6, oy+5, eye); px(ox+9, oy+5, eye) px(ox+7, oy+7, mouth); px(ox+8, oy+7, mouth) px(ox+6, oy+6, cheek); px(ox+9, oy+6, cheek) elseif dir == "side" then -- left or right handled by caller mirroring via draw order px(ox+7, oy+5, eye) px(ox+8, oy+7, mouth) px(ox+6, oy+6, cheek) end -- torso (rows 8..15) rect(ox+5, oy+9, 6, 6, shirt) rect(ox+5, oy+9, 6, 1, shirtD) rect(ox+5, oy+14, 6, 1, shirtD) -- arms rect(ox+4, oy+10, 1, 4, shirt) rect(ox+10, oy+10, 1, 4, shirt) px(ox+4, oy+14, skin); px(ox+10, oy+14, skin) -- legs / walk animation local L, R = oy+15, oy+15 if p == 0 then -- idle: legs together rect(ox+5, oy+15, 2, 6, pants) rect(ox+9, oy+15, 2, 6, pants) px(ox+5, oy+21, shoe); px(ox+6, oy+21, shoe) px(ox+9, oy+21, shoe); px(ox+10, oy+21, shoe) elseif p == 1 then -- step: left leg forward (down/up), or side-step rect(ox+5, oy+15, 2, 5, pants) rect(ox+9, oy+15, 2, 5, pants) px(ox+5, oy+20, shoe); px(ox+6, oy+20, shoe) px(ox+9, oy+21, shoe); px(ox+10, oy+21, shoe) elseif p == 2 then -- mid rect(ox+5, oy+15, 2, 6, pants) rect(ox+9, oy+15, 2, 6, pants) px(ox+5, oy+21, shoe); px(ox+6, oy+21, shoe) px(ox+9, oy+21, shoe); px(ox+10, oy+21, shoe) elseif p == 3 then -- step: right leg forward rect(ox+5, oy+15, 2, 5, pants) rect(ox+9, oy+15, 2, 5, pants) px(ox+5, oy+21, shoe); px(ox+6, oy+21, shoe) px(ox+9, oy+20, shoe); px(ox+10, oy+20, shoe) end end -- mirror helper for left/right by copying pixels local function mirrorRow(srcRow, dstRow) for f=0,3 do local sx = f*FW local dx = f*FW local sy = srcRow*FH local dy = dstRow*FH for y=0,FH-1 do for x=0,FW-1 do local c = img:getPixel(sx + (FW-1-x), sy + y) img:drawPixel(dx + x, dy + y, c) end end end end -- Row 0: walk-down for f=0,3 do frame(f*FW, 0*FH, "down", f) end -- Row 1: walk-up for f=0,3 do frame(f*FW, 1*FH, "up", f) end -- Row 2: walk-right (side) for f=0,3 do frame(f*FW, 2*FH, "side", f) end -- Row 3: walk-left = mirror of right mirrorRow(2, 3) local out = "assets/sprites/player.png" spr:saveCopyAs(out) print("Saved " .. out) app.exit()