
falling face
Welcome to what can only be described as a fully functional accident running inside PICO-8.
You move. You shoot. Things fall from the sky. You survive purely out of stubbornness and the fact that the enemies are too confused to coordinate an actual attack pattern.
This is a top down shooter where everything technically works, nothing behaves politely, and the entire game loop was held together with determination, debug prints, and questionable decisions that somehow became features.
Enemies spawn from the void, drift downward like they forgot why they exist, and occasionally change identity just to keep things emotionally unstable. You shoot them, they respawn, and the cycle continues until either you win or your hands give up.
There is a health system. There is a score system. There is also a difficulty system that increases so slowly you will question whether it is doing anything at all.
It is not balanced. It is not polished. It is barely contained chaos.
But it is yours.
Made entirely in PICO 8, this project proves that yes, you can build a playable arcade shooter with nothing but tiny sprites, simple math, and refusal to quit.
How to play
Move with arrow keys Z to shoot Do not get touched Pretend you are in control of the situation
Features
A player that moves like it is slightly tired Enemies that respawn instead of learning Bullets that obey physics but not logic A score system that exists purely for motivation A health system that slowly teaches consequences Difficulty scaling so subtle it might be a myth
This code is for you to see my bad code.
function _init()
cls(5)
bullets = {}
enemies = {}
x_position = 64
y_position = 64
x_movement = 0
y_movement = 0
bullet_speed = 3
score = 0
player_health = 3
hit_timer = 0
flash = 0
diff = 1
for i=1,3 do
add(enemies, {
x=flr(rnd(110)+10),
y=flr(rnd(128)),
spr=flr(rnd(3)+4)
})
end
end
function wrap(v)
if v > 128 then return 0 end
if v < 0 then return 128 end
return v
end
function reset_game()
bullets = {}
enemies = {}
x_position = 64
y_position = 64
x_movement = 0
y_movement = 0
score = 0
player_health = 3
hit_timer = 0
flash = 0
diff = 1
for i=1,3 do
add(enemies, {
x=flr(rnd(110)+10),
y=flr(rnd(128)),
spr=flr(rnd(3)+4)
})
end
end
function _update()
if hit_timer > 0 then hit_timer -= 1 end
if flash > 0 then flash -= 1 end
if btn(0) then x_movement = -2 end
if btn(1) then x_movement = 2 end
if btn(2) then y_movement = -2 end
if btn(3) then y_movement = 2 end
if btnp(4) then
add(bullets, {x=x_position, y=y_position-5})
sfx(3)
end
diff += 0.0001
if x_movement != 0 and y_movement != 0 then
x_movement *= 0.7
y_movement *= 0.7
end
x_position += x_movement
y_position += y_movement
x_movement = 0
y_movement = 0
x_position = wrap(x_position)
if y_position < 0 then y_position = 0 end
if y_position > 120 then y_position = 120 end
for b in all(bullets) do
b.y -= bullet_speed
if b.y < 0 then
del(bullets, b)
end
for e in all(enemies) do
if abs(b.x - e.x) < 8 and abs(b.y - e.y) < 8 then
score += 1
e.x = flr(rnd(110)+10)
e.y = -5
e.spr = flr(rnd(3)+4)
del(bullets, b)
end
end
end
for e in all(enemies) do
e.y += 1 * diff
if e.y > 128 then
e.y = 0
e.x = flr(rnd(110)+10)
e.spr = flr(rnd(3)+4)
end
if hit_timer == 0 and abs(e.x - x_position) < 8 and abs(e.y - y_position) < 8 then
player_health -= 1
hit_timer = 30
flash = 7
sfx(2)
if player_health <= 0 then
reset_game()
end
end
end
end
function _draw()
if flash > 0 then
cls(6)
else
cls(5)
end
spr(1, x_position, y_position)
for e in all(enemies) do
spr(e.spr, e.x, e.y)
end
for b in all(bullets) do
spr(3, b.x, b.y)
end
print("score: "..score, 2, 2, 7)
print("lives: "..player_health, 2, 8, 8)
end

Leave a comment
Log in with itch.io to leave a comment.