Controls: Left, Right
Get past the traffic herd to escape and win!
Hit z/x/c to restart after win/loss
Taffic World!!! Evade the cops and escape!
This is a simple but playable prototype of an idea I had about crashes and traffic management. I started it in the recent ludum dare but didn't have enough free time over the weekend to get something done so I figured I'd just finish it up through the week.
Basically, crash other cars, cause pileups, and stall the cops until you can get through the gridlock. There's only one level and it's very simple right now... if there's enough interest I may expand on it.
Possible full-fledged game of this would be something like infinity lanes rather than just 15 and various driving floats and food trucks and such that you can visit somehow. Basically a literal traffic world made of only lanes and driving endlessly in some one direction. Not sure how it would work exactly but I figured this simple first stab gives an idea of some of the mechanics around causing accidents.
- Make the cops not start flooding in until after your first accident
- Increase number of max cops from 35 to 40 since the beginning is much easier now
- Make all cars use turn animations
- Made colors less pretty but easier to read
- Made cops brighter and more noticeable
- Made player car bright red with a stripe
- Made turning and loss of traction animations
- Slight screenshake on loss of traction
- Slowed down shifting traffic lanes a little (aka "linkers")
- Slowed down new approaching traffic (aka "joiners")
First release, v0.1
Anx - A game about social anxiety. Make your way to the safety of your home while avoiding humans and trying not to panic. Explore 3 different somewhat large 3d areas (defined using the 2d pico8 map tool) and get chased down by chatty pathfinding mobs look at you in your eyes and make your poor digital self flip out and lose touch with reality as the pixels of the world tremble and break apart.
up/down - forward/backwards
left/right - turn
A/B - strafe left/right (if using the keyboard, use X and C. If you want to reverse these there's an option in the menu.)
source on github - It's compiled into anx.p8 from a few different files then the whitespace and comments are stripped out into publish.p8. Start with main.lua which will be the easiest to read and which contains all the code and references to the other files.
This is a 3D game I've been working on for awhile which is not really done in that I'd like to put much more art in it (it has room for ~3x the art that's in there so far) but it's basically feature complete and playable so I figured I'd release a first version since the previous WIP was very old. The code is a little rugged and I'm not sure I'd recommend reusing it (although you totally can if you want) but I just thought it was a fun way to explore what Pico-8 was capable of while getting my hands dirty with low level 3D code. It doesn't perform super well and there's some room for further optimization but it's fairly far in the realm of diminishing return at this point when the game already mostly works.
It renders the walls and mobs differently, but what they have in common is that it starts from the left and renders every pixel column individually. If it detects that it's running out of time, it will skip a column by rendering the next column twice as wide. Using this method, it's able to (most of the time) keep up at 30 fps even though the underlying code is not super efficient or mathematically sophisticated. It's a little bit more complicated than this because it actually renders the pixel columns of the objects one at a time and sorts them by depth and figures out how wide each wall/mob pixel is by which rays hit them, but that's the general idea.
When anxiety is accumulated, random vertical offsets are added to each pixel column to make them look sort of like rumbling books on a shelf as well as fisheye, field of view, height adjustments, and a terrible stress inducing music track. Once the panic attack hits... well, the books get torn apart ;P
Walls - Each pixel column is calculated independently and the height is drawn according to distance to the intersection of the wall, which gives the walls the nice even slopes. Because walls are always aligned to x/y axis, the calculations for this are simpler and quicker.
Mobs - Each mob has each pixel column rendered individually, but where the mob will be rendered on the screen is sort of planned/cached once per frame per mob instance on the screen lazily the first time the mob is struck by a ray. The mobs are calculated based on distance to the center of the mob which is why the mob edges are not sloped (unlike the walls) and they are only horizontally skewed. The darkened side edges are somewhat inelegantly hacked in to look 3D but are just sort of "cast" off of the pixels based on basic dot product calculations of 90 degrees off the face. I like the aesthetic though :D
Current version: 1.3 - Fix bug where music persists past blackout
1.2 - Made jittery anxiety effect and music not kick in until you've been talked at a few times, although the other effects still act as normal
Note - annoying bug where music persisted after blacking out (sorry)
1.1 - Made park walls easier to visually read and navigate
1.0 - First release version - Pathfinding, better anxiety, more fleshed out objectives, and a filled out map.
0.4 - Experiments with fisheye
0.3 - More levels and spinning objects, better graphics source
0.2 - Anxiety effects and improved graphics
0.1 - Initial WIP release
I was doing Ludum Dare 38 this weekend but I hated the theme and my mechanics weren't coming together so I decided to submit a mapscale function I figured out instead in case it was useful to someone.
It's basically identical to the map() function, except it takes a scale parameter also, similar to sspr (although it doesn't scale width separately from height, though you could add that with only a few quick adjustments if you wanted it). It uses sspr under the hood which is probably not super performant, but it seems to work well enough and I doubt there's a much faster way to scale a full screen worth of sprites anyways if that's what you need to do. It can be zoomed down past 1x or as high up as you want.
To try the demo just hit Z to zoom out. It does 4x,3x,2x,1x in order and then loops back to the beginning again twice as slow each loop so you can inspect how the pixels are getting smooshed if you like. It could probably be improved as when it's slow the scaling is a bit ugly, but it looks fine if you do it quickly.
Below is the code, I tried to add comments to make it a little clearer and I took as much code as I could out of the inner loop for performance. You might be able to optimize the code further, I didn't spend much time on optimization, but I think this is pretty reasonable as is. If you're scaling a full screen of sprites you probably aren't jonesing for performance anyways. I left a parameter for specifying layers but I didn't implement it, shouldn't be hard though it already pulls up the sprite id.
function ceil(num) return -flr(-num) end function map_scaled(cell_x,cell_y,sx,sy,cell_w,cell_h,layer,scale) local sprite_id local drawx,drawy,draww,drawh local spritex,spritey,spritew,spriteh local lcell,rcell,bcell,tcell,wcell,hcell local cell_x_current,cell_y_current for offsetx=0,flr(cell_w)+1 do cell_x_current = cell_x+offsetx --x pointing to current iterated cell -- these are the most i could move out of the y for loop -- makes it a bit confusing but otherwise lots of wasted calculations --these take into account a cell getting cut off lcell=max(cell_x,flr(cell_x_current)) --left bound of current cell rcell=min(flr(cell_x_current)+1,cell_x+cell_w) --right bound of current cell wcell=rcell-lcell --width of current cell spritew=wcell*8 --width of sprite, taking cutoff into account draww = wcell*scale*8 --width of rectangle to draw sprite in drawx=flr(sx+offsetx*8*scale)-(cell_x_current-lcell)*8*scale --x to draw rectangle at for offsety=0,flr(cell_h)+1 do cell_y_current = cell_y+offsety --y pointing to current iterated cell sprite_id = mget(cell_x_current,cell_y_current) --sprite id corresponding to current iterated cell spritex=(sprite_id%16)*8+(lcell%1)*8 --x of sprite (if the sprite gets cut off, it's the left bound of the cutoff) --these take into account a cell getting cut off bcell=max(cell_y,flr(cell_y_current)) --bottom of the cell is technically top of the screen. ie, lowest y tcell=min(flr(cell_y_current)+1,cell_y+cell_h) --top bound of current cell, highest y hcell=tcell-bcell --cell height spritey=flr(sprite_id/16)*8+(bcell%1)*8 --y of sprite (if it gets cut off, it's the lower y bound of the cutoff) spriteh=hcell*8 --height of sprite, taking cutoff into account drawh = hcell*scale*8 --height of rectangle to draw for current sprite drawy=flr(sy+offsety*8*scale)-(cell_y_current-bcell)*8*scale --y to draw rectangle at if draww > 0 and drawh > 0 then --skip if there's nothing to draw sspr(spritex,spritey,spritew,spriteh,drawx,drawy,ceil(draww),ceil(drawh)) --round width/height up so there are no gaps end end end end
Let me know if you have any questions, want me to add anything (like scaling x separately from y, implementing the layer checks, etc), or if you find it useful. Do feel free to reuse it without permission. Happy coding
Controls: Arrow keys only.
Here's my first finished Pico-8 cartridge, "Material Girl", which is also my first finished game (of hopefully many more!).
It's a goofy little puzzle game that's sort of a mashup of a dating sim and JRPG-style combat.
It's a very simple game, but it took me a long time due to being distracted by my day job and perhaps spending too much time overengineering the underlying code :P Due to code size limits it's definitely about finished, I could push it a bit further with a minimizer but I'm relatively happy with it.
I built mini libraries for keeping track of persistent sprites, promises, and doing complex sequences of tweens. If anyone has interest in using this code feel free, or let me know if you want me to clean it up and extract it into a separate file for easier reuse. They do take up a good chunk of space so they only make sense if you want many sequential and overlapping tweens on things like position, scale, etc. Since this game is turn based on animation-heavy it made sense for me but it probably won't make sense for a platformer or something like that which is more based on real time input.
Happy to hear any constructive feedback, I know the sound effects are kind of poor and it could use more music but I did what I could haha. Hope you enjoy it!