Io's Cosmic Orbit (A DOTA 2 Io Fangame)
[EN] This is a fast-paced arcade mini-game featuring Io (Wisp) from DOTA 2! Navigate through dangerous cosmic space, manipulate your guardian spirits, and survive against waves of enemies.
We've optimized the tutorial/early-game flow and buffed the mini-bosses for a greater challenge!
[CN] 这是一款基于 DOTA 2 英雄小精灵 (Io) 核心机制制作的快节奏像素街机同人游戏!在密集的攻势中灵活走位,操控你的幽魂法球,活下去!
新版本优化了新手流程,并强化了小 Boss 的挑战性与 AI 表现!
🎮 Controls / 游戏控制:
TAB 1:
function _init()
init_game()
end
offset=0
function _update()
if state == "play" then
-- gameplay logic
if player_dead then state = "gameover" end
elseif state == "gameover" then
if btnp(4) then
-- restart game
_init()
state = "play"
end
end
if game_state=="wave_start" then
spawn_timer -=1
if (spawn_timer<=1) spawn_wave()
elseif game_state=="playing" then
if (enemies_left <0) game_state="intermission"
end
if game_state=="intermission" then
wave +=1
spawn_timer=1
game_state="wave_start"
spawn_wave()
end
offset=(offset+1)%128
update_enemies()
p.x=mid(0,p.x,120)
p.y=mid(0,p.y,120)
if (collision_happened) p.state="dead"
if p.state=="alive" then
if btn(⬅️) then
p.x -=1.5
elseif btn(➡️) then
p.x +=1.5
elseif btn(⬆️) then
p.y -=1.5
elseif btn(⬇️) then
p.y +=1.5
end
end
if btnp(4) then
sfx(0)
-- add new bullet to list
add(bullets, {
x=p.x +2,
y=p.y -2,
speed=2
})
end
for b in all(bullets) do
b.y -= b.speed -- move up
if b.y < 0 then del(bullets, b) end -- remove
end
end
function _draw()
cls()
if wave==nil then wave="1" end
print("wave: ",10,10,8)
camera(cam_x,cam_y)
map(0,0,0,0,128,64)
map(0,0, -offset,0,16,10)
map(0,0,128 -offset, 0,20,16)
draw_enemies()
for e in all(enemies) do
spr(e.spr,e.x,e.y)
end
if p.state=="alive" then
spr(p.sprite,p.x,p.y)
else
print("game over",50,60,8)
spr(17,p.x,p.y)
end
for b in all(bullets) do
rectfill(b.x,b.y,b.x+1,b.y+2,10)
end
end
TAB TWO:
function update_enemies()
for e in all(enemies) do
e.y += 1 -- move down
e.y -= 1 -- move up?
if (p.x < e.x) e.x -=.80
if (p.x > e.x) e.x +=.80
if (p.y < e.y) e.y -=.80
if (p.y > e.y) e.y +=.80
if(e.hp <= 0) then del(enemies, e) end
-- remove if off screen
if e.y > 128 then del(enemies, e) end
-- simple collision with player bullets
for b in all(bullets) do
if abs(e.x - b.x) < 4 and abs(e.y - b.y) < 4 then
sfx(3)
e.hp -=1
del(bullets, b)
end
end
end
for en in all(enemies) do
for oen in all(enemies) do
if (oen != en) then
local dx,dy=oen.x-en.x,oen.y-en.y
local d=30
if abs(dx)<d and abs(dy)<d then
local a=atan2(dx,dy)
en.x-=cos(a)0.7
en.y-=sin(a)0.7
end
end
end
end
for en in all(enemies) do
if check_collision(p, en) then
-- handle collision (e.g., game over, lose hp)
p.state=false
p.hp -=1
sfx(4)
game_state="over"
end
end
end
tab three:
function draw_enemies()
for e in all(enemies) do
spr(e.spr, e.x, e.y)
end
if game_state=="play_next_wave" then
if #enemies==0 then
wave_number +=1
spawn_wave()
end
end
end
tab four:
function init_game()
gamestate="play"
p={x=64,y=100, sprite=1, hp=10, state="alive"}
enemies={}
bullets={}
wave_number="1"
enemies_left=0
spawn_timer=5
game_state="wave_start"
game_over=false
end
tab five:
function check_collision(a,b)
return abs(a.x-b.x)<4 and abs(a.y-b.y)<4
end
tab six:
function spawn_wave()
for i=1, wave*1 do
add(enemies, {x=rnd(128), y=0, w=8, h=8, hp=5, spr=4})
enemies_left +=1
p.hp -=1
end
game_state="play_next_wave"
end

function _init()
p={1,3,5,7}
p.x=64
p.y=64
p.sp=1
p.frame=0
p.timer=0
p.anim_speed=0.15
end
function _update()
local lx=px
local ly=py
if btn(⬅️) then
flip_sprite=true
p.x -=1
end
if btn(➡️) then
flip_sprite=false
p.x +=1
end
p.timer +=1
if p.timer > 6 then
p.timer=0
p.frame=(p.frame+1)%2
end
end
function _draw()
cls()
local current_sp=p.sp+(p.frame*2)
spr(current_sp,p.x,p.y,2,2,flip_sprite)
end

Hi everyone,
This is my first post here—a bit of a "love letter" to PICO-8 and Picotron.
First of all, I want to say a huge thank you to @zep. I truly admire both the console and the workstation; they are such a pleasure to work with. However, the most important component is the community. This group's friendliness, coziness, and openness fuel so much interest and creativity.
I am constantly amazed by what people achieve within such limited environments. There are countless examples of PICO-8 projects that "shouldn't" be possible, yet they thrive through sheer creative thinking. Inspired by all of you, I’ve finally found the courage to start contributing back with my own projects, tools, and games.
Teaching with PICO-8
For the past year, I’ve been teaching programming to kids at a weekend school using PICO-8 as our primary platform. We’ve leaned heavily on the incredible tutorials by @Krystman, @NerdyTeachers, @MBoffin, @2darray, @Gruber, and many many others.

function _init()
state="start"
putbacks={}
setup_game()
p={}
p.x=64
p.y=64
p.sp=1
p.atk_sp=3
p.is_attacking=false
p.atk_timer=0
p.atk_duration=10
end
function _update()
--thinking/logic/math--
if state=="play" then
move_player()
elseif state=="start" then
if btnp(❎) then
state="play"
end
elseif state=="win" then
if btnp(❎) then
setup_game()
state="start"
animate_walk()
start_attack()
end
end
end
function _draw()
--visuals--
cls()
local s=p.sp
if (p.is_attacking) s=p.atk_sp
if state=="play" then
map()
aniplr()
pickups()
draw_ui()
elseif state=="start" then
print("press ❎ to start",30,60)
elseif state=="win" then
print("your journey has come to end. now rest.",30,60)
end
---print(py)
end
function setup_game()
--sets up stuff
px=63
py=63
pf=1--player frame
flp=false --player flip
goal=1 --how many articats
init_ui()
for t in all(putbacks) do
mget(t.x,t.y,33)
end
table={x=10,y=23},{x=2,y=3},{}
putbacks={}
end
--animation--
function aniplr()
--animate stuff
if pf>2.95 then
pf=1
else
pf+=.05
end
spr(pf,px,py,1,1,flp)
camera(px-63,py-63)
if btnp(❎) and not p.is_attacking then
p.is_attacking=true
p.atk_timer=3
end
end
--pickups--
function pickups()
local ptx=(px+4)/8
local pty=(py+4)/8
spover=mget(ptx,pty)
if spover==30 then
mset(ptx,pty,17)
add(putbacks,{ptx,pty})
points+=1
if points>=goal then
state="win"
end
end
end
--points/ui--
function init_ui()
points=0
end
function draw_ui()
print("treasure: "..points,10,10,7)
color(10)
end
--player movement--
function move_player()
local lx=px
local ly=py
if btn(⬅️) then
px-=1
flp=false
elseif btn(➡️) then
px+=1
flp=true
elseif btn(⬆️) then
py-=1
elseif btn(⬇️) then
py+=1
end
local ptx=(px+4)/8
local pty=(py+4)/8
--is the player over a tile
--that has flag 0?
if fget(mget(ptx,pty),0)==true then
px=lx
py=ly
end
if btnp(❎) and not p.is_attacking then
p.is_attacking=true
p.atk_timer=0
end
if p.is_attacking then
p.atk_timer +=.25
if p.atk_timer >=p.atk_duration then
p.is_attacking=false
end
else
if (btn(0)) p.x -=1
if (btn(1)) p.x +=1
end
end
--attack systems
function start_attack()
player = {
x = 64,
y = 64,
atking = false,
atk_timer = 0
}
if btnp(4) and not player.atking then
player.atking = true
player.atk_timer = 10 -- attack lasts for 10 frames
end
-- handle attack timer logic
if player.atking then
player.atk_timer -= 3
if player.atk_timer <= 0 then
player.atking = false
end
else
-- move code goes here so player stops during attack
update_movement()
end
end

me.
a tiny companion.
what
me. is a small creature that lives on your screen. it has four needs:
hunger, fun, energy, love. you press buttons. me. reacts.
it is a tamagotchi in shape, but not in spirit.
what me. actually is, is closer to a face that breathes. a body that
gets tired. eyes that look away when sad. eyes that find yours when
trust has built up over time. a mouth that quivers before something
real happens.
if you ignore me. for too long, me. will get hungry. then sad. then
desperate. then me. will die, and the death will be unlike anything
you have seen in a tamagotchi-shaped game.
controls
- up : feed
I love this little machine. It can do everything I want it to. The community is super supportive as well. I remember a time when I joined a game jam and said in the group chat I was using PICO-8. Somebody using Unreal said I was on easy mode and I was flabbergasted. Making a game is easy no matter the tools you use. Making a game with an adjective is the hard part. Maybe making a bad game is easy, but you get what I mean. Regardless, I love posting on here and hearing from people. Building little toys to play with, experiences to chew on, or making games with spunk, this thing can do it all for me.
Thank YOU for making PICO what it is. I appreciate your artistic choice and direction with what you make and/or consume on here. I do it for you. I love all you strangers. Viva La PICO!
With love,
The Wall (or Squee)
|
|
[8x8] |





0 comments
.png)

