Posted April 19, 2026 by BitGlint Games
The isometric scenes in Melkhior's Tower are rendered using a technique described in this article that I wrote many years ago: https://www.bitglint.co.uk/Iso/default.htm
I use the same technique for all of my isometric game projects, for the reasons described in the article.
The scene above consists of 42 entities:
That's a lot of entities to mask and draw, which would result in the poor old Playdate's CPU maxing out straight away. To get around this problem, the scene is rendered in stages, based on layer information assigned at design time in the level editor. There are 4 rendering layers, highlighted in the image below:
Layer 0 : Blue - This is the background layer. It consists of entities that will always appear under/behind any "normal" entities in the scene. They are baked onto a background bitmap once, using the same isometric rendering technique mentioned above, and then effectively thrown away. Some entities, like the skirting bricks, may leave behind physics bodies for collision checks, but their visual representation is fixed onto the background bitmap. Entities on the background layer can't be animated.
Layer 1: Green - This layer is used for entities that will always appear under/behind "normal" scene entities, but can be animated. Therefore, the game engine needs to be aware of their presence in order to update animations and refresh the sprites associated with them, so unlike entities on layer 0, they cannot be discarded. They will only be masked against other entities on the same layer, but this seldom happens because they tend to be floor objects that never move.
Layer 2: Grey - These are the "normal" game entities. They can move around, be animated, interact with each other and, most importantly, they will be masked against each other as and when appropriate. These are the "updated every frame" entities (well, not quite, see below). In the image above, you can see that of the original 42 entities in the scene, only 3 are on this layer.
Layer 3: Yellow - Similar to the background layer, but for foreground entities. No entity from other layers can ever be rendered in front of, or on top of, entities on this layer. They are baked onto a foreground bitmap once, and then discarded. As with the background entities, they may leave behind physics bodies for collision checks.
All graphics are rendered using sprites, with sprites for each layer having a different Z order. Note that within a single layer, there is no drawing order. It's not required because the entities are masked against other entities on the layer, based on their relative positions in 3D space. This is described in more detail in the article mentioned above.
Masking is also optimised. Two entities will only be considered for a mask refresh against each other if their sprite's bounding boxes overlap. In the image below, none of the 3 entities on layer 2 overlap, so unless one of those entities moves, no masks need refreshing.
Further to that, whenever an entity's mask is refreshed, the rendering engine remembers the IDs and positions of other entities masked against it. On subsequent frames, this information is recalculated and, if it hasn't changed, then a mask refresh is not required.
Applying all of the above optimisations results in a happy Playdate CPU, easily maintaining 50fps at around 25% utilisation max. The image below shows how the CPU usage changes as the player moves around, and masks need refreshing.