I understand Pico-8 has a subset of the full Lua language. However, I wonder is there enough of it there to make the following book useful: https://www.amazon.com/Programming-Lua-Fourth-Roberto-Ierusalimschy/dp/8590379868/ref=pd_lpo_sbs_14_t_0?_encoding=UTF8&psc=1&refRID=JKY5ABS0S7DB70RF732Z
Does anyone have this and did it help you?
I've been able to get by picking up a smattering of lua syntax just online, but I enjoy the idea of getting a deeper look at the language. However since Pico-8 is the only platform on which I'm extensively using Lua, I want to make sure the investment would be worth it.






Played around with YellowAfterLife's char-functions, and ended up creating a C64-sprite-font at the same time...
I guess this has already been done a thousand times here, probably much better than this... but I just had to do my own version.
Any help with minimizing/optimizing this further would be cool.
Thanks also to Lumiette for the inspiration. :)
/ Pingo


“Shinkansen” is more of a “love letter” to the people (and railways!) of Japan than an actual game, but hopefully it is still at least mildly challenging and entertaining to play…
You are in charge of orchestrating the progressive replacement of the “conventional” railway of a “Fantasy Japan” (each game takes place on a procedurally generated island that bears little topographical resemblance to the real Land of the Rising Sun) with high-speed “bullet train” lines. Your career spans what could be considered Japan’s “golden era”, the 25 years from 1964 (historical introduction of the first Shinkansen) to 1989.
Each map features 16 cities and the inhabitants’ travel pattern is peculiar: in essence, there are commuters between any two cities identified by adjacent numbers, e.g. between “1” and “2”, between “2” and “3” etc. (“16” and “1” are considered adjacent for that purpose). At the beginning of the game, travelers follow the shortest route using the existing (conventional) rail network (grey lines).
By holding the “Z” key while moving the cursor (rounded coloured rectangle) you can connect two cities with a high-speed train line, following any available route between them (you will not be allowed to move the cursor over “forbidden” terrain). It will not replace the existing conventional railway, only run parallel to it. NB: until “Z” is released, the new route is only “in planning”.
The colour of the cursor is specific to the line, of which there can be up to five: red, green, blue, orange and purple. Once the first section of a line has been opened, it can only be “extended” (i.e. any new section must start at a terminus for that line). You can switch between lines by keeping the “X” key down when pressing the left or right arrow key.
Travelers are rational agents (some would call them AI and they’re almost certainly smarter than Sophia ;-) At the beginning of each journey, they compute the cost/benefit ratio of taking the Shinkansen: in the game, the bullet train is 5 times faster than conventional railway. By default, the cost of the ticket is JPY 5,000 per section, which is 5 times more expensive than a normal ticket. Travelers will opt to take the Shinkansen if and only if the travel time to their destination is divided by at least as much as the fare is multiplied. In other words: for the default factor of 5, only travelers whose cities of origin and destination are both serviced by the bullet train will take it.
For every section traveled by one passenger on the Shinkansen, you earn the equivalent of the fare (JPY 5,000 by default). For every section traveled by one passenger on either railway (i.e. including conventional), you must pay JPY 1,000 maintenance and operations fee. In short: if 100% travelers use the bullet train and the ticket price is JPY 5,000, you earn JPY 4,000 per passenger and per section. If fewer passengers choose the Shinkansen, your margin will shrink accordingly.
Opening one new section costs JPY 1,000,000 and you start the game with a JPY 5,000,000 budget. A new line/section can only be opened if you have enough funds available.
The yellow “post-it” note contains all the relevant information needed to play the game and plan your strategy. On the top left is the year (circled, in red). On the top right is the percentage of all ongoing journeys that use the Shinkansen. The other two numbers below are respectively the annual profit/loss (reset at the beginning of each year) and the current treasury, both in thousands of JPY.
The last section at the bottom of the “post-it” note is the current Shinkansen fare (displayed on a white/green background, my best yet pitiful attempt at reproducing an authentic JR ticket!). You change the fare (by JPY 100 increments/decrements) by holding the “X” key down while pressing the up or down arrow key. By making the necessary calculations, you can adjust it down to attract more passengers, but it will of course reduce your margin. The limits are JPY 1,000 (below which you cannot possibly break even) and JPY 5,000 (above which every traveler will choose the conventional railway over the bullet train).
This is a "sandbox" game, so you set your own objective: get 100% travelers on the Shinkansen, reach the 31,999,000 treasury limit as early as possible, use the fewest possible lines to service the whole country…
The number of travelers increases over time (by one unit every year) to reflect Japan’s booming economy. In Jan 1965, one traveler is added to the population commuting between cities “1” and “2”, in Jan 1966, it’s between “2” and “3” and so forth.
P.S. This project took longer to complete than expected and as a result, the code is rather messy... Sincere apologies to my fellow programmers with higher standards!



The city is on fire and only you can stop it. Play through 12 stages with fire to put out and civilians to save. Advance to the next level by getting rid of all the fires. Try to unlock the two hidden colors for the fighters. Once unlocked just press up at the title screen to change.
This is my first game in collection of games i will make for the pico 8. I hope you enjoy. Keep an eye out for more games soon.
--- v1.2 ---
Well I fixed a lot of little stuff that I didn't like. The collision between fighter and fire is better. A glitch that some times doesn't place something in the window is fixed. If there is no fires in the window then falling fire doesn't harm fighter. Both doors are used when rescuing civilians.
--- v1.1 ---
There is two new options in the pico menu. turn sound and flame effect on or off. also I fixed the problem with both truck appearing at the same time.



Material Capture, or "matcap" for short, is a really neat technique, and now that I've learned about it, I'm pretty surprised that it doesn't come up more often in gamedev conversations. It's great! Here's a pico8 implementation of the concept: it draws approximated realtime reflections on 3D meshes.
There are three settings that you can change while it's running:
Right/Left: Switch materials
Up/Down: Fast-mode / Slow-mode
O/X: Switch models
Fast-mode is kind of like a vertex shader in modern 3D engines (the material texture is only sampled along the edges of triangles). Slow-mode is kind of like a pixel shader (except there's no GPU to give it a speed boost)


Here is a simple function to convert a number to its hexadecimal string representation:
function num2hex(number) local base = 16 local result = {} local resultstr = "" local digits = "0123456789abcdef" local quotient = flr(number / base) local remainder = number % base add(result, sub(digits, remainder + 1, remainder + 1)) while (quotient > 0) do local old = quotient quotient /= base quotient = flr(quotient) remainder = old % base add(result, sub(digits, remainder + 1, remainder + 1)) end for i = #result, 1, -1 do resultstr = resultstr..result[i] end return resultstr end |
Usage:
print(num2hex(255)) -- ff print(num2hex(10)) -- a print(num2hex(1050)) -- 41a |


I love the simplicity of Pico, but for quick coding like in Game Jams it's nice to have a foundation to work off of. That's why I wrote this toolkit that provides some basic functionality like debugging and physics. Has anyone else done something like this before? Should I add anything else?
Thanks!



Converting shr() safely to simple math:
shr(v, 16) ==> v * 0x.0001 shr(v, 15) ==> v * 0x.0002 ... shr(v, 2) ==> v * 0x.4000 (or 0.25) shr(v, 1) ==> v * 0x.8000 (or 0.5) |
Multiplying by the fraction avoids a hazard where a negative number can go to 0 when dividing by numbers greater than 1, which destroys the sign-extending upper bits you expect to keep with shr().
It also allows shifts up to 16, whereas dividing only allows shifts up to 14. This is because PICO-8 can't represent any powers of 2 larger then 16384.
Similarly, because it is safe to divide by a fractional number less than 1, you can use the same idea to shift left up to 16 bits:
shl(v, 16) ==> v / 0x.0001 shl(v, 15) ==> v / 0x.0002 ... shl(v, 2) ==> v / 0x.4000 (or 0.25) shl(v, 1) ==> v / 0x.8000 (or 0.5) |
In this case, it's down to style or the need to shift by more than 14. Unlike dividing, multiplying by values greater than 1 is safe, so you can also obviously just convert shl(v,2) to v*4. PICO-8 performs divides as fast as multiplies, so performance is the same either way.
Basically, your safe bet is always to use the fractional power of two, whether dividing or multiplying. If you want to be sure, start your constant with "0x." and you'll always get it the right way around. :)
The reason some of us want to do this, rather than the more-intuitive shift calls, is that it saves one token per shift. That can add up quickly in a program heavy with binary math.

Yesterday, I try to create different think. First, I create a little auto tilting system in PICO-8 from this article.
After that, I create a maze generator with the Drunkard Walk algorithm (more information here). It's not very hard but I spend time on that. Finaly, I add a player, and a little hitbox system (with PICO-8 flag systeme), some monster (with lot of bugs), some coins and an exit. I've create a Rogue Like! I think I'm going to add some mecanics so, stay tuned on my Twitter!

Description
This is my platformer in the style of classic Mario games. I called it Platformer Base because I can't think of a good name. Play as the guy with the green helmet, jump on robots and stop their evil machinations once and for all!
Instructions
The game is fairly simple. Jump on the robots with O, and make it to the end of the stages. You can play them in any order you like.
Version
The current version is 1.2 and features the following changes:
+Added a flag that prevents autojumping
+Added SFX that can be toggled on and off
All previously published versions can be found Here.





On yonder thread, where you wisely noted we should stop polluting its subject, you responded to me and said:
[box=404040]Static preprocessors like cpp are a weird fit for dynamic languages like Lua. For example, cpp-style includes have no order-dependent side effects in the languages they're used for (other than in the preprocessor macro language itself, I think?), so they can more simply insert code at first mention. This is not the case in Lua. Lua modules make the handling of side effects in the code explicit, so there's no confusion as to what a require() is expected to do. I'm very interested to know why a Pico-8 developer would prefer an #include-like to a require() because I can't think of a reason, as long as require() is implemented correctly.
Re: defines and such, I think what we actually want, especially in the context of Pico-8, is build-time constant folding and dead code elimination.
But we should take build tool discussion somewhere else, so people can use this thread to discuss Compos. :)



EDIT: Fixed as of 0.2.0!
Original post:
Pretty sure when you originally added _update60(), you compensated for the doubled frame rate when returning time() values, but these days time() is running at double speed when you have _update60() instead of _update().
I noticed this when playing with a simple seven-segment-display demo. Here's one that uses update() and updates once per second as expected:
And this is the same cart, but switched to _update60() and runs twice as fast:
