Starting a Text Adventure in Corona SDK


I was looking at the “Choose your Adventure” type games on the Play Store, and wondered how it would be to do something like that in Corona.

A couple of strategies that present themselves as obvious, might be: one, using composer where each choice goes to a different scene. That would end up being a lot of Lua files! Another way might be saving the content into a file or files, and reading them in for choices, but that would add a lot of extra work. The route I chose to go was to use sqlite3 for the data store.

Below is the basic schema to get things off the ground:


CREATE TABLE "rooms" ( 
    `id` INTEGER PRIMARY KEY AUTOINCREMENT, 
    `content` TEXT, 
    `location` TEXT )

Content will be the text in the story, and its corresponding location will be saved in the field with that same name.

The story will be told in a single composer scene. As the user makes choices, the content will be fed into that same scene.

Here’s a basic screen:

screen shot 2019-01-13 at 9.59.14 pm

 Focusing solely on moving the content in and out using sqlite3, here is some code:


local sqlite3       = require( "sqlite3" )

-- include Corona's "widget" library
local widget        = require "widget"

local dbpath        = system.pathForFile( "data.db" )
local db            = sqlite3.open( dbpath )
local txt, location = "", ""

local function displayText()
  txt      = ""
  location = ""
  sceneGroup:remove( hud )
  sceneGroup:remove( nt )
    
  for row in db:nrows("SELECT * FROM rooms WHERE id= " .. inc) do
    txt       = txt .. row.content 
    location  = row.location
  end

  local options = {
    text = "HEALTH: " .. health .. "   LOCATION: " .. location,
    x        = 0,
    y        = 0,
    width    = 300,
    font     = native.system,
    align    = "left",
    fontSize = 18
  }

  display.setDefault("anchorX", 0)

  hud   = display.newText( options )
  hud.x = 5
  hud.y = 0

  local options = {
    text    = txt,
    x       = 10,
    y       = 0,
    width   = 300,
    font    = native.system,
    align   = "left",
    fontSize    = 16
  }

  nt    =   display.newText( options )
  nt.x  = 10
  nt.y  = 50
  display.setDefault("anchorX", 0.5)

  sceneGroup:insert(hud)
  sceneGroup:insert(nt)
end

Just as a proof of concept trial, I added a global inc value, and a button listener that increments that variable with each click. At any given time, the value of global inc corresponds to the id field of a database row.

So, the above function is within one composer scene. Composer does no navigation based on player story navigation. Upon game start, id 1 is loaded and displayed in the scene. When the user clicks the button, the global inc variable is incremented. The function then loads the row of id 2, and so on. Again, this was just to get things going. In a real game, each choice would have a corresponding id number. When the user selects a choice, the record corresponding to the user’s choice would be loaded.

A happy consequence of using a database as the data store for the game is, any number of fields can be added to each row, and that data becomes available as each user’s story choice is loaded.

Leave a comment