diff --git a/tools/aseprite_scripts/export_tileset_psx.lua b/tools/aseprite_scripts/export_tileset_psx.lua deleted file mode 100644 index d6c7af1..0000000 --- a/tools/aseprite_scripts/export_tileset_psx.lua +++ /dev/null @@ -1,113 +0,0 @@ -if TilesetMode == nil then return app.alert "Use Aseprite v1.3" end - --- Export tilesets for aseprite files with two layers: foreground and background --- Layer names don't matter. Make sure foreground is on top. --- 1. Copy both layers. --- 2. Turn original layers invisible --- 3. Flatten copied layers, make them visible --- 4. Convert flattened layer to tilemap layer --- 5. Export tileset --- 6. Delete flattened layer - ---local row_len = 32 - -local function activeFrameNumber() - local f = app.activeFrame - if f == nil then - return 1 - else - return f - end -end - - -app.command.GotoFirstFrame() -local spr = app.activeSprite -local lay = app.activeLayer -local fs = app.fs -local output_folder = fs.filePath(spr.filename) -if not lay.isTilemap then return app.alert "No active tilemap layer" end - -local function layers_tilemap_duplicate(spr) - for i,layer in ipairs(spr.layers) do - if layer.isTilemap then - app.activeLayer = layer - layer.isVisible = true - app.command.DuplicateLayer() - layer.isVisible = false - else - layer.isVisible = false - end - end -end - -local function layers_visible_flatten(spr) - for i,layer in ipairs(spr.layers) do - app.command.FlattenLayers{["visibleOnly"]="true"} - local grid = spr.gridBounds - grid.height = 8 - grid.width = 8 - spr.gridBounds = grid - - --row_len = 256 / grid.width - end -end - -local function layers_2visible(spr) - for i,layer in ipairs(spr.layers) do - layer.isVisible = true - end -end - -local function layers_visible2tilemap(spr) - for i,layer in ipairs(spr.layers) do - if layer.isVisible then - app.command.ConvertLayer{["to"]="tilemap"} - end - end -end - - -local function layers_getName(layers,name) - local out - for i,layer in ipairs(layers) do - if (layers[i].name == name) then - out = layers[i] - break - end - end - return out -end - -layers_tilemap_duplicate(spr) -layers_visible_flatten(spr) -layers_visible2tilemap(spr) - -local lay = layers_getName(spr.layers,"Flattened") -app.activeLayer = lay -if lay.isTilemap then - local tileset = lay.tileset - local spec = spr.spec - local grid = tileset.grid - local size = grid.tileSize - local row_len = 256 / size.width - spec.width = 256 - local col_len = math.ceil(#tileset / row_len) - spec.height = size.height * col_len - local image = Image(spec) - image:clear() - - for i = 0,row_len-1 do - for j = 0, col_len do - local current = i + j* row_len - if (current < #tileset) then - local tile = tileset:getTile(current) - image:drawImage(tile, i*size.width, j*size.height) - end - end - end - local path = fs.joinPath(output_folder, app.fs.fileTitle(spr.filename) .. ".png") - image:saveAs(path) -end -app.command.RemoveLayer() -layers_2visible(spr) diff --git a/tools/guide.org b/tools/guide.org index b2bdc50..7a0efd9 100644 --- a/tools/guide.org +++ b/tools/guide.org @@ -30,6 +30,8 @@ To run any scripts with this venv, run ~./tools/venv/bin/python * Generating a character sprite 8x8 tileset and mappings +** Exporting tilemap and tileset + For characters, we need to use the Aseprite tool for building sprites. Import the character's sprites as a sprite sheet and into an .aseprite file (see @@ -40,13 +42,42 @@ layer, with 8x8 tiles. Plus, you'll have to organize the frames in such a way that frames of the same animation are coupled together. Finally, group frames into animations by creating tags with animation names -(again, see 'SONIC.aseprite' for valid animation names). +(again, see 'SONIC.ase' for valid animation names). -Finally, export the animation names and mappings using 'export_tilemap_psx.lua', -then export the player tileset using 'export_tileset_psx.lua'. +Finally, export the animation names and mappings using 'export_tilemap_psx.lua'. + +Now to export the tileset itself, you'll need to File > Export > Export +Tileset. On this window, choose the following options: + +- Sheet Type: By Rows; +- Constraints: Fixed Width; +- Merge Duplicates: Yes; +- Borders + - Spacing: 1; +- Output + - Output File: SONIC.png. + +[[file:sprite_export_settings.png]] This will create a 'SONIC.png' file and a 'SONIC.json' file. +** Tweaking the texture + +This is not over yet -- You'll need to open up SONIC.png on a tool such as GIMP +and guarantee that no individual tile is being divided by the 256px line at the +bottom of the image. + +If so, you'll need to take the row of tiles that is being cut in half and move +it downwards so the first pixel in Y coordinate aligns with position 256. + +This is necessary since these tiles need to be within a 256x256 texture, and +when they can't, we simply snap them to the next texture page (in this case, at +the bottom). So the sprites use four texture pages (two horizontally since it +uses 8bpp color, and other two on the bottom of VRAM since they don't fit in a +single row), but the same CLUT. + +** Produce a TIM texture and a CHARA file + Now, just pack the frame and tile data into a CHARA file, and generate a TIM image with correct CLUT and TPAGE info: @@ -59,7 +90,9 @@ Notice that, different than other image tile data, character sprites rely on a PNG's alpha channel to generate transparency bits, instead of using the full black color as mask. -NOTE: If you need to refer to an animation directly by name, the animations are +** Animation names and generating their Adler32 hashes + +If you need to refer to an animation directly by name, the animations are referred to by the engine by their Adler32 hash, so you might want to add a new definition for that on ~player.c~. diff --git a/tools/sprite_export_settings.png b/tools/sprite_export_settings.png new file mode 100644 index 0000000..9281809 Binary files /dev/null and b/tools/sprite_export_settings.png differ