Log In  

It's a very nice and warm day outside so why not use it to sit inside doing something completely pointless? But sort of fun. So, I created a prototype of Pico-8/Kongregate API integration that uses the GPIO ports to translate Pico-8 scores etc. to the API. Of course, you are not limited to Kongregate, you can use whatever JS API you have access to. Quite easy to roll your own, too.

The idea is that the game updates the GPIO ports and the JS backend polls the ports. The Pico-8 HTML5 export sets the pico8_gpio array and it corresponds addresses 0x5F80... in Pico-8 memory space.

In short: my code in Pico-8 poke()'s a value in ports 0x5F80 and ..81 (we need to split the value into two 8-bit values as you can see in the code below), which is always one larger than the previous value in there. The JS code notices the value has changed and knows it has to read whatever is in the ports and act accordingly. I set a value that tells what the rest of the ports mean, e.g. 0 for a new high score in ports 3 and 4 that has to be posted.

In the game I have a delay after setting the values so that the JS code has enough time to read the values before they change (I set a bunch of these stats at game over). This could and should be handled with the JS setting a value in a port that tells Pico-8 it should continue but I didn't bother to do that.

Check the game on Kongregate, you can see there's my score in the leaderboards to prove it works. ;)

Here's some code, it's just a proof of concept so don't expect anything nice and clean (api.post() would be something like kongregate.submit("score", 2000) in reality):

statsapictr = 0

-- set values in ports

function sethighscore()
  poke(0x5f82, 0) -- 0 = post score
  poke(0x5f83, score % 256) -- low byte
  poke(0x5f84, flr(score / 256)) -- high byte

-- tell JS we have new stuff in the ports it has to post ASAP

function updatestatsapi()
    statsapictr += 1    
    poke(0x5f80,statsapictr % 256)
    poke(0x5f81,flr(statsapictr / 256))

        -- delay to make sure JS has enough time
    for i=0,10 do
        spr(243,0,0) -- show a sprite to show it's doing something, maybe a spinner
        flip() -- flip screen, i.e. wait 1/30th of a second


var pico8_gpio = [];
var pico8_prevGpioCtr = 0;

function doGPIO()
    var ctr = pico8_gpio[0] + pico8_gpio[1] * 256;

    if (ctr != pico8_prevGpioCtr)
        pico8_prevGpioCtr = ctr;

        switch (pico8_gpio[2])
            case 0:
                var score = (pico8_gpio[3] + pico8_gpio[4]*256);
                api.post("score", score);

            case 1: 
                api.post("gameCompleted", true);


    setTimeout(function() { doGPIO(); }, 50); // do this every 50 ms

Just run doGPIO() once and it keeps updating every 50 ms.

P#23664 2016-06-26 08:39 ( Edited 2017-12-05 15:37)

So you're posting a score from your P8 game to an online leaderboard? So more or less just an ajax call out, yes?

Does this only work on the web version then, I assume, since it needs the JS file...?

Very cool. Too bad this isn't something baked in where we could just have a post() command that we specify a URL or something. All sorts of possibilities if we have a way out of P8 into a service.

What's the payload going out look like?

P#23700 2016-06-26 18:35 ( Edited 2016-06-26 22:35)

Yeah it only works in the HTML export. But, in theory why wouldn't it also work on desktop? People have already done networking. You only need a way to access the GPIO ports somehow.

[quote] What's the payload going out look like? [/quote]

I just use the Kongregate API so it does all the work, but for that site only. I only do the very basic GPIO to API translation. Basically, it's exactly the same as in my example but with different variable names for the API calls.

It would be fun if there was a global leaderboard with a simple function to add a high score. :)

P#23735 2016-06-27 05:08 ( Edited 2016-06-27 09:08)

"People have already done networking."

How? With JavaScript, or in actual carts themselves? It's fine if it only works in the web player, but could net code be stored inside carts somehow (maybe as JS in a string that the web player can somehow execute)? I'd think that would be a huge security vulnerability, though, as it could be used for XSS. Would still be cool in a way if it worked though, because it could be used for not just hiscores, but also for importing additional game data from an external source.

P#34829 2017-01-03 07:31 ( Edited 2017-01-03 12:31)

Digging this thread up because I'm interested in having my cart send a string out to the receiving JS.

I have it working sending ints but is it possible to send a string? Or would it have to be encoded...and if so, how?

P#46122 2017-11-10 23:38 ( Edited 2017-11-11 04:38)

@kometbomb do I have permission to use this code in my game? I have a little game that I wanted to upload to Kongregate and I was hoping to use this code.

P#47126 2017-12-05 10:37 ( Edited 2017-12-05 15:37)

Just saying that this could be implemented on desktop using node.js

P#93060 2021-06-05 15:43

On desktop, the memory area corresponding to GPIO pins does nothing, so you would have to write a wrapper program (using python or lua or really any language) that starts pico8 and connects to its standard input and output streams for communication. One example is here: https://www.lexaloffle.com/bbs/?tid=38732

P#93068 2021-06-05 19:09

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2023-05-29 01:40:30 | 0.011s | Q:21