Preview - Tilemapping System

Tilemapping System

Hi guys, I’ve been working on a new system for Codea 4 to make typical tile-based 2D/3D games much more pleasant to develop

Rationale

This came out of me trying to make a nice example to demonstrate how to use sprites and atlases. Making a tile-based game is a pain and involves a lot of boilerplate

Features

API

It’s still in very early development but you have a few basic parts:

  • tm namespace for all tilemapping related classes and tools
  • tm.tilesheet reusable tilesheet class
  • tm.tile individual tile, created via tilesheet:tile(name)
  • tm.tilemap the tilemap itself with all data, visuals etc
  • tm.layer a layer created with tilemap:layer(name)

There are a few other things, including a rule-based auto-tiling system which you can see in the video. Right now I only have square tilemaps but in the future will look at isometric and hexagonal support

I will probably include this and an example project in the next beta. Let me know what you think and if you have any questions / suggestions

Utilities

new camera.rigs.canvas for super easy 2D camera controls (2 finger panning and zooming with one line of code)

1 Like

Looks great. Two suggestions of common parts to include:

  1. Lighting - often useful for slow reveal of maps as they are explored
  2. Pathfinding
2 Likes

Hi West

I was thinking about both of those possible features. For lighting it depends on what sort you want since there are a few different ways of achieving this:

  • Fake additive lighting (sprites that add to the existing pixel values)
  • Actual 2D lighting (with support for normal maps and shadows) - basically normal lighting but with some adaptations to 2D
  • Fog of war using textures or vertex-colored mesh (works on top of any type of rendering)

I plan to support custom shaders for tilemapping as well so a lot of effects can be done through that

Pathfinding should be possible (probably A* with some path-smoothing)

Yes - I’ve set a light level parameter for each map tile which updates on a ray cast from the main character. I use this parameter to set the tint alpha channel for each tile. As you say, many ways to go about it and interested to hear how much you intend to provide

1 Like

Some more experiments with the tilemapping system for a Crypt of the Necrodancer style rhythm dungeon game

2 Likes

How did you manage to sync the music with the code?

I haven’t documented the new sound API but in Codea 4 when you play a sound: sound.play(asset) or sound.playBackground(asset) you get a sound instance object. You can then get/set the .time property to seek or check the current playing position of the sound. I used that to sync the gameplay instead of using time.delta or time.elapsed

There’s no long a music function, you can have multiple music tracks…

First I load the music tracks using the new sound.read() API, which works the same way for all assets

    -- sound assets provided by a student
    musicBase = sound.read(asset.documents.MusicForJohn_JP.JP_TestTrack_60BPM) 
    musicLayer1 = sound.read(asset.documents.MusicForJohn_JP.JP_TestTrack_Layer1)
    musicLayer2 = sound.read(asset.documents.MusicForJohn_JP.JP_TestTrack_Layer2)

When the game begins I set up the tracks to play in a loop but make the extra layers mute (volume 0) so they can be turned on and off when the main music track loops

    -- somewhere in game init() play multiple background tracks
    self.music = sound.playBackground(musicBase)
    self.music.loop = true
    
    self.musicLayer1 = sound.playBackground(musicLayer1)
    self.musicLayer1.loop = true
    self.musicLayer1.volume = 0
    
    self.musicLayer2 = sound.playBackground(musicLayer2)
    self.musicLayer2.loop = true
    self.musicLayer2.volume = 0

Each frame I check if the music has looped (comparing the previous music time with last frame) and turn some of the extra tracks on or off

    -- somewhere in update(), check for loops in the music and randomly turn on/off extra music track layers
    local t = self.baseTime + self.music.time
    if self.prevTime > t then
        self.baseTime = self.baseTime + musicBase.length
        t = self.baseTime + self.music.time
        self.loops = self.loops + 1
        
        if self.loops > 1 then
            self.musicLayer1.volume = math.random(0,1)
        end
        if self.loops > 2 then
            self.musicLayer2.volume = math.random(0,1)
        end
    end

The gameplay relies on some variables I calculate to do the procedural animations. It’s all based on the BPM of the song, which is 60 or one beat per second roughly

    -- calculate some useful variables for the bpm including some normalised repeating signals

    local beatTimePrev = self.prevTime % self.beatRate
    local beatTime = t % self.beatRate
    self.beatTime = beatTime
    self.beatTimeNorm = t / self.beatRate
    self.beatPercent = beatTime / self.beatRate
    self.prevTime = t

This also ties into the logic of the game itself, with a bit of an added leniency window (so you can press a button a bit after the beat happens)

    -- update game logic to the beat of the music!
    self.tickThisFrame = beatTimePrev < 0.1 and beatTime >= 0.1
    if self.tickThisFrame then
       self:tick() 
    end    
2 Likes

It looks like a very nice little tool!

Why do I click on the above video, the picture does not change anything Can anyone see the change ?

The embedded videos seem to be broken for some reason, if you click though to twitter they should work though

I got it! It looks very interesting!

And I copy it to the Youtube, Here is it:

The same vedio

1 Like

Looks like a good direction. I was wondering how tedious it would be to implement custom tile mapping, since everything has to be coded a system would definitely help out.

1 Like