A command-line utility for the creation of a wide range of ZX Spectrum assets (for Classic and Next). Spectrum Asset Maker is intended to be a one-stop shop for all your game assets.
-
Tileset Attributes - Game properties (solid, lethal, ladder, custom)
-
Path Map - an array showing exits up/down/left/right for each square. Can be used to speed up pathfinding for complex AI.
-
Object Map - object type, x, y, width, height
-
Text data
-
Blank (zeroed) data
-
Arrays of data taken from a JSON config file
-
Tilemap - tile numbers, associated with a tileset
-
Tile/Attribute Graphics
-
Tile/Attribute Colours
-
Masked/Unmasked Sprite (sp1 format)
-
.SCR file (eg. loading screen)
-
Tile/Attribute Graphics (nxt)
-
Next tilemap (nxt) - short format, 1-byte per tile
-
Next tilemap (nxt) - extended format, 2-bytes per tile (palette offset not supported yet)
-
Palette (pal) - short format, 1-byte per entry
-
Palette (pal) - extended format, 2-bytes per entry
-
Sprite (spr) - 4-bit or 8-bit format
-
Bitmap (nxi) - pixels stored in row or column order
| Type | File format expected |
|---|---|
| Tilemap | Tiled tilemap exported JSON (.tmj) |
| Tileset | Tiled tileset exported as JSON (.tsj) |
| Object types | Tiled Object Types XML file (.xml) |
| Tile/Attribute graphics | Black and white PNG or GIF (PNG recommended) |
| Next Tile/Attribute graphics | Indexed PNG or GIF (PNG recommended) |
| Next Palette | Indexed PNG or GIF (PNG recommended) |
| Classic Sprite | Black and white PNG or GIF (PNG recommended) |
| Classic Sprite Mask | Black and white PNG or GIF (PNG recommended) |
| Next Sprite | Indexed PNG or GIF (PNG recommended) |
| Text | Plain text file |
| Classic SCR | PNG file, 256 pixels by 192 pixels |
| Next Layer2 screen | Indexed PNG file, 256 pixels by 192 pixels |
Install PHP with your favourite package manager:
Mac with Homebrew:
brew install php
Linux - Debian/Ubuntu/Mint:
sudo apt install php
Linux - Fedora/RedHat:
sudo dnf install -y php
Windows/Mac without Homebrew:
(use installer from PHP.net)
Command line bash script:
./makeassets --config=[path to JSON config file]
Command line PHP script:
php SpectrumAssetMaker.php --config=[path to JSON config file]
All assets associated with a project with a project - sprites, tilemaps, graphics etc - are specified in the JSON config file. These are created in one pass, simplifying the build process.
Choose which sections to process (comma-separated)
Example:
php SpectrumAssetMaker.php --config=config-assets.json --section=sprite
Choose individual items to process by name (comma-separated)
Example:
php SpectrumAssetMaker.php --config=config-assets.json --name=font
Here is an example JSON configuration file to create a large set of game assets. The settings are explained in more detail below.
{
"settings": {
"create-assets-list": true,
"naming": "underscores",
"output-folder": "./assets",
"object-types": "raw-assets/objects/objecttypes.xml"
},
"blank-data": [{
"name": "level-tilemap",
"size": 2208,
"output-folder": "./assets/blank-data"
}],
"graphics": [{
"name": "font",
"input": "raw-assets/fonts/nice-font.png",
"paper-colour": "white",
"output-folder": "./assets",
"section": "BANK_0"
}],
"palette-next": [{
"name": "next-font",
"input": "raw-assets/fonts/nice-font.png",
"output-folder": "./assets",
"format": "binary",
"binary-format": "1-byte"
},
{
"name": "next-font",
"input": "raw-assets/fonts/nice-font.png",
"output-folder": "./assets",
"format": "binary",
"binary-format": "2-byte",
"create-binary-reference-file": false
},
{
"name": "next-font-for-reference",
"input": "raw-assets/fonts/lander-bold-next.png",
"output-folder": "./assets/reference-asm",
"format": "asm",
"binary-format": "1-byte"
"add-to-assets-list": false,
}
],
"screen": [
{
"name": "loading-screen",
"input": "raw-assets/loading-screen.png",
"output-folder": "./assets"
}
],
"bitmap-next": [
{
"name": "background-screen",
"input": "raw-assets/background-screen.png",
"output-folder": "./assets",
"bank": 30
}
],
"sprite": [
{
"name": "player-sprite",
"input": "raw-assets/sprites/player-sprite.png",
"mask": "raw-assets/sprites/player-sprite-mask.png",
"paper-colour": "black",
"output-folder": "./assets/sprites",
"section": "BANK_0"
}],
"sprite-next": [
{
"name": "player-sprite",
"input": "raw-assets/sprites/player-sprite.png",
"output-folder": "./assets/sprites",
"format": "binary",
"binary-format": "4-bit"
},
{
"name": "enemy-sprite",
"input": "raw-assets/sprites/player-sprite.png",
"output-folder": "./assets/sprites",
"format": "binary",
"binary-format": "8-bit"
}],
"text": [{
"name": "intro-text",
"input": "raw-assets/intro.txt",
"output-folder": "./assets/text",
"section": "BANK_0"
}],
"tile-graphics-next": [{
"name": "next-font",
"input": "raw-assets/fonts/game-tileset.png",
"output-folder": "./assets",
"format": "binary"
},
"tilemap": [{
"map": "raw-assets/tilemaps/screens.tmj",
"output-folder": "./assets/levels",
"use-layer-names": true,
"generate-paths": true,
"path-width": 2,
"path-height": 2,
"path-map-style": "platform",
"format": "asm",
"compression": "rle",
"ignore-hidden-layers": false,
"section": "BANK_6",
"tileset": {
"name": "game-tiles",
"tileset": "raw-assets/tilesets/game-tileset.tsj",
"output-folder": "./assets/tilesets",
"replace-flash-with-solid": true,
"section": "BANK_4",
"custom-properties": {
"colours": true,
"properties": [
"solid",
"lethal",
{
"name": "prettiness",
"length": 6
}
]
}
}
}],
"tileset": [{
"name": "menu-tiles",
"tileset": "raw-assets/main-menu/menu-tiles.tsj",
"output-folder": "./assets/main-menu",
"section": "BANK_4"
}]]
}If the 'create-assets-list' setting is used, the tool will create an 'assets.lst' file in the specified output folder containing file-paths for all the generated assets. You can add this file to your project settings with '@output-folder/assets.lst' to include the assets as part of your build.
You can exclude individual assets from the LST file using by setting 'add-to-assets-list' to false in the asset's JSON section.
Supported values:
-
true (create assets.lst file)
-
[filename] (create assets list with custom filename)
-
false (don't create lst file)
You can set the format of variable names to match your coding style. Iinclude the "settings/naming" field in your JSON. Options are:
-
camelcase (default)
-
underscores
-
titlecase
Set how the Next screen is laid out, either as 3 rows (for 256x192 resolution) or 5 columns (for 320x256 or 640x256 resolution).
-
rows (default)
-
columns
Input file to use
Where to save the generated asset(s)
Out to a specific filename, overriding auto-generated filename.
Format to save data as, usually assembly or as binary file.
-
asm (default)
-
binary
-
c
Some Spectrum Next assets can be stored in different binary formats, eg. palettes can be 1 or 2 bytes per colour, and sprites can be 4-bit or 8-bit per-pixel. This is set using the 'binary-format' option (see example JSON for usage)
By default, Spectrum Asset Maker creates an asm file pointing to the binary that you can use in your C program, for example:
section rodata_user
public _bandit
public _bandit_end
_bandit:
BINARY "./binary/generated/bandit.spr" ; 128 bytes
_bandit_end:
If this is unwanted (if you're using Next or Boriel BASIC for example), you can disable this on a per asset-basis by setting 'create-binary-reference-file' to false (see example JSON)
Code/memory section to save the asm to (eg. "rodata_section", "PAGE_80", "BANK_20")
Alternative to 'section' setting - set memory bank by number
Alternative to 'section' setting - set memory page by number
Set the compression format to use (see README section on Compression). Default is no compression.
-
rle
-
zx0 (binary only)
For Next bitmaps. Override the global "next-screen-format" setting to save by columns or rows.
-
rows
-
columns
For classic Spectrum sprites. Set which colour to use for PAPER. Anything else will be taken as INK.
For classic Spectrum sprites. Specify a path to an image to use as the sprite mask.
ignore-hidden-layers
For tilemaps. Set to true to skip importing hidden tile layers. Default is false.
If 'layer-type' is set to 'all' (default) or 'tilelayer', the tool will create code for each tilemap layer. The tool will include hidden layers unless "ignore-hidden-layers" is set to true.
The destination code name is built from the folder and layer names in Tiled and respects the global "naming" setting. For example, take the following structure in Tiled:
(folder) level-1
|_____ (tilelayer) layout
|______(objectmap) enemies
|______(objectmap) collectables
This will create the following asm resources. With "naming" set to "underscores":
level_1_layout
level_1_enemies
level_1_colletables
With "naming" set to "camelcase":
level1Layout
level1Enemies
level1Collectables
With "naming" set to "titlecase":
Level1Layout
Level1Enemies
Level1Collectables
By default, Spectrum Asset Maker will output the attributes as a byte in the usual Spectrum format attribute (F,B,P3,P2,P1,I3,I2,I1).
Add the following properties to the individual tile in Tiled:
-
flash (boolean)
-
bright (boolean)
-
paper (number 0-7)
-
ink (number 0-7)
-
solid (boolean)
You can customise what is saved by adding a "tile-properties" section to the tileset config JSON. This allows you to create as many 8-bit arrays of properties as you like.
In the example below, we've modified the 'colours' array to replace 'flash' with 'solid' and added a second array with 4 boolean properties (unbreakable, lethal, ladder, water) and a 4-bit integer property (rating):
"tileset-properties": [
{
"name": "game-tiles",
"tileset": "raw-assets/bean-bros.tsj",
"output-folder": "./binary/generated-asm",
"format": "asm",
"custom-properties": {
"colours": [
"solid",
"bright",
{
"name": "paper",
"length": 3
},
{
"name": "ink",
"length": 3
}
],
"my-properties": [
"unbreakable",
"lethal",
"ladder",
"water",
{
"name" : "rating",
"length" : 4
}
]
}
}You can disable the 'colours' array like this:
"custom-properties": {
"colours": false,
"my-properties": [
...
]
}Or you can add a second array of properties but leave the 'colours' array as default:
"custom-properties": {
"colours": true,
"my-properties": [
...
]
}The resulting arrays for 'tilesetMine' and 'tilesetJungle' would be named in code like this (where "naming" is set to "camelcase"):
tilesetMineColours
tilesetMineMyProperties
tilesetJungleColours
tilesetJungleMyProperties
Note: Each tile in the tileset MUST have at least one property set, even if not used by Spectrum Asset Maker, otherwise Tiled won't include it in the exported JSON and you'll end up with missing tiles and errors.
Note 2: At the moment each tile slot uses a full 8-bits, potentialy wasting bits. In future it should be possible to combile multiple tiles into a single byte.
'Path maps' can be pre-generated which helps speed up movement calculations in some situations. The feature was created to speed up enemy AI in my game Gilligan's Mine.
This will create a byte for each square on the map that specifies which directions a player/character may move from that square.
This feature requires 'solid' (true/false) and optionally 'ladder' (true/false) properties to be set on tileset tiles in Tiled.
The path-width and path-height settings are used to specify how many tiles wide/high the gap needs to be to fit through.
The 'path-map-style' property changes navigation style. There are two options:
-
platform - character can only move up and down if the tiles have 'ladder' set to true.
-
overhead - character can move in all 4 directions if there's a space
The byte format of a square in the path map is as follows:
[0][0][0][0][up][down][left][right]
For example, a square with exits in all 4 directions would be represented as:
00001111
If 'layer-type' is set to 'all' (default) or 'objectgroup', the tool will create code for each objectgroup layer.
To add the width & height of objects, add a boolean 'add-dimensions' property to the appropriate layer and set to 'true'.
Data is saved in the following order:
- object type ID (optional, see below)
- row
- col
- width (optional)
- height (optional)
You can map object types in Tiled to an ID that can be used in code. This will be saved as the first value in the code. To do this, you must define each object type in Tiled's Object Types Editor and give each object a unique 'index' custom value.
Export the objecttypes.xml and specify the path using the --object-types parameter.
1 byte for tilenum, 1 byte for run-length.
The data will be preceded by 2 bytes specifying the array length (hi/lo). This will appear after rows and columns if 'add-dimensions' is specified.
You can set 'compression' to 'zx0' to compress a generated binary file using ZX0. This still needs to be fully tested.