I just started playing around with Pico-8 and while I've been programming for a very long time, I've never done so at such a low level so I'm finding P8 a great challenge that is wonderful escape from my daily style. That being said, I'm looking for code review-style feedback on my first little learning game.
I'm making a simple game for my preschooler daughter so it's not complicate but it's requiring me to cover all the basics for making any game - collisions, maps, sprites, movement, etc. This first pass focuses on movement and object/sprite collision. I watched the "popular" light cycle tutorial as well as read through the Fanzines and took all that cobble something together. So thanks to all of those people! It's be a treat learning something new.
Right now the game is just moving the character around and collecting food items. Run into a present and food pops out. Run into the food and they disappear (collected). That's it.
Again, I'm just looking for feedback on how it's written, probably mostly around the architecture and places where I'm wasting space. The game is working as I expected, so there are no bugs, per se...just looking for efficiencies.
I am planning on adding more graphics and stats that keep track of what's been collected. There will be other screens but that's the next lesson.
I appreciate any feedback, thanks!
pickups={} player={} box={} -- /////////////////////// function _init() cls() createplayer() createbox() end function _update() foreach(pickups,function(o) if (o.wild and collide(o,player)) then o.wild=false end end) if (collide(box,player) and box.closed) then box.closed=false for x=1,4 do add(pickups, createpickup()) end createbox() end player.update() if (btnp(5)) then createbox() end end function _draw() cls() foreach(pickups, function(o) o.draw() end) player.draw() box.draw() end -- /////////////////////// function createbox() box.closed=true box.x=flr(rnd(110)+10) box.y=flr(rnd(110)+10) box.hitbox={x=0, y=0, w=8, h=8} box.draw = function() if(box.closed) then spr(1,box.x,box.y) end end end function createplayer() player.x=60 player.y=60 player.spr={3,2} player.cel=2 player.dir=1 player.hitbox={x=1, y=0, w=6, h=8} player.update=function() -- movement controls if (btn(0)) then move(player,4) end if (btn(1)) then move(player,2) end if (btn(2)) then move(player,1) end if (btn(3)) then move(player,3) end end player.draw=function() spr(player.spr[player.cel],player.x,player.y) end end function move(obj, dir) obj.dir = dir if (obj.dir == 1) then obj.y = obj.y-1 end if (obj.dir == 2) then obj.x = obj.x+1 player.flip = false end if (obj.dir == 3) then obj.y = obj.y+1 end if (obj.dir == 4) then obj.x = obj.x-1 player.flip = true end if (obj.x <= 1) then obj.x = 1 end if (obj.y <= 3) then obj.y = 3 end if (obj.y >= (125-8)) then obj.y = (125-8) end if (obj.x >= (125-6)) then obj.x = (125-6) end --p.spr = p.spr + 1 --if (p.spr > 2) then p.spr = 1 end if player.cel==1 then player.cel=2 else player.cel=1 end end createpickup=function() local obj={} obj.x=flr(rnd(110)+10) obj.y=flr(rnd(110)+10) obj.spr=flr(rnd(5)) + 64 obj.hitbox={x=0, y=0, w=8, h=8} obj.wild=true obj.draw=function() if (obj.wild) then spr(obj.spr, obj.x, obj.y) end end return obj end function collide(obj, other) if other.x+other.hitbox.x+other.hitbox.w > obj.x+obj.hitbox.x and other.y+other.hitbox.y+other.hitbox.h > obj.y+obj.hitbox.y and other.x+other.hitbox.x < obj.x+obj.hitbox.x+obj.hitbox.w and other.y+other.hitbox.y < obj.y+obj.hitbox.y+obj.hitbox.h then return true end end |
I think lua is prety open in term of style, specialy for Pico 8 where project's keep a small size. It's true that using same functions and variables in a coherent way can lead to smaller and clearer code. Your code seem prety good already.
I have two suggestions, first removing special code in the _update() function, and only calling each pickup/player update function. So collision test should be either in player or pickup update function.
The other thing is that I prefer to use a dirx/diry than a single dir. You can even call it velocityx/velocityy, store it in the player and have simple physics, acceleration and drag on you character.
It's great that you're making this for your child. :-) What would the code look like if, instead of spawning more objects, there was just one object on the screen that disappears when you collide with it? I'm still learning the basics, and this is the closest I have come to finding a simple pickup "tutorial".
Wow...an oldie but a goldie :) Glad you're able to use it to learn something. Doing little carts like this was exactly how I got started...just basic "how do I pick stuff up" game.
The code you're after is inside the _update() function. It's the if() condition that happens when the character collides with the present item. The 'for' loop inside that condition says "create 4 new pickups and a present".
So whatever you want to have happen when you hit the box, just put inside that if() condition. If you don't want more pickup items, just delete that 'for' line and the createbox() after it.
-- When player collides with a present, do something if (collide(box,player) and box.closed) then ...do whatever you want... end |
Hope that helps a bit. The collide() function is the magic that detects when things run into each other. Honestly, that bit of code is somewhat inefficient as you see it there, but it does work just fine.
And if you're interested, that code above turned into this game...it's a little more game-y and one my kid actually played a few times.
https://www.lexaloffle.com/bbs/?pid=20318&tid=3310
Here's a link to a Pico-8 boilerplate I used when starting a new game.
https://github.com/morningtoast/pico8dev/blob/master/boilerplate.p8
The most useful stuff for you is probably at the bottom of the code, just search for #utility and you'll see a bunch of helper functions that do things like collision, angles, distance and some text functions.
The boilerplate as a whole is a little out of date from what I use today (I need to update it) but it's plenty good to try out for learning.
[Please log in to post a comment]