Log In  
2

This is Pico-8 on the GamePad Digital GPD-WIN palmtop gaming computer. I won't give this a detailed review because there are better sources of info on this machine, and it's no surprise that it can run Pico-8. But since I posted pics of RaspiBoy I thought it'd be fun to show it off in comparison.

GPD-WIN is a bit famous for being surprisingly good at what it does, but if you haven't seen it before: 5.5 inch touch screen, Intel Atom processor, teeny keyboard, built-in game controls (including shoulder buttons), and it runs Windows 10. Install the Windows version of Pico-8 and not only can you play games, but you can make games as well. The keyboard is implausibly small, but it compares favorably to a PocketChip. The whole thing folds up to the size of a 3DS.

I made a half-hearted attempt at setting up the game controls with Pico-8. You can choose between three controller modes using a hardware switch, including a mouse-and-keyboard emulation mode for regular Windowing. I ended up using this mode and Pico-8's keyconfig to get a reasonable result with the D-pad and buttons. I bet another mode and proper SDL controller set-up would also work. Mouse-and-key mode is also plausible for the editors: left stick to move the mouse, left shoulder button to left-click, etc. Touchscreen mousing is surprisingly good in general, but I personally would prefer the stick for drawing. There is one (and only one) USB-A port for external peripherals. It also supports Bluetooth.

The GPD-WIN sells for ~$400 USD, so a bit pricier than a RaspPi set-up (or any handheld game machine subsidized through licensing). It's also a plausible option (only option?) for playing Steam games in a handheld-like, which appears to be its chief purpose. I don't think I'd use it for apps unless I were desperate, or could use its mini-HDMI out and peripherals.

GPD-WIN has a subreddit of devoted fans, and the subreddit has a FAQ.

P#46896 2017-12-01 00:06 ( Edited 2017-12-01 01:14)

1

This is the RaspiBoy handheld console kit running Pico-8. Inside, it's a Raspberry Pi Zero connected to a TFT display, a LiPo rechargeable battery, a small speaker, a custom controller board, and a built-in full-size SNES-style controller including shoulder buttons on the back. The custom board provides two USB-A ports for data, a microUSB port strictly for charging, mini-HDMI video out, a headphone jack, a volume wheel for the speaker, and buttons for adjusting the display. RaspiBoy ships as a solderless kit that does not include the RaspPi Zero.

The two big ideas here are the full-size SNES-like controller grip and the injection molded case. Injection molding and silicone membrane pushbuttons do more to recreate the mass-market handhelds than any 3D-printed equivalent can. The controller size is comfortable and familiar. Overall, there are a lot of good ideas in the RaspiBoy that we haven't seen yet in this increasingly populated category of small-run manufacturing of Raspberry Pi-based handheld game consoles. The general design ticks a lot of boxes in my ideal version of this concept.

Unfortunately, there are some significant failures in the details. The large grip comes at the expense of a wide frame around the TFT screen. As shown in the picture, Pico-8 by default doesn't fill the frame, and the low resolution makes even Pico-8's chunky typeface difficult to read. (I have not yet experimented with options and config to fix this. The -width and -height command-line arguments may come in handy.) A flaw common to RaspPi-based handhelds is the need to formally shut down the operating system before turning it off, or risk corrupting the filesystem. (This could be fixed with custom software and a "soft" power button, but it'd be a project that I haven't seen anyone attempt yet.)

While the silicone membrane buttons have a familiar feel, they're a pain to assemble as part of the kit. Plastic buttons sit atop the membrane, and the membrane makes contact with simple copper pads on the circuit board. Getting these to line up while you push the two sides of the case together is difficult, and it took me multiple tries to get it to fit together correctly. Even when fully assembled, the buttons are too unreliable for gaming performance. I had far better luck sticking a prefab USB controller into one of the ports than I did with the built-in controller.

RaspiBoy doesn't use any custom software: it's just RetroPie in a common RaspPi configuration, and you install it yourself. So I'm not sure how to explain that Pico-8 misbehaves and crashes after a few minutes of play. I'm tentatively inclined to blame the RaspiBoy, the RaspPi Zero, or possibly the way the controller board connects to the Zero using pogo pins pressed up against the test pads. Needless to say, it's a deal breaker if I can't actually use it to play games reliably. I doubt I'll have the time or patience to troubleshoot this properly.

The basic RaspiBoy kit sells for 75 euros (~$90 USD) from http://www.8bcraft.com/.

P#46893 2017-11-30 23:16 ( Edited 2017-12-01 01:10)

1

Picotool is a library and toolset for manipulating Pico-8 cart data, useful for build workflows, as well as cart generation and transformation experiments. Many Pico-8 devs use it for its code minification feature (p8tool luamin), which can be handy when your game's code is near the uncompressed character limit.

A more recent feature is "p8tool build", a tool to assemble carts from multiple files. This tool takes a cart and replaces a type of its data from another file. For example, you can copy the spritesheet from another cart like so, such as to collaborate with an artist working in a separate cart file:

% p8tool build mygame.p8.png --gfx sprites.p8.png

You can pull in Lua code from a .lua file with the --lua argument:

% p8tool build mygame.p8.png --lua mygame.lua

When you use --lua, you get an especially powerful feature: build-time support for Lua's require() statement. The main .lua file can call require() to include code from additional .lua files, such as reusable libraries. It supports several features of the official Lua require() statement, such as only including a module once, and module return values.

You can get Picotool from its Github repo, as well as file bug reports, here:

https://github.com/dansanderson/picotool

Packages and the require() function

p8tool build supports a special feature for organizing your Lua code, called packages. When loading Lua code from a file with the --lua mygame.lua argument, your program can call a function named require() to load Lua code from another file. This is similar to the require() function available in some other Lua environments, with some subtle differences due to how picotool does this at build time instead of at run time.

Consider the following simple example. Say you have a function you like to use in several games in a file called mylib.lua:

function handyfunc(x, y)
  return x + y
end

handynumber = 3.14

Your main game code is in a file named mygame.lua. To use the handyfunc() function within mygame.lua, call require() to load it:

require("mylib")

result = handyfunc(2, 3)
print(result)

r = 5
area = handynumber * r * r

All globals defined in the required file are set as globals in your program when require() is called. While this is easy enough to understand, this has the disadvantage of polluting the main program's global namespace.

A more typical way to write a Lua package is to put everything intended to be used by other programs in a table:

HandyPackage = {
  handyfunc = function(x, y)
    return x + y
  end,
  handynumber = 3.14,
}

Then in mygame.lua:

require("mylib")

result = HandyPackage.handyfunc(2, 3)

This is cleaner, but still has the disadvantage that the package must be known by the global name HandyPackage wihtin mygame.lua. To fix this, Lua packages can return a value with the return statement. This becomes the return value for the require() call. Furthermore, Lua packages can declare local variables that are not accessible to the main program. You can use these features to hide explicit names and return the table for the package:

local HandyPackage = {
  handyfunc = function(x, y)
    return x + y
  end,
  handynumber = 3.14,
}

return HandyPackage

The main program uses the return value of require() to access the package:

HandyPackage = require("mylib")

result = HandyPackage.handyfunc(2, 3)

The require() function only evaluates the package's code once. Subsequent calls to require() with the same string name do not reevaluate the code. They just return the package's return value. Packages can safely require other packages, and only the first encountered require() call evaluates the package's code.

Where packages are located

The first argument to require() is a string name. picotool finds the file that goes with the string name using a library lookup path. This is a semicolon-delimited (;) list of filesystem path patterns, where each pattern uses a question mark (?) where the string name would go.

The default lookup path is ?;?.lua. With this path, require("mylib") would check for a file named mylib, then for a file named mylib.lua, each in the same directory as the file containing the require() call. The lookup path can also use absolute filesystem paths (such as /usr/share/pico8/lib/?.lua). You can customize the lookup path either by passing the --lua-path=... argument on the command line, or by setting the PICO8_LUA_PATH environment variable.

For example, with this environment variable set:

PICO8_LUA_PATH=?;?.lua;/home/dan/p8libs/?/?.p8

The require("3dlib") statement would look for these files, in this order, with paths relative to the file containing the require() statement:

3dlib
3dlib.lua
/home/dan/p8libs/3dlib/3dlib.p8

To prevent malicious code from accessing arbitrary files on your hard drive (unlikely but it's nice to prevent it), the require() string cannot refer to files in parent directories with ../. It can refer to child directories, such as require("math/linear").

As with Lua, packages are remembered by the string name used with require(). This means it is possible to have two copies of the same package, each known by a different name, if it can be reached two ways with the lookup path. For example, if the file is named foo.lua and the lookup path is ?;?.lua, require("foo") and require("foo.lua") treat the same file as two different packages.

Packages and game loop functions

When you write a library of routines for Pico-8, you probably want to write test code for those routines. picotool assumes that this test code would be executed in a Pico-8 game loop, such that the library can be in its own test cart. For this purpose, you can write your library file with _init(), _update() or _update60(), and _draw() functions that test the library. By default, require() will strip the game loop functions from the library when including it in your game code so they don't cause conflicts or consume tokens.

For example:

local HandyPackage = {
  handyfunc = function(x, y)
    return x + y
  end,
  handynumber = 3.14,
}

function _update()
  test1 = HandyPackage.handyfunc(2, 3)
end
function _draw()
  cls()
  print('test1 = '..test1)
end

return HandyPackage

If you want to keep the game loop functions present in a package, you can request them with a second argument to require(), like so:

require("mylib", {use_game_loop=true})

How require() actually works

Of course, Pico-8 does not actually load packages from disk when it runs the cartridge. Instead, picotool inserts each package into the cartridge code in a special way that replicates the behavior of the Lua require() feature.

When you run p8tool build with the --lua=... argument, picotool scans the code for calls to the require() function. If it sees any, it loads and parses the file associated with the string name, and does so again if the required file also has require() calls.

Each required library is stored once as a function object in a table inserted at the top of the final cartridge's code. A definition of the require() function is also inserted that finds and evaluates the package code in the table as needed.

To match Lua's behavior, require() maintains a table named package.loaded that maps string names to return values. As with Lua, you can reset this value to nil to force a require() to reevaluate a package.

This feature incurs a small amount of overhead in terms of tokens. Each library uses tokens for its own code, plus a few additional tokens for storing it in the table. The definition for require() is another 40 tokens or so. Naturally, the inserted code also consumes characters.

Formatting or minifying Lua in a built cart

You can tell p8tool build to format or minify the code in the built output using the --lua-format or --lua-minify command line arguments, respectively.

% ./picotool-master/p8tool build mycart.p8.png --lua=mygame.lua --lua-format

This is equivalent to building the cart then running p8tool luafmt or p8tool luamin on the result.

Future build features

I actually implemented require() support back in March of 2017. I didn't announce it at the time because I wanted to implement "dead code elimination," a feature that would prune unused code from included libraries, thereby saving tokens and making reusable libraries more practical. It'll be a fancy feature to implement, and I need to overhaul the parser to do it right, so that project is on hold for now. I'm announcing require() support now in case anyone has a use for it.

Let me know if you have any questions. Feel free to file bug reports and feature requests in Picotool's issue tracker on Github.

-- Dan

picotool build require
P#46443 2017-11-18 03:18

0

Next Thing Co. now has an alpha test image of the next version of the PocketCHIP software (4.4 alpha) that includes Pico-8 1.9. If you don't mind installing an alpha version (which may have bugs that cause data loss), it's easy to give it a try. It's easy enough that you probably don't even need instructions but there's one bit that I found by guessing so I thought I'd write it up.

You'll need a computer running Chrome, a USB-to-micro-USB cable, and your PocketCHIP. Ideally, the computer would be plugged into power so it doesn't lose power in the middle of the update.

  1. In Chrome, go to http://flash.getchip.com/. If this is your first time using the CHIP flash utility in Chrome, it will prompt you to install the Chrome extension. Do so.
  2. Connect PocketCHIP to your computer via the USB cable.
  3. Turn on PocketCHIP. Allow PocketCHIP to boot up to the main menu.
  4. On PocketCHIP, press the "power" on-screen button. In the power menu, select "Flash Software."
  5. In the Chrome window, start the flasher, then follow the prompts. Ignore the instructions involving a paperclip and "FEL" mode; you accomplished this with the menu option.
  6. Leave everything connected until the flasher utility reports success.
  7. Unplug PocketCHIP and allow it to reboot.

Start Pico-8 and notice it displays the 0.1.9 version number during start-up. Enjoy!

P#32191 2016-11-03 23:40 ( Edited 2016-11-15 19:35)

15

I just got a Pimoroni Picade, an arcade mini-cabinet for use with small board computers like the Raspberry Pi. It's a great match for PICO-8!

See also a short video I posted to Twitter.

The cabinet is $240 / £180, not including the Raspberry Pi and power supply. The cabinet goes together with a screwdriver (no soldering) and is fun and easy to build. (Be sure to refer to the assembly video in addition to the written instructions.) The result is solid and gorgeous.

I used a RaspPi 3 for my Picade. I strongly recommend the USB audio adapter that Adafruit sells, a major improvement in sound quality over connecting the Picade speakers directly to the RaspPi headphone jack. RaspPi 3 has built-in wireless Internet, but if you're using an older model you'll also want a RaspPi-compatible USB wifi dongle.

RetroPie is an easy-to-use software package of the best retro-gaming projects for the Raspberry Pi. It includes emulators for many platforms (arcade and home computers) as well as media center software, and a master menu called Emulation Station that you can manipulate using just the joystick and buttons so you don't need a keyboard connected once it's all set up.

Setting up RetroPie for Picade

I won't go through the RetroPie set-up procedure in detail. There are plenty of guides on the web, including at Adafruit. What follows are a few notes from my build.

Download the RetroPie image, in my case "retropie-v3.8.1-rpi2_rpi3.img".

Format an appropriately-sized SD card, at least 8 GB. I used a 32 GB card, which takes a while to format.

Write the image to the SD card. I have a Mac laptop and I used the command line to do this, as follows:

  1. Determine which disk device (e.g. "disk2") is the SD card.
diskutil list
  1. Unmount the SD card, substituting "disk2" with your actual device name.
diskutil unmountDisk /dev/disk2
  1. Write the image to the SD card, substituting "rdisk2" with your actual device name with a "r" in front of it ("rdisk" instead of "disk"). This command can take a while.
sudo dd bs=1m if=retropie-v3.8.1-rpi2_rpi3.img of=/dev/rdisk2

With the SD card still connected to the laptop, edit "/boot/config.txt" (accessible on the Mac as "/Volumes/boot/config.txt"). Uncomment this line so that Picade's screen will work correctly:

hdmi_force_hotplug=1

Unmount the SD card then remove it from your computer. Put the SD card in the Pi, hook it all up, and supply power. It should boot to Emulation Station and let you set up the button bindings. I mapped the D-pad controls to the joystick, and took a guess at the six top, two front, and two right buttons. (The two left buttons are for the speaker volume and are not seen by the Pi.) This is easy to change later.

From Emulation Station, go into the RetroPie menu and set up wifi. You'll need a keyboard connected to the Pi to enter your wifi password.

Once wifi is set up, select "show IP" from the RetroPie menu. You can use this IP address to connect to the Pi over the wireless network, transfer files, and make config changes. To get to a remote shell from your laptop, use the "ssh" command, substituting your IP address, and enter a password of "raspberry":

To copy a file to the Pi:

scp pico-8_0.1.8_arm.zip [email protected]:~/

The USB audio interface needs to be configured from the command line. See Adafruit's tutorial and RetroPie's sound docs for reference. Mine came up as the CM-Headphone type, and the only config change I needed to make was to create the "/etc/asound.conf" file:

pcm.!default {
  type hw card 1
}
ctl.!default {
  type hw card 1
}

Reboot the Pi:

sudo shutdown -r now

The Emulation Station menu plays sounds, and RetroPie comes with Doom pre-installed (see the Ports system menu). Test the audio. Use the volume buttons on the left of the cabinet to adjust as needed; it may start out too quiet to hear.

PICO-8 on the Picade

You can run the Raspberry Pi version of PICO-8 with this set-up. Copy PICO-8 to the Pi and unpack it into the ~/pico-8 directory:

# (starting from your computer:)
scp pico-8_0.1.8_arm.zip [email protected]:~/
ssh [email protected]

# (now on the RaspPi:)
unzip pico-8_0.1.8_arm.zip

On the Picade with a keyboard connected, exit Emulation Station (Menu button, Quit, Quit Emulation Station) to get a shell prompt, then run the pico8 command:

~/pico-8/pico8 -splore

Controls, fullscreen graphics, sound, and Splore over the Internet should all just work.

Launching PICO-8 from Emulation Station

Of course, it'd be better if you didn't need the command line and a keyboard to start up PICO-8, especially since Splore lets you download and play PICO-8 games using just the joystick and buttons. I wanted the ability to launch PICO-8 from Emulation Station, as in this video. It turns out this wasn't too difficult, but it involves a few steps.

I made two versions of the PICO-8 logo, one with light text and one with dark text, based on the one I made for the PICO-8 wiki (which in turn is heavily based on the official logos). You can get these here:

On the Pi, create a new pico8 theme directory for Emulation Station:

cd /etc/emulationstation
sudo mkdir themes/carbon/pico8

Copy the logo files to the Pi and move them to this directory. (You will need to use "sudo mv ..." to move the files into place.)

You also need to create a "theme.xml" file in this directory. Copy the one from .../themes/carbon/amiga/theme.xml, then edit it (such as with the "nano" editor):

sudo cp themes/carbon/amiga/theme.xml themes/carbon/pico8/theme.xml
sudo nano -w themes/carbon/pico8/theme.xml

Make these changes:

  1. Replace all instances of "./art/controller.svg" with "./../amiga/art/controller.svg".

  2. Change the logo for the main system screen, using the dark text version:
<view name="system">
  ...
  <image name="logo">
    <path>./p8logo_dark.png</path>
  </image>
</view>
  1. Change the logo for the system detail screen, using the light text version:
<view name="basic, detailed">
  ...
  <image name="logo">
    <path>./p8logo.png</path>
    ...
  </image>
  ...
</view>

Now you need to add pico8 to the list of systems. Edit the system config file:

sudo nano -w /etc/emulationstation/es_systems.cfg

Inside <systemList>...</systemList>, add these lines:

  <system>
    <name>pico8</name>
    <fullname>PICO-8</fullname>
    <path>/home/pi/pico-8</path>
    <extension>.sh .SH</extension>
    <command>/opt/retropie/supplementary/runcommand/runcommand.sh 0 "/home/pi/pico-8/pico8 -splore"</command>
    <platform>pico8</platform>
    <theme>pico8</theme>
  </system>

Emulation Station expects to find a directory of game files under <path> whose names have an extension specified by <extension>, so it can list them all in its menu and launch them individually. If you really want to use this feature with PICO-8 carts (and not use Splore), you could use <extension>.p8 .p8.png</extension>, <command>/opt/retropie/supplementary/runcommand/runcommand.sh 0 "/home/pi/pico-8/pico8 %ROM%"</command>, and an appropriate <path>. Every cart you put in your cart directory will appear as a menu option in Emulation Station.

For my configuration, I just wanted Emulation Station to launch PICO-8 in Splore mode. My configuration says to look for ".sh" files in the "/home/pi/pico-8" directory and create a menu entry for each one it finds. Emulation Station will not show the system in the main menu unless there is at least one such file. I created an empty file called "/home/pi/pico-8/+Start PICO-8.sh". When I select this option from the Emulation Station menu, it runs <command>, which in this case ignores the selected menu option and just starts PICO-8 with Splore.

Another way to do this is to make "/home/pi/pico-8/+Start PICO-8.sh" a real script that starts PICO-8, like this:

#!/bin/bash
pushd "/home/pi/pico-8"
./pico8 -splore
popd

Don't forget to make the script executable:

chmod a+x "+Start PICO-8.sh"

Change the command to <command>/opt/retropie/supplementary/runcommand/runcommand.sh 0 %ROM%</command>. This runs the script itself as the command when the menu option is selected. Doing it this way lets you add more items to the PICO-8 Emulation Station menu simply by adding more scripts to /home/pi/pico-8, such as to have multiple configurations (such as a non-Splore gamedev mode) or jump straight to your favorite carts.

Reboot ("sudo shutdown -r now") and you should now have PICO-8 in your list of systems. Select the PICO-8 system, then select the "+Start PICO-8" option. PICO-8 starts in Splore mode, and you can browse the BBS, play games, and add them to your favorites all using Picade controls. You only need a keyboard connected if you want to do text searches in Splore, or if you want the ability to exit to the PICO-8 command prompt or code editor.

retropie picade
P#25959 2016-07-27 04:22 ( Edited 2017-12-11 18:03)

8

I'm happy to announce the relaunch of the Pico-8 wiki!

http://pico-8.wikia.com/

I've spent the last few weekends writing articles and reference material for Pico-8, including complete API and command references, a memory map (including format details), a summary of the Lua subset, and tutorials on several subjects. This is very much a rough draft and I still have a list of to-dos, missing articles, more thorough sample code with screenshots, and some stuff I want to reorganize.

But it's a wiki, so you can help! Corrections are welcome at this stage. If you want to discuss a change before making it, hit me up on Slack or use Wikia's messaging feature or just reply here. But don't be shy about changing things directly.

Let me know what you think!

--

Two possible points of controversy I'll mention up front:

  • I tweaked the theme colors so they're reasonably readable, matching the forum site. I'm still a bit concerned that the Pico-8 red is unsuitable for link and header text. One of my monitors apparently doesn't support sub-pixel rendering or something and blurs it all to hell, but I'm not sure how big a problem that is. I tried a bunch of options and all the others seemed to drop the Pico-8 feel of the site. Suggestions welcome.

  • The cos, sin, and atan2 articles currently use a different convention to explain the y-inversion than the official docs do. A quick survey of the Slack group led me to try and explain it as inverting the angle direction and not the sign of sin(). This works until you get to atan2, which requires inverting the dy argument to fit that model. So the choices are counterclockwise with inverted sin() result, or clockwise with inverted atan2() dy argument. Inverting a result seems less problematic than inverting an argument, so I'll probably change it back. (I already have the diagram drawn.) Feedback welcome here as well.

Thanks!

-- Dan

wiki
P#23100 2016-06-18 04:40 ( Edited 2016-09-23 14:02)

11

Cart [#11980#] | Copy | Code | 2015-07-28 | Link
11

An implementation of Conway's Game of Life cellular automata.

Wikipedia: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
Game of Life wiki: http://www.conwaylife.com/wiki/Main_Page

v0.1: Initial version. GoL simulation uses the screen itself for storing cell data, using the two-line buffer method, with null edges.
v0.2: Pattern library. Audible feedback. Small bug fixes and performance improvements.
v0.3: Performance improvements. Pattern placer now lets you stamp multiple copies until you cancel. Simulation displays a generation count. Small visual changes.

P#11841 2015-07-26 04:35 ( Edited 2016-10-24 19:41)


:: More
X
About | Contact | Updates | Terms of Use
Follow Lexaloffle:        
Generated 2017-12-13 11:19 | 0.286s | 2097k | Q:29