Log In  

Turn your 2D game into a 3D game!

That's 50% extra D!
100% guaranteed to work, sometimes, if you're lucky.
Simply paste this into the top of your 2D game, and be the envy of all your 2D coding friends!!!1!1

(OK, I'll stop now.)

This works best for top down games like "Pic-oh mummy!" by @Hokutoy, "Pakutto boy" by @Konimiru (both pictured)
Admittedly it's more of a gimmick/experiment - the result isn't very playable due to not being able to see the whole play area.

I mainly just wanted to see if it would work :)

  return (x-_.cx)-64,_.ch,128-(y-_.cy)
  local scale=_.d/z
  return x*scale+64,y*scale+_.ymid,scale

 _.cx=x or 0
 _.cy=(y or 0)+_.cyoff


 local wx,wy,wz=_.s2w(x,y)
 local px,py=_.proj(wx,wy,wz)

 local wx,wy,wz=_.s2w(x,y)
 local px,py,scale=_.proj(wx,wy,wz)

 w=w or sw
 h=h or sh
 local wx,wy,wz=_.s2w(x+w/2,y+h)
 local px,py,scale=_.proj(wx,wy,wz)
 local pw,ph=w*scale,h*scale

 -- sub pixel stuff
 local x0,x1=flr(px-pw/2),flr(px+pw/2)
 local y0,y1=flr(py-ph),flr(py)


 if(not n or not x or not y)return
 -- convert to equivalent sspr() call
 w=(w or 1)*8
 h=(h or 1)*8
 local sx,sy=flr(n%16)*8,flr(n/16)*8

 cx=cx or 0
 cy=cy or 0
 x=x or 0
 y=y or 0
 w=w or 128
 h=h or 64

 -- near/far corners
    local fx,fy,fz=_.s2w(x,y)
    local nx,ny,nz=_.s2w(x,y+h*8)

 -- clip

 -- project
 local npx,npy,nscale=_.proj(nx,ny,nz)
 local fpx,fpy,fscale=_.proj(fx,fy,fz)

 -- clamp

 -- rasterise
 local py=flr(npy)
 while py>=fpy do

  -- floor plane intercept
        local g=(py-_.ymid)/_.d
        local z=_.ch/g      

        -- map coords
        local mx,my=cx,(fz-z)/8+cy

        -- project to get left/right
        local lpx,lpy,lscale=_.proj(nx,ny,z)
        local rpx,rpy,rscale=_.proj(nx+w*8,ny,z)

        -- delta x
        local dx=w/(rpx-lpx)

        -- sub-pixel correction
        local l,r=flr(lpx+0.5)+1,flr(rpx+0.5)

  -- render


EDIT 1: adjusted near plane to avoid numeric overflow. Defaults for omitted map() parameters.
EDIT 2: also 3Dise sspr, pset and circ
EDIT 3: sub-pixel logic
EDIT 4: add map() layer parameter. fix gaps between adjacent sprites.

New version!

I've made a new version called Instant 3D plus! :-).
It should behave exactly like the original, but it's cleaned up quite a bit, and you can call the 3D functions directly to fix the bits that it doesn't get right automatically - or place things in exact 3D positions (like up in the air).

More details in the other post.

P#75793 2020-05-04 11:57 ( Edited 2020-05-17 01:05)


It's pretty fantastic to see a 2D project in 3D :) Thank you.

...And sometimes it's not so simple haha.

P#75797 2020-05-04 15:09 ( Edited 2020-05-04 15:15)

Brilliant yet fails miserably on any game I tried!

P#75798 2020-05-04 18:00

No refunds!

Here's a few more:

"Mazeborn" by @gymcrash

"Lazarus the lizard" by @Truttle1

"Pico sprint" by rylauchelmi

"Escape from squirrel park" by @Nikkei

"Object system demo" by @Saffith

"D-Day" by @projectSAM

P#75815 2020-05-05 00:06 ( Edited 2022-02-15 07:11)

I tried it with my project Delve and it turned out really weird

Really cool stuff though, love how simple it is to install.

I also used it on CoinDash and this is amazing!

P#75824 2020-05-05 05:42 ( Edited 2020-05-05 05:52)

@Mot Seeing this has 100% made my day. It's the 3D version of D-Day that I always wanted to get round to making. Now I don't have to - thank you! I can't wait to see how the final Hitler boss works in this...

P#75833 2020-05-05 08:43

Love it!

Awesome way to add perspective in a game.

I'll try it!

P#75834 2020-05-05 09:19

@projectSAM - It's a cool looking game. Reminds me of "Commando" or "Ikari Warriors" on the old 8-bit computers.
If you specify the width in tiles when you call map() it should clip off the right hand side, so you get a proper column instead of seeing the whole tilemap.

P#75836 2020-05-05 10:59

Adding/modifying a few camera() commands makes 3D "Pakutto Boy" quite playable.

P#75838 2020-05-05 11:17

Hey, this is super cool. I noticed that you're using a table to store the original functions. Could you not save a little table-lookup overhead by using a do end block instead?

 local _print=print
 function print(s,x,y,c)
  --fancy 3D version

This way there is no extra cost from dereferencing the table. Regardless, I'm gonna give this a shot as a starter point for a project :)

P#75876 2020-05-05 19:50 ( Edited 2020-05-05 19:51)

This is really awesome, will definitely have to give it a try.

P#75883 2020-05-05 20:56

Wow, that's really cool! Thanks for trying it out on that little lizard game I made! :)

I wonder what it would look like if the PICO-8 IDE was made 3D...

P#75919 2020-05-06 01:52 ( Edited 2020-05-06 01:53)

I was planning on playing around with this and seeing what can be done with it on a blank project, but it doesn't appear to be working correctly? The perspective is nothing like in the screenshots. All it is doing is panning the camera.

P#75930 2020-05-06 03:04 ( Edited 2020-05-06 03:04)

@Lafolie do you have the latest 0.2.0 version?
There were some tline() issues in earlier versions.
I'm using 0.2.0e (although I noticed 0.2.0f has been released)

P#75931 2020-05-06 03:34

@Mot yeah I'm on 0d... I thought I updated to e though?! Strange. I'll update and get back to you.

P#75932 2020-05-06 03:37

It's a shame that tline doesn't accept the same optional layers attribute map does. Looks rather weird when these lads are flat on the map where there spawn points are defined and also running about.

Not sure what's going on with this one! Funnily enough Sonic does have running animations normally but it's broken here somehow. This is a really old unfinished project though and I don't really remember what most of the drawing code is doing and I don't have the time to dig into it right now.

P#75938 2020-05-06 07:20 ( Edited 2020-05-06 07:24)

@oakreef yeah, I noticed the layers issue too with some of my projects. If a layer parameter was added to the tline() command then it could be done properly.

The sonic one looks like it's not clearing the screen before drawing a frame...? Are you doing something clever, like dirty rectangles?

P#75988 2020-05-06 21:22

It's been ages since I touched that code and I don't want to dig through it now but IIRC I never bothered clearing the screen because the first thing it draws anyway is pink rectangle across the entire screen, which would wipe out the previous frame anyway. The intent was to eventually draw a proper background with parallax but I never got around to it.

P#75989 2020-05-06 21:25 ( Edited 2020-05-07 06:56)

Minor tweak to clean up raggedy lines



P#76017 2020-05-07 07:14

Just tried your code in my Imi's Dungeon game.
It exposes my tile entities xD.

P#76033 2020-05-07 11:50 ( Edited 2020-05-07 11:50)

@Mot it looks like Zep added layers to tline for 0.2.0h!

P#76083 2020-05-07 18:35

@oakreef cool. I've updated the snippet.

@NeithR lol :). Pay no attention to the man behind the curtain...

P#76103 2020-05-07 23:39

Not bad! Works decently well on my Breakout game with only one addition for camera()

P#76274 2020-05-09 21:48

I remade WoolCat as WoolCat 3D

P#76307 2020-05-10 11:03

Oh my God bless you, this is probably the best thing that has happened to me this whole year you are amazing

P#76436 2020-05-12 11:32

Like Jelpi 3d?

P#76437 2020-05-12 11:38

I made a quick little game with your Instant3D. Very nice!

P#76453 2020-05-12 17:07

Cart #nemuwizey-2 | 2020-05-13 | Code ▽ | Embed ▽ | No License

Guys, very simple test. Game-code labirynth like, also for beginners to learn. Code is super easy, if you want to start your own. Can turn into pac-man etc. 3D effect works great!

P#76481 2020-05-13 01:26 ( Edited 2020-05-13 01:34)

The one game that I have actually completed gave very amusing results.
Something about the game just hated the 3d code

P#76490 2020-05-13 11:04

Very usefull I enjoy it for a future game...

P.s. How about ask ZEP to put that code snippet as internal function in next Pico-8 version? as a poke or an I3D()

this snipped will be very used in the future tough! :)

good for my first 3d racer soon! btw.

P#76502 2020-05-13 15:29 ( Edited 2020-05-14 17:01)

This makes my cave game so much more immersive!

I had to add sprites over the top of the map tiles that were walls to "lift" them up. I'm using sprite flags to mark them. I'm going to try and bake that into the function, but it would have to be a second drawing pass because a single map call could included both types.

P#76649 2020-05-15 17:51

@Mot wow, thanks for trying out your great coffee on mazeborn... It's given me some perspective (!) on how my 3d version is going...

P#76910 2020-05-19 16:29

Can you switch this on and off?

I'm making a game that's part overhead map and part side on platform. The map part may benefit from this angle.

P#79219 2020-07-12 20:20

@garryg I made an updated version here with the ability to turn it on/off - plus some other cleanups etc.

P#79222 2020-07-12 21:24

I mean

P#106295 2022-02-04 03:40

Cart #deyikafite-0 | 2022-02-04 | Code ▽ | Embed ▽ | No License

function _init()
for i=0,127 do

function _update()
  for i=0,127 do
    if sy[i]==128 then
  print("jet flight at night",26,58,1)
  print("lib by mot",44,66,1)

Outstanding work, @Mot. Real gold star achievement.

Just wanted to state it would be useful to have a keystroke such as [TAB] to flip back and forth between using the 3D LIB and normal 2D graphics. This can be disabled as well.

P#106305 2022-02-04 06:10 ( Edited 2022-02-04 06:49)

Cart #yerujagune-0 | 2022-02-04 | Code ▽ | Embed ▽ | No License

Can someone please show me how to make this 3D using this lib ? As you can see it's not doing it right.


I am using this SPRITE ^ and want to make a 3D grid like this using sspr():

P#106308 2022-02-04 06:45 ( Edited 2022-02-04 07:10)

Heh, nice! Reminds me of The glEnd() of Zelda.

P#106313 2022-02-04 07:07


Here's an example.

Cart #instant_3d_grid_example-0 | 2022-02-07 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

I used the newer version of the snippet, which is a bit cleaner and has a few more features (like toggling back to 2D).

Basically you have to use a map, as maps get drawn as a flat plane, whereas sprites are still drawn upright.

P#106482 2022-02-07 07:48 ( Edited 2022-02-07 07:49)

@Mot Hope one day you plan to do this code snippet for Picotron. I just imagin how my games like Crazy Position / Crazy Rally deluxe looks like in it.

P#146197 2024-04-09 19:54 ( Edited 2024-04-18 16:13)

@BGelais that's actually a good idea.
I'd need to learn Picotron a bit better first though.

P#146221 2024-04-10 02:10

[Please log in to post a comment]