Categories
Blog Development Teratree

PRISM: A library to simulate the ZX Spectrum display in LÖVE

I’ve done some refactoring and separated my display code into a simple library called PRISM. I’ll think of a funny backronym some day but it’s in reference to the Spectrum logo.

In a previous blog I talked about how I’m rendering the sprites to the screen. Since then I have added a way to dynamically rotate the sprites and to simulate the border and Attribute Clash of these old display methods.

Colour Clash

The displays of the early 8-bit machines often could only manage 2 colours per 8×8 pixel cell, so if 2 sprites overlapped the colours would change depending on which sprite was drawn last. There may be a better way to make this work but here is my method.

I have 3 canvases; paper, ink and sprite. Each are 256×192 pixels, the resolution of the original Spectrum display. When the sprite function is called it draws an 8×8 rectangle of the paper and ink colours to their respective canvas. Then the sprite itself is drawn in monochrome to the sprite canvas.

When the PRISM draw function is called it sets a custom shader I made and passes the ink and paper canvases to it before drawing the sprite canvas. The shader simply checks each sprite pixel and returns the colour of the same pixel from the ink canvas if the sprite pixel is white and the paper pixel colour if the sprite pixel is black.

It runs fine on my PC but I feel it needs a lot of optimization before it runs ok on mobile.

Download

You can grab my current version here. Zlib licence (same as LÖVE). Inside is a main.lua which runs the demo in the video above.

Categories
Blog Development Teratree

Editor coming together

I’ve been working on my level editor for Teratree. The video above will give you the basic idea of how it works.

All the world data is saved in one big nested table.

world
    name
    author
    cells
        room
            name
            tiles
                tile
                    name
                    ink
                    paper
                    bright
                    cells
                        sprites
            cells
                block
                    celltype
                    health

Each table called cells is a 2d array, the rooms in the world, blocks in the room and pixels in the sprites are all handled in the same way.

Currently the world table gets dumped to a lua file using this library but it’s not very human readable. I may work on a custom exporter when I’m happy with the format of the table.

Since the video I’ve added the ability to change the text like the room names and given the tiles multiple sprites for animation. I’ve had to start on a menu/ui module to make things easier to build buttons and text inputs. More on that another time.

Categories
Blog Development Teratree

Sprites and Strings

It took me a while to decide where to start with this refactoring of my code. In the end I decided to work on display stuff. I need a way to draw my game in a ZX Spectrum style.

Display

The display of the ZX Spectrum was 256×192 with a border to fill the rest of the screen. I want to keep that resolution but have it scale to the window size.

function display:scale()
    local winx,winy = love.window.getMode()
    local xres, yres = 256, 192
    
    local xscale = winx/xres
    local yscale = winy/yres
    local transx, transy = 0,0
    
    if yscale*xres > winx then
        scale=xscale
        transx, transy = 0, winy/2 - (yres*scale)/2
    else
        scale=yscale
        transx, transy = winx/2 - (xres*scale)/2, 0
    end
    love.graphics.translate(transx, transy)
    love.graphics.scale(scale)
end

I run this at the start of the draw callback and, no matter what size or orientation, the play area scales to the shorter dimension and center on the longer. I may adjust the scale slightly if I want to have a border on all sides but this works for now.

teratree-scaling

Sprites

LOVE can of course draw image files on the screen but I decided I wanted my game to handle sprites in the program. Each sprite will be a 2-dimensional array of bits and when it is drawn you give it the colour of “paper” and “ink”.

ZX Spectrum Colours
ZX Spectrum Colours

The Spectrum has 8 colours, each with a dark or bright variant. I’m using the number to indicate the colour I want and another bit to indicate the “bright” variant. To make this work with LOVE’s setColor function, I do a simple function to convert the number I have into an array of RGB values.

if bright == 1 then
            value = 255
        else
            value = 215
        end
    
        if number == 1 then
            colour = {0,0,value}
        elseif number == 2 then... etc

return colour

Next I parse the 2d array sprite I want to draw. For each pixel I use love.graphics.rectangle to draw a 1×1 square. To save drawing every single pixel I draw a rectangle the size of the sprite with the “paper” colour and then just draw individual pixels for the “ink”.

Test sprites

I want to do some kind of “colour-clash” mode but I’ll probably have to do some kind of shader for that. For now I need to allow a moving sprite to not draw it’s “paper” over the background. If the colour number for the paper is not 0-7, the “paper” rectangle isn’t drawn.

Transparent "paper"

Strings

The final thing today is writing strings with a sprite font. I already had a version of the Spectrum font as binary arrays from the last time I worked on this. I had used a Python PNG library to convert an image of the font into bits. Lots of trial and error on my part. Once I had these sprites I put them into a dictionary list, named for each character. All that was needed then was to take whichever string I wanted, split it using gmatch”.” and printing the corresponding sprite to the screen for each character.

Hello World!

I was missing an exclamation mark… fixed now.

Categories
Blog Development Teratree

Start of Devblog for Teratree: a Miner Willy engine clone.

This year I have started this project 3 times, each time realizing a better way to do it as I learn to use Lua and LÖVE.

I am about to start again, refactoring everything to keep the code clean an expandable. Will I succeed this time? We shall see.

The dream is to have the main project executable standalone with a menu that can load levels, edit worlds and sprites and play the games. All that will be nice and open source, as will any games I make myself with the engine. I will be making versions of MM and JSW too, if nothing else to make sure the engine feels right.

Here are some videos of previous attempts: