Log In  
Follow
pancelor

hi! here is some text for you to read.
some selected carts that I've uploaded here:

the tower
mine1k
linecook

for more, see my itch page or my website

SHOW MORE

Here's my /appdata/system/startup.lua file (picotron automatically runs it on startup)

-- take str, delete all chars between
-- indices i0 and i1 (inclusive), and
-- insert newstr into that space
local function splice(str,i0,i1, newstr)
    return sub(str,1,max(1,i0)-1)..(newstr or "")..sub(str,i1+1)
end

-- return str, but replace the first instance of cut with paste
local function _replace(str,cut,paste)
    local i0,i1 = str:find(cut,1,true) -- no pattern-matching
    if not i0 then return str end
    return splice(str,i0,i1,paste)
end

-- use str:find to do sed-like file editing.
-- no lua patterns, just literal string matching
local function sedish(fname,cut,paste)
    local src = fetch(fname)
    if not src then return end

    src = _replace(src,cut,paste)
    store(fname,src)
end

-- fix alt-tab annoyance
sedish("/system/lib/gui_ed.lua",
    [[if (keyp("tab")) then]],
    [[if keyp"tab" and not key"alt" then]])

-- add home/end/del to the terminal. only works for windowed terminals?
sedish("/system/apps/terminal.lua",
    [[if (keyp("up")) then]],
    [[if keyp"home" then cursor_pos = 0 end   if keyp"end" then cursor_pos = #cmd end   if keyp"del" and cursor_pos<#cmd then cmd = sub(cmd, 1, max(0,cursor_pos))..sub(cmd, cursor_pos+2) end   if (keyp("up")) then]])

-- fix bbs cache bug
sedish("/system/util/load.lua",
    [[rm "/ram/bbs_cart"]],
    [[rm "/ram/bbs_cart.p64.png"]])

what is this

I made this because picotron inserts a tab into my code whenever I alt-tab. I figured out how to edit the code editor itself to not do that, and then I made this script to automatically make the required edits. (you can't just edit the files on disk, because they get regenerated every time picotron boots)

this won't be necessary for too long hopefully, but it works great for now!

(the name "sedish" comes from the (loose) inspiration for this: sed)

post your tweaks

If anyone has other system tweaks like this one (fixing alt-tab), post them here!

P#143638 2024-03-18 04:05 ( Edited 2024-03-19 08:03)

SHOW MORE


load #sprimp-1
// to load from inside Picotron

tada! now you can import pico8 spritesheets. and map too!

importing a .p8 file

  • put your game.p8 file somewhere inside picotron's file system
    • the filename should not have any dashes ("-"), they generally cause problems currently (picotron 0.1.0b2)
  • run this importer (sprimp)
  • import the p8 cart
    • you can drag-and-drop the cart onto the sprimp window
    • or you can use "Import .p8 file" in the menu (the dialog that pops up says "save as" -- please ignore this. this is the best way I know how to launch a system filepicker)

exporting sprites

  • press "Save gfx..". choose a filename; the default is /ram/cart/gfx/0.gfx (which is the default spritesheet for your current cart)
  • IMPORTANT: if the spritesheet was already open in picotron's gfx editor, you'll need to close the file and reopen it (right click on the tab, close, then press the plus)
  • if you saved to /ram/cart/... save your cart afterwards (ctrl-s)

exporting map

  • (same as exporting sprites, just click "Save map.." instead)
  • for an easy transition from pico8 maps to picotron maps, check out this snippet, which includes mget and mset replacements

other ways to import (copypaste, aseprite)

importing sprite by copy-paste

  • open the pico8 sprite editor
  • copy the entire spritesheet (press tab, ctrl-a, ctrl-c)
  • your clipboard now has a [gfx]... code in it
  • open this tool (sprimp) in picotron
  • past the [gfx]... code into the tool

importing a single sprite

  • you can copy from pico8 and paste into picotron directly, zep made that work already
  • you can even paste your entire spritesheet into a single picotron sprite -- it's sorta wild. but you probably wanted to spread the spritesheet out into individual sprites, right? that's where this tool can help

importing from aseprite

you can use my exporter script for aseprite to export aseprite images into the [gfx]... format, letting you paste them into picotron or sprimp (or even pico8!)

future plans

  • Yes: Make importing sprites/maps easy. (mostly done! still some UI/UX work tho)
  • Maybe: sfx/music. I likely won't do this myself. If you have a working sfx/music importer and want to join forces, let me know!
  • Maybe: importing p8 code tabs into .lua files without any processing. with a big disclaimer that you'll need to do a bunch of manual work to fix the code
  • No: make it possible to drag-and-drop a pico8 cart into picotron and have everything "just work"

maybe zep will add improvements to picotron itself, and this whole project will no longer be relevant. that would be great! but whether or not that happens, this was a fun small project for me to learn some basics of picotron tool-making

changelog

v0.2

  • add .p8 import -- thank you @Krystman for the idea!
  • add drag-and-drop support
  • add map import/export

v0.1

  • sprite import/export
P#143506 2024-03-17 13:58 ( Edited 2024-03-18 09:33)

SHOW MORE


load #susizker-0
// to load from inside Picotron

just a port of a tweetcart of mine to the new system :)

move this into /system/screensavers/ and it'll show up as an option in your settings

If you run it on its own as a cart, you'll want to run reset() vid(0) in the console afterwards to get things back to normal

edit: if you want it to be permanently available, you need to put it in /appdata/system/screensavers (otherwise, you need to re-add it every time you start picotron). create the folder by copying the system folder: cp /system/screensavers /appdata/system/screensavers

P#143111 2024-03-15 13:37 ( Edited 2024-03-17 07:36)

SHOW MORE

Cart #ghostpatrol-2 | 2023-10-07 | Code ▽ | Embed ▽ | No License
9

Oh no, ghosts are approaching the town!

Mayor Wombledon has begged ALFREDO THE GHOUL BANISHER to team up with THE WILY WIZ to protect the town. Can they put aside their differences and work together, or will evil spirits devour the populace?

Controls

  • Arrow keys: move
  • Z: swap heroes
  • Enter/P: pause (level select, volume controls)
  • X: next level

Outcomes

  • 1 night protected: You have the villagers' sincere gratitude 🙏
  • 5 nights protected: The villagers are beginning to hope again 😭
  • 10 nights protected: Valiant Heroes 🏆
  • 40 nights protected: Local Deity 🤯

Tips

  • Alfredo can dig up graves with his fearsome claws.
  • The Wiz can swap places with nearly anything.
  • You can change levels freely in the pause menu.
  • Never give up; always fight with your full strength.

1024 bytes, made by pancelor for PICO-1K 2023. Thanks to timp + shrinko8 for compression help!

The layouts were randomly generated, but they don't change. My best times for the first 5 levels are 7 / 11 / 15 / 39 / 41.

If you enjoyed this, you might also enjoy my game Hungry Eggbug, or the board game that loosely inspired this game: Ricochet Robots.

P#135418 2023-10-04 21:47 ( Edited 2023-10-07 02:35)

SHOW MORE

Hi @zep, found a parser bug for ya:

for --[[a]]e=0,1 do print(e) end
print(fore)

expected: 0 1 [nil] (this is what lua 5.4 outputs)
observed: [nil] 0

pico-8's highlighting works correctly, but the runtime seems to see this somehow:

fore=0,1

do
  print(e)
end

system: linux / pico8 0.2.5g


I ran into this while using shrinko8's annotations (for --[[preserve]]e=0,1 do)

Workaround: add an extra space (for --[[preserve]] e=0,1 do)


edit: ah! this thread has more cases / info: https://www.lexaloffle.com/bbs/?tid=51618

P#135201 2023-10-01 10:22 ( Edited 2023-10-05 04:16)

SHOW MORE

@zep if you open this cart in pico8 and save it, pico8 inserts an extra byte at the end (0xff) (this is wrong, but additionally it is very confusing because my text editor thinks the text encoding has changed and starts displaying weird unicode everywhere)

pico-8 cartridge // http://www.pico-8.com
version 41
__lua__
?'hi'
__meta:title__
cooltitle

After some minimal testing, the conditions necessary seem to be:

  1. the file ends with a __meta__ section (__gfx__ doesn't trigger the bug)
  2. the file does not have a trailing newline (the last byte of this particular file is 'e', not '\n')

platform: linux / pico8: 0.2.5g

P#135184 2023-10-01 00:14

SHOW MORE

Bitplanes are powerful, but they can be difficult to understand. How do you use them in PICO-8?

The short version: bitplanes let you draw colors to the screen without completely overwriting the existing colors, making it possible to do effects like shadows, transparency, etc. But be warned: they come with a lot of unintuitive restrictions, like monopolizing half your screen palette or requiring it to be set up in a particular way.

Longer version: PICO-8 colors are 4-bit numbers (0-15). The screen is a 128x128 4-bit image, but you can imagine it as 4 separate 12x128 1-bit images overlaid on top of each other. By poking a particular location in memory, we can tell PICO-8 to draw to these "bit planes" separately. Normally, drawing overwrites any existing colors, but if we selectively disable some of the bitplanes, some bits of the old color will remain onscreen.

Technical version: see "Technical details" below.

This post lists some specific examples and tricks that you can do with bitplanes. I won't attempt to fully explain how bitplanes work, but I'll leave some resources at the end.

Examples

Shadows

  1. set up your screen palette:
    i. 0-7: shadow palette; 0 is the shadow color for 8, 1 is the shadow color for 9, etc
    ii. 8-15: any colors
  2. draw anything
  3. enable bitplane mode 0x08 (clear the 0/8 bitplane)
  4. draw anything -- any pixels "drawn" will instead overwrite colors 8-15 with their shadow colors
  5. disable bitplane mode

Cart #bitplane_shadows-2 | 2023-09-21 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
7

I used this method in my freecell clone.

Spotlight

  1. set up your screen palette:
    i. 0-7: all identical; e.g. all 0 (black)
    ii. 8-15: any colors
  2. draw your scene using colors 0-7. they will all appear black
  3. enable bitplane mode 0xf8 (only draw the 0/8 bit)
  4. draw a circfill in color 8 -- instead of drawing red, it will add 8 to each color it hits, revealing the image "underneath" the darkness
  5. disable bitplane mode

This cart uses a very similar technique to create an "xray" effect. (They set up their palette differently and use a different bitplane mode, swapping adjacent colors instead of shifting the palette by 8)

1-bit sprite packing

If you have 1-bit sprites, you can store them merged in the 4 bitplanes in the spritesheet, and extract them at runtime using bitplanes. It's essentially another way to do this sprite-layering technique. Here's a tool that does something similar. Neither of these actually use pico8's bitplane feature, but they could be implemented that way to save some tokens and a tiny bit of cpu.

Chromatic aberration

You can create some cool effects (like https://mastodon.social/@zep/109315783011955478) by drawing slightly different images on different bitplanes.

Trippy motion blur

Flashing lights warning, this one can be pretty rough on the eyes. It's a neat trippy effect where each bitplane gets updated every 4 frames, leaving a slightly out-of-date impression onscreen for those other 3 frames, which creates a motion blur of sorts. I find it hard to look at (especially the jelpi example in the replies!) but it looks fascinating and it's very neat how bitplanes make it easy to create this effect in any game. I wonder how this could look with palette specifically designed for it... (the palette from the following "Anti-aliasing" example works decently well!)

(thanks freds72 for finding the link to this! I couldn't remember where I'd seen it)

Anti-aliasing

You can add anti-aliasing by drawing the same thing at slight subpixel offsets, like in this example. (Note that this restricts your palette to 5 colors)

Technical details

Wikipedia has some general info, and the PICO-8 wiki (search "bitplane") has specifics about how they work in PICO-8:

> 0x5f5e / 24414
> Allows PICO-8 to mask out certain bits of the input source color of drawing operations, and to write to specific bitplanes in the screen (there's 4 of them since PICO-8 uses a 4BPP display). Bits 0..3 indicate which bitplanes should be set to the new color value, while bits 4..7 indicate which input color bits to keep.
> For example, poke(0x5f5e, 0b00110111) will cause drawing operations to write to bitplanes 0, 1, and 2 only, with 0 and 1 receiving the color value bits, 2 being cleared, and 3 being unaltered.
> This formula is applied for every pixel written:
> dst_color = (dst_color & ~write_mask) | (src_color & write_mask & read_mask)

If you're not sure what to try, setting the write_mask and read_mask to the same value is often useful.

Other resources

-Bitwise math tutorial
-A simple bitplane example -- three circles rotating in 3D
-My bitplane explorer -- it helps visualize how colors will interact

-The original discovery
-Bitplanes confirmed by zep
-Circular Clipping Masks -- discusses other non-bitplane ways to get shadow and spotlight effects

P#134693 2023-09-21 11:11 ( Edited 2023-09-24 09:27)

SHOW MORE

PICO-8 supports bitplane drawing; the wiki (search "bitplane") has a description of how they work:

> 0x5f5e / 24414
> Allows PICO-8 to mask out certain bits of the input source color of drawing operations, and to write to specific bitplanes in the screen (there's 4 of them since PICO-8 uses a 4BPP display). Bits 0..3 indicate which bitplanes should be set to the new color value, while bits 4..7 indicate which input color bits to keep.
> For example, poke(0x5f5e, 0b00110111) will cause drawing operations to write to bitplanes 0, 1, and 2 only, with 0 and 1 receiving the color value bits, 2 being cleared, and 3 being unaltered.
> This formula is applied for every pixel written:
> dst_color = (dst_color & ~write_mask) | (src_color & write_mask & read_mask)

This is precise and correct, but I find it a bit hard to understand. So I made this cart to give myself an interactive sandbox where I can play around with bitplanes, to see how they affect drawing.

Cart #bitplane_explorer-1 | 2023-09-21 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
3

The code is straightforward:

  1. draw the full 16-color palette
  2. enable bitplanes, using the poke shown onscreen
  3. draw a circle, using the circfill shown onscreen

You can change the bitplane settings and the circle's "color" -- the controls are shown onscreen. This interactively shows how drawing any color will interact with any other color under the current bitplane settings.

You'll still need to study the description from the wiki to understand how to use bitplanes, but this cart is a helpful supplement for me when working with bitplanes. I hope you find it helpful too!

P#134692 2023-09-21 02:13 ( Edited 2023-09-21 10:01)

SHOW MORE

update 2024: the 0.2.6 update improves things! search the update post for menuitem(0x301 for details. (My original menuitem post remains below, unchanged)


PICO-8 has fancy menuitems but there are some gotchas and bugs to be aware of.

Here's an example of what I do by default; the rest of this post will explain how the code works and why I do things this way:

Cart #menuitems-1 | 2023-08-21 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
6

L/R pitfall

Imagine you want to add a "mute" button to your game's menu. Can you spot the issue with this code?

function _init()
  menuitem(1,"mute",function()
    ismuted=not ismuted
    -- ... play/pause the music
  end)
  -- ... other game init
end

The issue: left/right can be used to change the menuitem, and left/right always leaves the menu open afterward (this may be a bug; it's unclear) so there's no indication to the player that they accidentally muted the game! It's a minor issue... but it's easy to accidentally hit left/right when navigating the menu on a gamepad, which makes this worse.

An easy fix: don't respond to L/R (menuitem(1,"mute",function(bb) if bb>=16 then ... end end)). This is what I'd recommend for games that are short on tokens but willing to spare a few to fix this.

Responsive menu

If you'd like a more responsive menu, you can do this:

function _init()
  menuitem(1,ismuted and "music: off" or "music: on",function()
    ismuted=not ismuted
    -- ... play/pause the music
    -- update the label:
    menuitem(nil,ismuted and "music: off" or "music: on") -- feels like we could save some tokens...
    return true
  end)
  -- ... other game init
end

Now the option shows its status, and updates its label immediately when you change it!

Note the return true -- this keeps the menu open. Without this, if the player presses left (toggling the setting) and then presses enter (trying to close the menu but instead toggling the setting again), they'll wonder why their change isn't sticking. By leaving the menu open, we show them that they actually re-toggled the setting, and they need to choose "continue" instead to resume the game.

Code organization idiom

The repeated ismuted and "music: off" or "music: on" is suspicious -- can we save some tokens? Yes, by setting up each menuitem() again at the end of the callback, just to refresh the labels:

function _init()
  domenuitems() -- setup all menuitem()s
  -- ... other game init
end
function domenuitems()
  menuitem(1,ismuted and "music: off" or "music: on",function()
    ismuted=not ismuted
    -- ... play/pause the music
    domenuitems() -- refresh the label
    return true
  end)
  -- menuitem(2,...
  -- menuitem(3,...
end

I do this for code-organizing reasons -- it's nice to have all the menuitem code in one place -- but it can also save a few tokens, depending on your setup.

Context-dependent menuitems

Some menuitems should only be show in certain situations -- e.g. don't show "back to title" if we're already on the title screen. You could break each menuitem into its own little setup function (like zep's original LOAD #CUSTOM_MENU cart does -- check it out, it's nice!) or do what I do: menuitem(1,condition and "label",...). This will only show the menuitem when condition is truthy. I call domenuitems() anytime the menu needs changing (e.g. at the end of init_title_screen()) and it all works out.

Recommendations / Summary

I put all my menuitem() calls inside a custom domenuitems() function. Every callback runs domenuitems() at the end, to refresh the labels.

There are three types of menu options I commonly use: commands, toggles, and selectors.

  • For commands (run some code, e.g. return to the title screen), I wrap the callback code in a if bb>=16 then ... end block, to prevent L/R from triggering the command
  • For toggles (e.g. mute/unmute the game), my callback always has return true, leaving the menu open afterward and avoiding the UX issue described above
  • For selectors (choose a number from a range, e.g. change levels), my callback has return bb<16, leaving the menu open only if L/R were used to change the selection. (this is technically unnecessary due to a longstanding bug(?) in PICO-8's menu handling)

Read the code of the example cart at the top of this post for more info!

P#133332 2023-08-21 01:02 ( Edited 2024-03-14 08:32)

SHOW MORE

I often use shell scripts to export and then upload my games to itch.io, and there's a small inconvenience that trips me up sometimes: If my game is too large, the export fails, but I have no way of detecting that from my shell script.

> pico8 game.p8 -export "-f froggypaint.html"
EXPORT: -f froggypaint.html
failed: code block too large

> echo $?
0

I would expect the status code (echo $?) to be 1 or some other failure code

(Hm, now that I've written this up I suppose I could work around this by reading stderr stdout and checking for the string "failed"...)

P#130092 2023-05-24 08:14

SHOW MORE

A slow but token-efficient sort:

-- 35-token bubblesort, by pancelor
function sort(arr)
  for i=1,#arr do
    for j=i,#arr do
      if arr[j] < arr[i] then
        add(arr,deli(arr,j),i) --slow swap
      end
    end
  end
end

I did a brief speed analysis and this function seems reasonable to use for arrays up to around 50 or 100 elements, depending on how much CPU you have available to burn.

speed analysis:


I did some minimal testing, using this code:

cls()
function _draw()
arr={
--20,5,8,3,7,4,1,9,2,-30,
--20,5,8,3,7,4,1,9,2,-30,
--20,5,8,3,7,4,1,9,2,-30,
--20,5,8,3,7,4,1,9,2,-30,
20,5,8,3,7,4,1,9,2,-30,
}
sort(arr)
end

By commenting out lines of the array, I changed it's length. Here's how much CPU the function spent, as a percentage of a single 30fps frame (measured with the ctrl-p monitor, on pico8 0.2.5g)

The "best case cpu" was calculated by defining arr outside of _draw, so that the array was already sorted after the first frame

Array length Typical cpu (30fps) Best case cpu (30fps)
10 0% 0%
20 1% 1%
50 5% 4%
100 21% 15%
200 81% 58%
300 181% 130%
400 321% 231%

I believe this algorithm is O(n^3): O(n^2) for the two loops, and an additional O(n) b/c the swap step uses add and deli, which shift around the array elements. But the chart seems to indicate that doubling the length will quadruple the cpu cost (instead of octupling it) so maybe it's only O(n^2) somehow? It doesn't much matter, since you don't want to use this for large arrays anyway, but maybe add/deli are cheaper than I would expect.

P#128863 2023-04-21 23:04

SHOW MORE

mildly interesting: when drawing a perfectly vertical line (line(1,1,1,h)) or perfectly horizontal line (line(1,1,w,1)), it used to be cheaper (in cpu cycles) to use rect or rectfill instead. but not anymore! I'm testing this on 0.2.5g; I'm not sure when this changed.

tl;dr: line and rectfill cost the same for orthogonal lines (rect is more expensive for vertical lines only)

simple test:


load #prof, then add these lines:

-- horizontal
prof(function()
 line(0,0,90,0,2)
end,function()
 rect(0,0,90,0,2)
end,function()
 rectfill(0,0,90,0,2)
end)
--  9+10=19 (lua+sys)
--  9+10=19 (lua+sys)
--  9+10=19 (lua+sys)

-- vertical
prof(function()
 line(0,0,0,90,2)
end,function()
 rect(0,0,0,90,2)
end,function()
 rectfill(0,0,0,90,2)
end)
--  9+10=19 (lua+sys)
--  9+22=31 (lua+sys)
--  9+10=19 (lua+sys)

full test:

function one(fn,opts)
  local fmt=function(n)
    -- leftpad a number to 2 columns
    return n<9.9 and " "..n or n
  end

  local dat=prof_one(fn,opts)
  printh(fmt(dat.lua)
    .."+"
    ..fmt(dat.sys)
    .."="
    ..fmt(dat.total)
    .." (lua+sys)")
end

function hline(x) line(0,0,x,0,2) end
function hrect(x) rect(0,0,x,0,2) end
function hrfil(x) rectfill(0,0,x,0,2) end
function vline(x) line(0,0,0,x,2) end
function vrect(x) rect(0,0,0,x,2) end
function vrfil(x) rectfill(0,0,0,x,2) end

printh"--"
for i=0,127 do
 printh(i..": ")
 one(hline,{locals={i}})
 one(hrect,{locals={i}})
 one(hrfil,{locals={i}})
 one(vline,{locals={i}})
 one(vrect,{locals={i}})
 one(vrfil,{locals={i}})
end

--[[
...
14: 
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
15: 
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
16: 
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 4=13 (lua+sys)
 9+ 2=11 (lua+sys)
17: 
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 2=11 (lua+sys)
 9+ 4=13 (lua+sys)
 9+ 2=11 (lua+sys)
...
]]

summary:

rect:
    when h is 1, sys cost is:
        max(1,w\16)*2 (agrees with CPU wiki page)
    when w is 1, sys cost is:
        max(1,(h-1)\8)*2 (disagrees? unsure)
line and rectfill
    a,b = max(w,h),min(w,h)
    when b is 1, sys cost is:
        max(1,a\16)*2 (agrees with CPU page for rectfill, but not line(?))

P#127584 2023-03-25 03:47

SHOW MORE

Cart #thetower-2 | 2023-07-27 | Code ▽ | Embed ▽ | No License
28

welcome to the tower
welcome to the tower
welcome ‍ to the tower
welcome to the tower

controls

  • arrow keys: walk, interact
  • enter: pause menu (volume, toggle effects, etc)

the game will autosave your progress each floor

credits

made by tally (art, room design, dialog) and pancelor (code, game design, music, dialog)

pixel art created with tiles from teaceratops and yelta

built with pico-8, aseprite, PX9, and shrinko8

changelog

  • thetower-1: added title screen
  • thetower-0: initial release
P#125012 2023-02-18 13:09 ( Edited 2023-07-27 07:01)

SHOW MORE

switching between custom and default fonts (?"\015") behaves a bit strangely; the first line of text is spaced differently from the rest, depending on whether:

  1. custom fonts are enabled by default (poke(0x5f58,0x81)), and
  2. the line height (peek(0x5602)) is more or less than 6 (the size of the default font)

run this cart to see what I mean:

Cart #kahedapibi-1 | 2023-01-30 | Code ▽ | Embed ▽ | No License
2

specifically:

  1. when the custom font is enabled by default and the custom font's height is more than 6, the default-font text in this cart has a large gap between the first and second lines:
  1. when the custom font is not enabled by default and the custom font's height is less than 6, the custom-font text in this cart has a large gap between the first and second lines:

I didn't test how ?"\^y" affects things.

my system info: 64-bit linux, pico8 0.2.5e

P#125013 2023-01-30 07:21

SHOW MORE

how many tokens should this cart cost?

s="x".."="
a=1+2

in 0.2.1b, it costs 10 tokens (5 for each line). this seems correct to me. however, in 0.2.5e, the first line only costs 4 tokens for some reason.

edit: even weirder: s="x".."=" costs 4 tokens but s="x".."y" costs 5 tokens. it seems like concatenating any string that starts with the equals symbol is 1 token cheaper than it should be; how odd! maybe this is somehow due to the recent parser updates for += etc?

P#123586 2023-01-03 07:52

SHOW MORE

When I'm making games or tweetcarts, I often adjust numbers just a tiny bit, then rerun the whole game. e.g. I change the player speed by 0.1, then change it back, then try 0.05...

This is a bit slow, so here's a library I made to help me do it faster. I also find it useful for analyzing other people's tweetcarts -- if I can easily adjust the values they use, I can quickly figure out what they mean

setup

  • load #twiddler
  • copy the knobs.lua + helpers tabs into your game
  • use kn[1], kn[2], ... kn[8] in place of any number
  • add twiddler() to the end of your _draw function

Now, run your code:

  • press tab and adjust the values (see "controls" below)
  • press tab again -- the values will be copied to your clipboard
  • paste the values into the start of your code to save them

example 1

Start with a tweetcart you want to study. For example, this one by 2DArray: https://twitter.com/2DArray/status/1492566780451205120

?"\^!5f10◆█🐱░4웃9♥"
::_::?"⁶1⁶c"
w=t()/8
c=cos(w)
s=sin(w)
n=1800
for i=0,n do
a=i*.618
j=1-i/n*i/n
y=1+j*j-2*j*j*j
r=1-(1-j)^3+sin(a*10)/9
p=(6+sin(a*10)*(.5+r/2))*(.7+y*y/3)
circfill(64+cos(a+w)*r*20,80-y*30+sin(a+w)*r*12,2,p)
end
goto _

Add the knobs, and replace some interesting-looking numbers with knobs:

kn={.5,.7,.618,2,0,0,0,0} --changed
?"\^!5f10◆█🐱░4웃9♥"
::_::?"⁶1⁶c"
w=t()/8
c=cos(w)
s=sin(w)
n=1200 --changed -- twiddler needs a little bit of cpu to run
for i=0,n do
a=i*kn[3] --changed
j=1-i/n*i/n
y=1+j*j-2*j*j*j
r=1-(1-j)^3+sin(a*10)/9
p=(6+sin(a*10)*(kn[1]+r/2))*(kn[2]+y*y/3) --changed
circfill(64+cos(a+w)*r*20,80-y*30+sin(a+w)*r*12,kn[4],p) --changed
end
twiddler() --changed
goto _

Now run the code and play around! looks like knobs 1 and 2 control the color gradient, knob 3 controls the spiralness of the circles. cool! Add new knobs, remove old knobs, keep going until satisfied.

example 2

This process works on your own code that you're in the middle of writing, too. Write kn[1] etc instead of a number, open the knobs panel, and edit the value until it looks right:

This is from the dev process of a recent tweetcart of mine (twitter, cohost)

controls:

Press Tab or W to open/close the knob panel

  • LMB - change slider value
  • MMB - pan slider range
  • RMB - cancel current interaction
  • wheel - zoom slider range

When you close the panel (Tab/W), knob values will be copied to your clipboard -- paste them into your code to save them.

Cart #twiddler-0 | 2022-10-28 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
10

When you're done with the knobs, you can replace kn[1] etc with the literal value of the knobs, and delete the twiddler code. This is a tool meant for development, not meant to be used during a finished game. (although, a finished game that used something like this would be pretty nifty!)

P#119729 2022-10-28 22:11 ( Edited 2022-10-28 22:13)

SHOW MORE

Cart #mine1k-0 | 2022-10-09 | Code ▽ | Embed ▽ | No License
19

A demake of the classic minesweeper.

The game cartridge is just 1024 bytes -- see https://gist.github.com/pancelor/a3aadc5e8cdf809cf0a4972ac9598433 for some lightly commented source code

RULES / CONTROLS:

  • left click to reveal a tile
    • if you hit a mine, you lose
    • revealed tiles will show a number, telling how many of their 8 neighbors are mines
  • right click to flag a tile
  • reveal all non-mine tiles to win!
  • click the smiley face to restart

TIPS

  • left click + right click (simultaneous) to auto-reveal neighbors, if the number of nearby flags matches the number on the tile you clicked
  • mines left and a timer are displayed in the top corners
P#118854 2022-10-09 21:57

SHOW MORE

When exporting a game to a binary format (.exe, etc), the manual says:

> To include an extra file in the output folders and archives, use the -E switch:

> > EXPORT -E README.TXT MYGAME.BIN

I tried this (pico8 game.p8 -export "-f game.bin -e examples/ -e samples/") but it doesn't include those subfolders. If I -e examples/kick.pcm, then that file is included, but it's included at the top level, and not in an "examples" subfolder

Am I doing this wrong somehow? I assume this just isn't supported (yet? fingers crossed)

P#111906 2022-05-16 22:38 ( Edited 2022-06-04 19:26)

SHOW MORE

Cart #imhungry-0 | 2022-04-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
2

> Vous contrôlez un petit rennes qui doit attraper le plus de nourriture possible, il s'agit de pain et de mûres. Plus vous attrapez de, plus la nourriture va vite et plus il est compliqué de l'attraper. En haut à droite, vous verrez qu'il y a votre tableau de bord, chaque aliment pêché vaut un point. Et en haut à gauche, il y a un panneau qui vous montre combien d'aliments vous n'avez pas attrapés. Attention ! au bout d'une dizaine d'aliments non attrapés vous perdez et le jeu affiche alors « GAME OVER ! », alors il faut appuyer sur enter pour recommencer.

> Les commandes sont : la flèche droite pour se déplacer vers la droite, la flèche gauche pour se déplacer vers la gauche et la flèche vers le haut pour sauter. C'est si simple !

(for more info, see https://itch.io/jam/im-hungry / https://pancelor.itch.io/im-hungry)

P#110904 2022-04-26 21:12 ( Edited 2022-06-01 14:24)

SHOW MORE

I hit this bug while working on a tweetcart:

?"\*6a"  -- prints 6 'a's    (expected)
?"\*6\"" -- prints 6 quotes  (expected)
?"\*6\n" -- prints 1 newline (unexpected!)
?"\n"    -- prints 1 newline (expected)
P#109613 2022-04-03 02:06

View Older Posts
Follow Lexaloffle:          
Generated 2024-03-19 11:27:23 | 0.117s | Q:70