Scapia - dev log

Scapia

We are working on a puzzle adventure game called Scapia. It takes place in a magical-medieval world with many areas for the player to explore. What started as a text-based choose-your-own-adventure game for my girlfriend is now a few months into production as a fully graphical Playdate game. I'm coding, she's doing the art. It's been a fun project with a huge learning curve for both of us.

We're excited to share our work so far! This is the first game we've made, so we're looking for feedback! Whether you have some advice or just a quick opinion to offer, we are grateful for your thoughts in the replies.

I'd like to highlight a few of my favorite features to start, and plan to go into more details on how these work in future posts. Progress will also be posted, as we are working on the game daily.


dialogue

In this game, conversation is key. You can talk to people to learn about the world and progress the story.

This gif (below) where the player is talking to their brother shows how conversations are tracked independently. You can have many 'active' conversations with an NPC, and freely choose between them.

It also demonstrates side-scrolling text for longer player dialogue options. The scrolling here and in the next gif were not built-in Playdate functions, and were fun to write.

dante_long_talk


In this gif (below) is shown more dialogue, but with Dad this time, and showing the vertical scrolling associated with longer NPC phrases. I truncate with "..." indicating to the player it's a longer text than shown, and give the player a couple seconds to start reading the dialogue before scrolling.

dad_talk


puzzles

In addition to dialogue, another key component of the game is the puzzling. I have an invisible tile system which tracks where things are in 20x20 pixel "tiles." These are used for puzzle logic, as well as for placing the pieces that make up the various puzzles.

"a chicken? huh?"

This gif (below) shows how the player can walk up to a statue, press B to toggle grabbing the statue, and move it around.

  • The player can only push or pull in the direction they're facing.
  • Moving orthogonally disengages the hold on the piece.

puz_simple


mirrors

Thematically and literally this game has a lot to do with reflection.

  • Mirrors reflect the player at a 90 degree angle across the map.
  • Your reflection can do certain things you cannot, such as pass over small terrain that can't be walked over normally.

This gif (below) shows the most basic properties of reflection.

mirror_demo_02


coins

This gif (below) shows how:

  • the player can aim and toss a "coin" on the ground.
  • If the player's reflection ends up on top of that coin, the player can then teleport to the reflection.

This can be used to get the player over the aforementioned un-walkable terrain, and has other uses.

tele_04


Thank you for reading my first post about this game! I'm looking forward to posting more, and hearing your feedback. I'm excited to get back into the code after a short break, during which I graduated school.


testing... testing... 1, 2, 3...

I also do not have a Playdate yet, though I expect to get one in this latest rollout (group 4). If anyone is interested in testing this for us, we'd be happy to send playable versions to you! I will include a pdx in a post soon so anyone on here can try it out and let me know what they think. Again thank you so much for reading, and thanks Panic for making the Playdate.

10 Likes

Neat conversation system! The font immediately made me think of Diamond on Amiga. Nice and big and readable!

FWIW, single-pixel lines cam often get lost on hardware, especially when the light isn't really bright. The Playdate screen is tiny! So the Simulator can be misleading in that regard. Sometimes just repeating the same art 4x to double the lines is a help.

(For example, that bird-statue is probably a lot more visible on hardware than the player character is.)

1 Like

really glad to hear that about the text, was wondering if the size was right. and with the conversation system I want to make a poor-man's Ink

thank you for the info about the single-pixel lines. I think we're going to make the main character art more salient, and this helps guide that. everything i've learned abt the playdate says "make it big" lol

1 Like

This looks cool, especially that mirror/reflection mechanic!

With the vertical scrolling text, it'd be more accessible to have that auto-advance as an option but also allow the player to advance the text manually at their own reading speed. It'd be equally annoying to miss the start of a conversation because it started scrolling too fast as it would to be reading ahead and constantly waiting for the scroll to catch up.

You might also consider not scrolling beyond the end of the text (both vertically and horizontally). There's no need to keep scrolling as nothing more is coming in to view, only moving out of it, and it delays the text scroll restarting. Especially on the horizontal text options I wouldn't want to be waiting for the entire line of text to disappear before it resets just so I can read the first word I missed, for example!

1 Like

While I'm pretty happy with how dialogue is starting to look, there are some obvious improvements to the dialogue that can be made.

  • Scrolling should be as player-controlled as possible.
    People read all kinds of ways, I was likely overthinking it by trying to average it out.

  • single-button scroll reset

  • considering pagination vs scrolling, which is kinder to the player?

I want to make dialogue as user-friendly as possible,
I really appreciate the thoughts and suggestions @orkn :pray:

2 Likes

Anecdotally I'd say pagination is much more common than scrolling, but it's maybe as much an aesthetic choice as it is practical and the look you have is pretty cool. This being a playdate game my mind immediately jumps to scrolling text (optionally) using the crank, which sounds kind of fun!

Anyway I don't mean to get you unduly hung up on dialogue, I look forward to seeing more of the game in general :slight_smile:

It's been a while since my last post, but I'm back with some exciting updates on my game for the Playdate! I finally got my hands on the device, and I must say, it's absolutely amazing. I've been glued to the screen, playing Bomber Panda endlessly.

lene_guard

As much as I want to bask in the joy of having the Playdate, I've encountered a critical error that's been causing some headaches. When I side load my game onto the device, it crashes after just a minute or two of gameplay. Even with sim settings (throttled and 16mb) I'm not crashing on my laptop.

My immediate goal is to tackle this memory problem head-on. To do that, I'm planning to reduce the number of sprites and active elements in memory. Additionally, I'm considering offloading some of the assets to storage, which can be retrieved as needed. This approach should help avoid overloading the memory and hopefully make the game run smoothly on the Playdate.

I've come up with an idea that involves loading the current room's elements as well as adjacent rooms' elements. By doing this, I aim to enable seamless movement of the player between rooms without maxing out the device's memory.

However, debugging device-only crashes has proven to be quite challenging. I could use some help from those who have experience in this area. If any of you have faced similar issues or have insights on how to effectively debug Playdate-specific crashes, I would greatly appreciate any pointers or advice.

arilys-gif-32-72

Currently, I have some debug code in place, which I know I should remove before shipping. This code allows me to open a text file using pd.file.open("debug.txt", pd.file.kFileWrite), where I write debug output. The best part is that this information persists in storage through crashes, unlike console logs, which are not available on the device or after a hard crash in the simulator. If this is not a memory issue and could potentially be a segmentation fault or something similar, I'm hoping that tracking it down using this method might be the key.

Thank you all for your support and insights. Developing for the Playdate has been an exciting journey, and I can't wait to share more progress and updates with you all soon.

guard-32-72

1 Like

Major Audio Issues

So while I am in the process of rewriting the game from the ground-up, I am running the game on-device much more often. I have found that the SDK audio library is much more capable in the simulator vs on the playdate.

I want to design really dreamy, fantasy-inducing synths. But the device crashes when even just a small handful of effects are used on a single audio channel. I played with this for hours yesterday and could not get a (imo, lightly) effected channel to play on the playdate without insta-crashing.

Remedies I'm considering

  • using recorded audio (as much as i'd rather use synths)
  • somehow utilizing coroutines to reduce CPU time for audio functions
  • shaving my head and becoming a monk with no technology
  • drinking more coffee, and just trying different things out

Post Desperately Seeking Answers

Here is a post about it I made to try to get some feedback on my process and other people's experiences.

Audio Bug Resolved

Bug fix implemented on Panic's side, (more info in the SDK Get Help post linked above) so I'm just waiting for that to see how far I can really push the effects. I love the synth tones, and the effects really bring them to life. Stoked to work more on the soundscape of my game. I've experimented with making nature sounds (much of my game takes place outside in a forest), and found myself listening closely to my surroundings for this project.

Songs and Playlists

I'm working on the structure of the music and music playing functionality in my game. Music is so important to a player experience. For my game, everything will be "playlists." This seems to be the most intuitive way for me to deal with music. Playlists will allow me to regionalize music in my game. IE: when you're in the country, you'll hear the country music.

Edge cases such as interrupts for special event-triggered music will be interesting but ultimately trivial I think. They will also be playlists, just of one song.

This allows me to loop, shuffle, or otherwise curate the music a player hears based on various world events. Songs can be discovered, or unlocked, and added to playlists to make the soundscape more rich as the game progresses.

1 Like

Just a reminder that you don't need to wait for the bug fix to be pushed out by Panic. dave mentioned a workaround you can use:

A workaround for now is to drop the local when you create an effect that gets added to a channel.

So if I understand dave correctly that means you just need to ensure any effect is available globally in some form. So you could also just add them to some global table to keep them referenced. Example change to your music_player.lua file:

local song_library = {}
local playlist_library = {}
effects_library = {} -- no "local" to make sure the workaround works

-- then when creating your effects
local bitcrush = sfx.bitcrusher.new()
table.insert(effects_library, bitcrush) -- this makes sure there always is a global reference to the effect
1 Like

an effect library might be a good idea regardless. hadn't thought of that, I've just been making them as needed for each song.

@NPException thanks! :pray:

Check In

Who would have thought a complete rewrite from scratch would take a while?

Okay so life stuff has kept me super busy. In addition to that, I discourage myself by thinking that devlog posts need to be these huge cool advertisements for my game. They don't! They don't need to be anything in particular. I think if I can let go of that undo pressure, then I'll post more frequently instead of ... never.

General ReWrite Ranting

So far the rewrite is going well! @trotopype and I have been diligently re-implementing things in smarter ways. I believe a big issue in our last version was that we were running through too many loops every frame. For instance - we have 240 tiles on the screen. We were running through each of these every frame to detect the tile which the player currently occupies. That's super inefficient, @trotopype is working on the more efficient version of that currently.

All rooms (73 so far) existed in memory at all times. This was a huge issue and I think throttled RAM like crazy. So I'm currently working on saving and loading rooms from disk. I don't want the player to have to wait for rooms to load, so I'll have to be somewhat smart about pre-loading adjacent rooms, but the system is working so far.

The music player is working more or less as expected. I do have some technical debt in that all my songs exist in memory - and should have a way to save/load from disk. I want a large variety of songs to help set the setting for each different region in the game.


New Features Implemented

We got narration working. Whereas previously all text was associated with an NPC, now I can trigger free-floating narration as needed. This will be cool for everything from story exposition to interacting with in-game objects that require a bit of explanation.

We have implemented a custom update function to run in tandem with the pd.update function. this allows me to easily add functions that I want to run every frame - with a queue and dequeue system that makes for a smooth developing experience.


Sign off

I will try to come back and update more frequently. We're having a good time making the game, want it to be high quality, and are not in a huge hurry to finish it. It's about the journey, as they say.

PS

WOW it's almost been a year since starting this devlog. That's crazy lol. And I think the game was in development on Playdate for nearly a year before that. Not to mention that the game started as a C++ terminal text-based game in 2021. Holy ****. I don't want to ramble too much but it is crazy that I am now a few months from marrying the person that I made that original C++ game for, and she's now making the art for this Playdate version of it. Time not only flies, it blasts forward like an everlasting explosion.

2 Likes

Music Works Differently Now

So I used to just load up all my songs with custom sequence-building functions. The problem was two-fold.

  • All these songs shared an effect library, which became very precarious to upkeep.
  • All the songs existed in memory in their full form at all times

Solution has been to create JSON files containing all the necessary data to spin up instruments and effects on the fly. A function now loads up a sequence based on the associated JSON file, and thus only ONE song has to be in memory at a time.

This allows me to have an arbitrary amount of songs and not blow up into the RAM space. Also, not having more than one sequence loaded at a time I just create new effects as needed, because they can safely be discarded after use. This got rid of a handful of effect-library problems actually.

Doors Again

So after months of rewrite, doors finally function again. There are two types of doors we're working on. Pass-through and manual. Manual you have to press a button to use, pass-through you just walk through and it takes you to the next place.

I'm not super excited with how they work at the moment however. Because of how we do our walking/input handling the player is totally reset after entering a room. Meaning, they have to press an arrow key again to start walking again. I'd like them to just continue, wouldn't you? So we'll fix that.

The Call of the Yerb

I'm two coffee's deep into the day and I'm hearing the call of the yerba mate I've got stashed in my office mate's mini-fridge. Do I drink it? And potentially ruin the evening with a crash? But in the meantime, I'd be an email and coding god. Or do I just get some water. These are the questions that plague me at 2:33PM on a Wednesday.

2 Likes

I should add that I'm really excited for people to hear the music in this game. I think it will be a big part of the experience. Each region will have its own playlist of tracks that the player will explore, solve puzzles, and talk to NPCs to.

1 Like

Auras

I've decided to call the space around things wherein the player can interact will be called auras. For objects with an aura, it will most often be used to trigger narration - working like the familiar 'examine' button from lots of games.

With NPCs it will allow the player to trigger dialogue.

I couldn't find any built-in way to detect when a collision is no longer happening, so once the player enters the aura a timer is set off where every 0.75 seconds I check if the player is still occupying (colliding with) the aura.

Now to attach narration to things!

Autosave and Doors

When the player picks up or moves an object, this is now saved to disk upon exiting the room.

Writing

Also - this kendrick drake beef is wild. it could go very deep, but regardless it's gotta me relistening to kendrick's discography with freshly perked ears. it's really amazing how good of a writer he is. he's always speaking on multiple levels. He makes video game references that often go unseen.

With narration and dialogue starting to really work and do things (affect states in the game, allow for choices, etc) I am really looking forward to fleshing out the story. The story exists - but the literal dialogue needs to be written.

New Games

been playing Spelunkey 2, super super super good game. i have not gotten far at all but it's fun.

excited for Braid anniversary. really looking forward to my first playthrough of the game.

1 Like

Reflection & Teleportation

Things are moving along swimmingly. Again, art updates forthcoming, so forgive the static player image.

The video below shows teleportation working. And you might be thinking, wasn't teleportation working in the previous build of the game? Well, yes. But it would only work in the Simulator. When attempted on the Playdate it would crash without fail.

This time around I'm being much more straight-forward and efficient with calculating all the necessary values. For example, I believe last time around I was iterating through all 240 tiles every frame, searching for the player. Now, the player's occupied tile updates efficiently with player movement - thanks to code from @trotopype.

I Fixed Dialogue

Also - the ever-complicated custom dialogue system is coming along. I am now able to dynamically navigate conversations. My custom dialogue files look like this:

dialogue

  • the text at the top is something an NPC will say
  • text in quotes ("") are choices the player can choose from
  • * asterisks indicate a condition which must be met for the choice to display
  • $ dollar signs indicate an outcome of selecting that choice
  • > an angled bracket like this indicates the next node to travel to
    • this can be either:
      • just the node ID to stay in the current conversation
      • a new conversation topic and the node ID to go to within that convo

Here is a video of dialogue working as-intended. There are known issues with it - but the basic mechanics are what I'm focusing on at the moment.
The below video show a couple things:

  • In the first narration - the player examines the family vase
  • upon revisiting the vase (re-engaging in the narration) there are new options. this is due to an outcome of having read about the vase.
  • when talking to the NPC the player ends the conversation abruptly the first time
  • the second conversation with the NPC the player selects a choice which leads to more dialogue - a new topic.

Thoughts

There's a lot to fix. This last week we've added a lot to the game and that all needs to be refactored and improved. Things like basics of how text is displayed and how fast the player moves and all that fun stuff are on the workbench right now. I'm just so happy to have these features working AND WORKING ON-DEVICE.

3 Likes

Nice job, a dialogue-data parser is always a fun topic!

Do the variables in the dialogue become standard Lua variables that you could read/write from non-dialogue scripts? It seems cool either way - I guess the has_reflected value looks like something which would get set to true outside of dialogue...

Also, how's that syntax highlighting work in that screenshot of the text editor? Is it playing off of the highlighting for some existing format (markdown or something?) or did you set up your own highlighting rules?

Thank you, yeah dialogue has been a fun undertaking.

So yes, the variables such as conditions and outcomes do become standard Lua variables. I then have a file of "states" which I save/load needed. That file looks like this:

{
  "is_curious_about_inn":true,
  "knows_about_vase":true,
  "test_outcome_01":true
}

So yes, the conditions do expect that the variable has been set somewhere else. Most often this will happen as an outcome of a dialogue choice - but I want outcomes to come from gameplay as well.

The syntax highlighting is custom. I followed a couple blog posts about how to set it up. It isn't necessary but makes writing dialogue more pleasant. Originally I was writing all the dialogue in a spreadsheet and that was miserable.

1 Like