Ardulem - The Lemmings arrive on Arduboy!

Yes, I was talking for the Arduboy2. How can I submit you an enhancement? Is there a thread in the forum?

1 Like

Hello All,

I’ve uploaded a .arduboy file in the Release folder of my repo. I could import it in ArduboyManager, however, I couldn’t test the transfert, since all the game I tried to transfert to my Arduboy with the ArduboyManager was not successful (just freezing the ArduboyManager).

Please let me know if you try it, and if it works for you.

Also I’ve added a compiled version of the Editor (should run directly on Windows, and on linux/Mac you can run mono in command line giving the exe file in parameter).


The best way is to create a pull request on GitHub. You could also create a new issue on GitHub, containing the proposed changes.

Alright Scott,

I’ve just created an issue, where I attached a test program, with my “optimized version” which is of course backward compatible.

Feel free to test and do whatever you want with it. :smile:

The level editor sounds amazing have you tried making a Arduboy game maker?

Waooh… an Arduboy game maker would be very challenging, I think. And probably limited with the featrues it can provides, or limited in a certain genre. :sweat:
Anyway, maybe it will give some inspiration to others. :smile:


Hi Erwin

Danke…jetzt geht es


Awesome little game…thanks mate :smiley:


In few minutes, I will try to stream the development of a new Arduboy game from scratch. If you’re interested, you can follow me here:



Now dealing with Ardulem for making the ESP port. :slight_smile:

1 Like

Woah, that’s cool!

I think you can pretty much using the same strategy as my change on Rick Ardurous, if you want to first port it on Arduboy2 :slight_smile:

Good luck!


What can I say, it works. Except for one important little thing.
The Lem::IsThereRoofAt(…) and the MapManager::GetPixelsColumn(…) called from it always return positive value when CLIMBING lemming comes close to a vertical wall.
That way the lemming thinks it has hit the roof and falls down without even starting to climb up.
I’ve been wandering around for hours and can’t figure out why this is happening.

the problem was not so obvious

return (unsigned char)((height16PixelsColumn << leftShift) >> (leftShift + yNormalized));

fixed line

return (unsigned char)((((height16PixelsColumn << leftShift)&0xFFFF) >> (leftShift + yNormalized))&0xFF);

It seems that ESP always operates with 32-bit values when shifting. Despite the fact that uint16_t height16PixelsColumn;. Thus, when shifting left by 7 and back by 15, bits beyond 0xFFFFFF were returned and were written into unsigned char. They shouldn’t have been.)

ESP Ardulem needs a bit of testing, but so far it seems to be working fine.
And yes, it uses the Arduboy2 and Arduboy-Playtune libraries now )


  • The built-in compiler function int __builtin_popcount(unsigned int); for counting the number of bits installed didn’t work properly. I didn’t get into the details, I just wrote my own.
  • Pointers which were read by pgm_read_word(…) had to be converted to pgm_read_ptr(…) and where calculations were performed for calculating addresses to pgm_read_dword(…) (32-bit addressing does not like when we cut off half bytes)
  • And of course we had to change: int->int16_t, unsigned int->uint16_t, char → signed char
  • Again I had problems with “%” where division by 0 was found and MCU reloaded by exception
  • Some adjustments for the sound in Arduboy-playtine and some optimization in ingame calculations

Doesn’t seem like much work, but it took all day
Fun adventure, thanks @lswbanban for the great game and interesting code :slight_smile:

1 Like

As I mentioned recently in another thread:

“prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such as int). In particular, arithmetic operators do not accept types smaller than int as arguments
- cppreference, Integral promotion

int is 32-bit on ESP, and C++ classes the shift operators as ‘arithmetic’ operators, so yes, shifting will always be 32 bit or greater (when using long/long long).

An alternative solution would have been:

(unsigned char)(static_cast<uint16_t>(height16PixelsColumn << leftShift) >> (leftShift + yNormalized));

(Which is what we did to fix the bug in Sprites.)

By the way, the 0xFF in your solution is redundant if unsigned char is 8 bits wide, or if uint8_t is used instead.
(On 99% of systems unsigned char is 8 bits wide, but there are weird edge cases out there.)

Although, thinking about it…

That’s redundant. Shifting right by (15 - 7) = 8 would provide the exact same result with one less operation.

There should be a way to eliminate the left shift entirely if the left shift is always less than the right shift.

Someone might want to check my work, but theoretically this…

Could be reduced to:

return static_cast<unsigned char>(height16PixelsColumn >> yNormalized);

Because the remaining shifts cancel each other out…
I.e. if l <= r then x >> (r - l) == (x << l) >> r, right?

as I see in addition it is necessary to set to 0 all bits equal and higher then bit N(leftShift)
which is achieved by height16PixelsColumn << leftShift

Actually, because the left hand side is signed (i.e. int is signed), >> will behave as an ‘arithmetic’ right shift, so it could be padded with 1s or 0s depending on what the value of the most significant bit is.

If it were unsigned int, then it would have been padded with 0s.

(Thinking about it, this is probably part of the issue you had. When int is 32 bits, the msb is the 31st bit, and when int is 16 the msb is the 15th bit.)

Though yes, that could possibly cause a problem.
I’ll look again later to see if I can work out whether it would or not.

All the other things I understood, but I’d be interested to know more about this issue.

I was sure you would have issue with the popcount :slight_smile: That’s a pretty low level function, and I was even surprised that it was working on Arduboy. Anyway, happy that you liked the code… I was myself quite amazed by what I was ending writing…

And also, if you have more RAM on ESP, don’t hesitate to increase the buffer that store the modification of the level by the lemmings… For now if you dig a very long tunnel, you may end up filling the rotating buffer, which means the tunnel will close itself :slight_smile:


Yes, exactly, I used a left then right shift assuming it will pad with zeroes. If you want to combine the left then right shift into a single shift, you will need to replace it with some masking.

And yes the left then right shift should be performed on unsigned numbers, if it is not the case, that’s probably a bug.

1 Like

for example line 163

CurrentMapMirroredSprites = (const unsigned int *)((const unsigned int *)pgm_read_word_near(&(MapData::AllMaps[CurrentMapId].SpriteIdList)) + spritesCount);
1 Like

I use unsigned uint16_t height16PixelsColumn;
and in the original code it is signed int

And yes, thank you for your wonderful videos!
I watched them from time to time and it was very curious to follow the development process :slight_smile:
Unfortunately there isn’t much material like yours. Perhaps in some of the first videos there is a brief overview of the tools used. I have a long time plan to find time and carefully review videos about it.