I've been trying ways to take a specific sprite and replace all of them on the map with another sprite.
Here are two methods I figured out.
This here is the first method and the one I use in my Pico-8 game "Marley The Adventurer". Probably the most simple and reliable method. It just scans all tiles one by one every time it wants to swap and immediatly replaces it by the other tile if the tile matches the one specified. It uses almost no extra RAM, but a lot of CPU usage. And if one of the tiles gets removed or if one gets added it will still react properly and replace the new tiles as well.
The function takes two parameters:
Now for the next one
This method works by scanning the whole map when you run the cart (which may lead to longer loading times) and stores the sprites coordinates into a variable. The tile replacing function simply reads the coordinates that were in memory and replaces them with a given sprite. This method is good when you have few tiles to replace, as it takes just a bit more RAM to save a lot of CPU, but if you want to replace a sprite that is drawn almost all over the map, this method will save a tiny bit of CPU and take a lot more RAM. It also takes more code and has the downside of not responding to map changes: it will still try to replace the coordinates in memory even if you made changes to the map.
The function that puts the sprites in memory:
sprites_in_memory = get_all2(sprite)
The function that sets a new sprite:
What other ways do you have in mind? I'm kind of new to Pico-8 and I'd like to know what you would come up with.
P.S. There seems to be a bug with the amount of memory shown on the browser
Alright, lemme think for a second, @bilodau ...
First off be aware that if you use mapper that exceeds or is at 32 vertical, that cuts into your 128-255 sprites.
I'm not going to use that space. I'll just use the 0-127 horizontally and 0-15 vertically.
The map doesn't scroll to new data ... pretty sure that's a requisite.
bilodau: instead of looping over the map and using mset, have you thought of changing the sprite data with sset?
Well I think @merwok is definitely on to something. Here now, try out this code and examine the sprites. This is probably the first map in Pico-8 that takes advantage of 256-colors. :)
Here, I'll also document this one completely. Check the source-code for details.
Check the CPU usage. Using MEMCPY() for many sprites is actually faster than manually using SSET() for a single 8x8 sprite.
Runs best offline where it does not flicker at all - at least for me.
yes, that’s using sset to change sprites used in the map.
the demo could be improved by changing the sprites when a button is pressed ;)
as was pointed out, using memcpy will be more efficient than using sget, as memcpy can set 8 pixels in one call. it’s a bit more advanced but worth learning!
I made this function for the purpose of replacing a sprite with sset. Do you think you can make it work with memcpy and that the function still uses the same parameters?
function replace_sprite(os,ds,f) -- os: original sprite -- ds: destination sprite -- f: include flags local os_x = (os%16)*8 local os_y = os \ 16 * 8 local ds_x = (ds%16)*8 local ds_y = ds \ 16 * 8 for y = 0,7 do for x = 0,7 do sset(ds_x+x,ds_y+y, sget(os_x+x,os_y+y)) end end if f then fset(ds,fget(os)) end end
Thanks in advance,
P.S. According to my tests, each byte from 0x0 to 0x0fff represent two pixels on the sprite sheet. Am I right?
I am on the downstairs computer now. And ...
Nope, a single pixel for Pico-8 uses 4-bits of data, not 8. So if you were to poke 0x6000 or 24576 a value of 0xFF or 255 which is 8-bits then it would be two "Salmon" (color #15) pixels that appear in the top-left-hand corner of the screen.
If you poke something that is 3-bytes or more, it spills into the next horizontal frame. So MemCpy() doesn't really do you a big advantage unless you are shifting MORE THAN ONE sprite at a time.
Your best results for 16-sprites for instance will be to use the first row (#0 if you count them 0 to 15) - the first row would contain the sprite you want to have appear. The second row #1 to contain the image of the sprite 1st frame and the third row #2 to contain the image of the sprite 2nd frame.
Then simply use a timer to animate them in sequence. If you want to animate at different times, you can do this.
Suppose you want to have 8-sprites animated fairly quickly and the 8 after it to animate somewhat slower. You could have this for that:
TO LOAD THIS PICO-8 CART, in immediate mode, type:
So here are 16-sprites that don't animate, the first is just a black square. Then you have 8 that do animate, slow, and 8-more that animate a bit faster. 2 frames per animation sprite cel in all. Uses a simple 128x16 drawing map field. Use LEFT and RIGHT arrow keys to scroll through it.
If you don't split the animation as I am doing now and in fact have 16-sprites across to animate at one speed and 16-more sprites to animate at a different speed, the code would run faster and cleaner and use less CPU overall.
[Please log in to post a comment]