Been a while since I've posted something here, I've not been really active with pico-8 recently, but done a couple of stuff, really enjoy the platform, just lack of time :(
Anyway. Among Pico (not final name, if it will have a final name one day) is a test project I've started some time about (early September 2020) and been working a bit here and there since. Started just as a pure test for various effect we could do with PICO-8, ended with what it is now.
I will post a cart a bit later, need to do a bit of cleaning before posting it.
I don't have a lot of backup of old version, but I have plenty of GIF I made during the process, so let's start with that.
The name may not be clear, but the origin of the project started with Among Us in mind, and I first wanted play around the way your character move in AU and replicate that., So I made a inspired set of sprite and started to animate it on screen. Nothing really fancy and even if the bouncing is there, it don't really look good, but well I was pleased enough at the time.
And then went, ok now, AU have multiples colours palette for players, let's add that:
Nothing really fancy, but always fun to play with the palette to try to find nice combinations that works.
Reasonably satisfied with that, I went. Ok what I want to play with next. I came to the visibility shadow which is in the original game, as wall tend to cast shadow so there are area you don't see what is in there.
I started to play around, trying to identify how to do that. First working on a poly fill:
which was way more buggy than I originally though :D (will fix is latter in many iterations)
Then trying to understand how to cast the shadow from a wall in the vision area:
As you can see the projection somewhat work, but the polyfill is really buggy :D
And I ran into the problem if the corner not getting filled:
And that's about at that time I decided to look around on how other people solved that type of thing to find the blog post of the author of Dank Tomb that explain thoughtfully how he does his lighting effect, and it was quite interesting.
I decided to see if I could use some of his idea (and in the end used some of his code) for the shadow cast.
It seemed to work reasonably fine, even not being fully satisfied with how it behaved, it felt good enough for the job:
It is also about when I found another issue with my polyfill:
Which was the result of a division by zero :D
Then I' ve continued doing test also adding the possibility to change the view radius on the fly:
Then decided to build some form of a room to see how the shadow react:
With some variants:
And decided it was time to play with a tilemap, and added one of top the wall and see how it behave:
It looks nice, but something is off. You are not supposed to see everything in rooms you are not in, but at least you should see the shape of non movable thing in there.
And I remembered about a tweet from Zep about some POKE magic, and played around with it:
And I was really happy with that, it does not cost CPU time, works really well, the only drawback is you need to make sure to not draw thing in the room you don't want the player to see, and choose palette correctly for thing will look in the shadow area.
And that's when the first really laborious task of the project started. It was time to get a proper map to run around. So I went on google, search for the first AU map (the Sked) and found an image of it.
Then resize it to roughly match my sprite size (so thing don't feel too off), clean it to remove all art just keep the wall and floor, and map it in PICO-8. Yeah it actually fit in the normal tilemap (using the extended area) I was not expecting that at all! But it also come at the expense of limiting to only two tile banks, and well. That does not leave me with a lot of usable tiles in the end, but that's another story for later.
All the tiles used for the drawing all walls:
So after a while I came to that:
(You can also notice that the moving animation is more smooth and bouncy than it was, I don't remember exactly when, but I've done some tweak on it to make it looks better)
Also decided that the out of space was a bit dull so added a good old star effect:
Then came the second laborious task. mapping the wall to the actual map. I didn't really wanted to do that by hand, way too many change of error, so needed to have a break and came back with a, I think, clever idea, I temporarily change the main sprite as a single dot, and moved with it around and used printh to map all the wall corner in each of the three wall loop that map have. It really worked fine and was perfect on the first try!
Just needed to add some code to automatically create the wall list from each loop list of point, and voila:
But that's when I started to have to issues.
First, I needed to cull all the wall not on the vision area, because I had a lot of drop from 60 to 30fps, and second even after culling there were still some drops (less but still some) and found that on some wall the shadow was absolutely not behaving the way it should:
the red poly is the actual casted shadow for the wall in green, and of course that is not valid.
Can also see it in this test mode I implemented just for checking and debugging that issue:
I had to scratch my head a lot, and went into a complete rewrite of how I do extend the shadow, in a way which is still not perfect, there is still some overdraw and more than I really should draw:
But now does work in all conditions and in the expected way, and slightly unexpected bonus?
It now run at a constant 60fps! CPU use is still high, but that's to be expected there are a lot of math and drawing involved. Thing probably could be more optimised, but it is good enough for now.
Casting shadow is fun, but being a ghost walking through wall is fun for some time:
It was clearly time to make sure you cannot clip through the wall. It took me some time because I wanted to make it in a clever way, took me a couple of day away from the project to clear up my mind and get into a working solution:
And that's the current state of the project.
I'm happy if people are interested to explain how and where my shadow cast differ from @krajzeg solution, how my wall collision detection work, it is simple, probably not original, but I like how it works.
There are more thing to come with this project, including something it is way to early to talk about. I may stream working on that project on twitch at a later point.
I will post a cart a bit later I just need to make sure it is good enough for a demo release ;)
Hope the reading was interesting :)
Edit: I've added the cart on the top of the message and as all the key binding are not obvious:
Player1 ⬆️⬇️⬅️➡️ : move around
Player1 ❎🅾️: cycle between player color
Player2 ❎🅾️: change the visibility area
And before people ask. No I don't normalize diagonal movement, because moving the camera with that make movement look super choppy and I prefer that people move a bit faster than annoying visual.
One of the problem with the original sked map, is that most wall were not on a tile boundary, and it use different angle for the non horizontal/vertical wall. I had to do some changes to lower the tile count.
I'm using promotion for all tile/pixel art based work, and started with around 4000 tiles with the original image, ended with about 40, that's a nice reduction!
Also I know that the wall in Electrical do not cast shadow. It was not on the original map I draw (forgot about when I cleaned the map) si the wall list does not have the point for that one. I need to add them at a later point.
Also the WALL stats is the number of wall currently in the visibility area
@zep: I think there is a bug with the BBS/Splore, the cart does not show in splore, I can't even find it by searching cart by me or with the name...
I've try to delete/recreate the topic, and same issue.
I remember in the old day if you were creating a topic without a cart, it would not appear in Splore. Don't know if that was fixed or not.
Edit: That's interesting. If I move the cart to the top of the first message, it now shows it.
It really feels like a bug
I edited the player sprites and animation
Modified sprites and animation code:
tab 2, replace line 156
spr(2*flr(self.frame), self.pos.x-8, self.pos.y - (self.jumpy/2)-8, 2, 2, self.fleft)
tab 2, replace lines 130 to 147
if self.move == true then -- removed original animation self.jumpyp=self.jumpy self.jumpy += self.jumpd if self.jumpy >= 3 or self.jumpy < 0 then self.jumpd = -self.jumpd end -- walk frames if self.jumpy<0.5 then self.frame=1 if nextframe then if wf==0 then wf=2 else wf=0 end nextframe=false end else nextframe=true self.frame=wf end -- idle frame else self.frame = 7 self.jumpy = 0 self.jumpd = abs(self.jumpd) self.framed = abs(self.framed) end
[Please log in to post a comment]