Making of Castle Tintagel, Part 1


Motivations

Hi, Pixelated Opus here and today I want to discuss the development process of my playdate game titled, “Castle Tintagel”. I have always been a huge fan of anything from the Medieval period. The story of King Arthur is an exciting one with the earliest of my memories being playing King Arthur & the Knights of Justice or just watching The Sword In The Stone on beta.

Growing up I was huge fan of the Castlevania and Megaman franchise. I particularly latched onto the setting of Castlevania and the notorious difficulty of Megaman. Not to say Castlevania is a walk in the park, but Megaman always felt a bit more difficult for me. I am also a huge fan of Gladiator! “Strength and honor!” 😉

So, to sum it all up. We have a story that takes place in the Arthurian world with some hints of revenge ala Gladiator and the play style of “Megamania”  

The Playdate

After seeing the Playdate, I was excited about the idea of bringing a new title in this style to the catalog of games offered. I started to write a rough design document that outlined the main beats of the game. It was scrappy, but that was fine. I was trying to establish some high-level mechanics and thinking of ways I can utilize the crank to bring some fresh new gameplay to the genre.

One thing I wanted to avoid was overusing the crank. The reason for that is simple, I still wanted this to feel like a classic platformer. The crank was meant to supplement the gameplay, but not completely replace it. I also did not want to overstimulate the player with all the various forms of input at once. The crank is usually used in places where there is no need to attack or move to evade an enemy.

Moving onto the art style. The playdate screen has a whopping 400x240px display, which is IMO amazing in terms of fidelity of such a small screen. However, because the physical screen is small, I had to experiment with different approaches to authoring art for the game. I settled on authoring everything at half the size and blowing it up by 2x. Tiles are, believe it or not 10x10px and upscaled to 20x20px and Gawain is 16*16px upscaled to 32*32px. This allows us to visualize things more clearly and retain the pixelated look. Also, it makes authoring the art simpler. 

Level Creation

Data in Castle Tintagel is mostly kept in raw LUA tables. Normally I would drive this data through some external formats (i.e XML, JSON, css) or what have you, but for this game I kept things simple.

Each level has a data table that looks something like this:

Level_1 = { 
    key = LevelKeys.Level_1,     
    hasMenuImage = true,     
    spawnPlayer = true,     
    musicKey = SoundManager.MusicKey.kMusicForest,     
    startRoomKey = RoomKeys.Room1_1, 
}

A level has a UID, and most importantly a start room key which defines the room that is created once the level is created. (Swapping the room key during development was an easy way for me to immediately test new rooms or different points throughout a level)

Level Creation in steps:

  1. Unload previous level including SFX that are no longer needed.
  2.  Spawn Player if required.
  3.  Add/Create the first room
  4.  Sound Manager loads all level SFX and stores the sample player objects
  5. HUD Manager triggers the transition
  6. Game:OnLevelCreated() is fired that sets up some player variables 

Rooms

Each room in Castle Tintagel is 400x240, 800x240 or 400*480. 1x1, 2x1 or 1x2 respectively.  Each room has a grid that defines which objects and tiles are placed/created. There is an Object Factory in the game that keeps track of all objects that are in the scene at a given time. Each object is registered via a unique key.  On room creation, the grid is traversed and if an object is registered to the factory it is spawned. If we come across a Wall tile(W*) that is suffixed by a 0, 1, 2, … n then that index is used as the lookup inside the tile map index to resolve the texture that will be used for that wall.

Sample grid:

W0

W0

W0

W0

W0

W0

 

 

 

W0

W0

 

 

 

W0

W0

 

 

 

W0

W1

W1

W1

W1

W1


Sample Tileset

Collision for wall tiles is added in a post traversal where adjacent walls are combined into 1 collider. I do this because walls are static in my game (except for some secret blocks 😉) This means that I only need 1 collider instead of 10 if 10 blocks are in the same row. 

 Snippet from object generation Logic inside the “Room” class.  ( I have a C/C++ background so the semicolons are a habit of mine)

for row = 0, numTilesHeight - 1 do         
    for col = 0, numTilesWidth - 1 do                 
        local index = (row * numTilesWidth + col) + 1;                          
        local posX = col * TILE_SIZE;             
        local posY = row * TILE_SIZE;              
        local key = grid[index];             
        if key ~= ' ' and ObjectFactory:CanCreateObject(key) then                 
            ObjectFactory:CreateObject(key, posX, posY, {roomKey = self.roomKey});             
        end         
    end     
end

I could have rolled my own full blown GUI level editor or used some 3rd party solutions, but I decided to keep things simple (you will notice me say this a lot throughout these blogs). Simplicity was the main theme for this game. This is because I tend to get so bogged down on the technical aspects of the games and overengineer solutions. I wanted to prove the concept out and find the fun fast. This solution was flexible enough and worked well for me.

There is plenty more to cover in the upcoming blog segments, so I hope you enjoy reading along and feel free to drop any questions in the chat.

Until next time! 😊

-PixelatedOpus

Get Castle Tintagel

Buy Now$8.99 USD or more

Comments

Log in with itch.io to leave a comment.

Great lil devlog!
Out of curiosity: Did you use ldtk to create the levels, or did you actually create those level layout grids by hand?

(1 edit) (+1)

Thanks! Because of the self imposed room size constraint, the grids were initially created by hand and quite manageable. I kind of rolled with it and before I knew it a level was complete(the grids are quite “small”, 20x12 for a 1x1). I decided it was sustainable for this project. However, going forward I will definitely use a 3rd party tool or roll my own GUI Level Editor. I.e if I create a sequel for the game.