Lua + C Minimal Example?

Is there a minimal example of starting a Lua-based game from the C API and registering a function?

1 Like

Do the existing C/Lua examples not fit your requirement?

Ideally, I am looking for an extremely simple example that simply starts Lua from C and does little to nothing else. Specific business logic will depend on the program in question. I guess the other question I have is, can Lua be used with a custom update function? (This may be documented.)

For what it is worth, I am not interested in using Lua myself, but the architectural option may open avenues for collaboration.

EDIT: This is a minimal example of a Playdate program that registers an update function and does nothing else. I am looking for a version of the same thing that starts Lua and runs it from the update function so C is still in control. Having said that, if control is generally completely passed to Lua, a barebones example of that architecture would also be nice to have.

src/main.c

#include "pd_api.h"

struct ProgramState {
  PlaydateAPI *pd;
  // ... other fields here ...
};

void initProgramState(struct ProgramState *ps, PlaydateAPI *pd)
{
  ps->pd = pd;
  // ... initialize other fields here ...
}

static int update(void* userdata)
{
  struct ProgramState *ps = (struct ProgramState *)userdata;
  PlaydateAPI *pd = ps->pd;
  // ... game logic here ...
  return 1;
}

#ifdef _WINDLL
__declspec(dllexport)
#endif
int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t arg)
{
  (void)arg; // only used for kEventKeyPressed == event
  static struct ProgramState *ps = NULL;

  switch (event) {
    case kEventInit:
      ps = pd->system->realloc(ps, sizeof(struct ProgramState));
      initProgramState(ps, pd);
      pd->system->setUpdateCallback(update, (void *)ps);
      break;
    case kEventTerminate:
      pd->system->realloc(ps, 0);
      ps = NULL;
      break;
    default:
      // do nothing
    break;
  };

  return 0;
}
1 Like

It’s generally passed. You can trigger a pseudo update callback in C from lua by calling a c func ever call of playdate.update.

The Array example is the best example for what you’re asking. Implements simple C functionality and exposes that to lua, then hands control to lua.

I thought I'd pointed it out in the docs, but I guess not. If you call setUpdateCallback() in the kEventInit handler, we don't bother setting up the Lua environment. If you call it in kEventInitLua instead, I think it'll do what you're looking for. It runs main.lua immediately after the eventHandler call but then calls your update function instead of playdate.update().

At least, that's what it should do. I've never tried that myself, so no guarantees. :playdate_wink:

2 Likes

@ericlewis
The Array example exposes functionality to Lua, but it does not implement a custom update() function.

@dave
I can try to put together a distilled barebones example that calls setUpdateCallback() in kEventInitLua. Also, I may have simply missed it in the documentation.

Hi. I just tried this out and it appears to be true in the simulator but not on device.

An empty main.lua file compiled to main.pdz and included in my pdx got me past a Couldn't find pdz file main.pdz error in the simulator.

On device, my main.lua had to at least include function playdate.update end otherwise I'd get an e1 error and no such function 'update' when pressing B to get more info.

An empty Lua playdate.update function makes no difference in the simulator as it appears to call the C-based update function regardless. On device it appears to run the empty Lua-based update function which results in a blank screen.

Given the apparent order of things I don't think it's possible to work around this by having the Lua update function call my C update function because the Lua code seems to run before I can add the C function to the Lua runtime.

It turns out I was accidentally building for the simulator. If I do that and then upload to my device I get the behavior I described.

If I build for device I can still upload via the simulator but get the desired behavior.

2 Likes

wait... there's building for sim vs device?

If you're using C there is

1 Like

The opposite is also true; if I build for device and run it in the simulator, it tries to call a Lua playdate.update function, but if I upload it to device from there the C update function is called as expected.