MannBärSchwein - Game Jam 5

mbs

This is my entry for the Arduboy Game Jam 5: Pretty simple. It is a simple side-scrolling platformer where the character must morph between three different states in order to pick up food and pass through gates. The visuals uses a trick in order to achieve three shades of gray to draw the characters, gates, and food in different colours. It also has neat graphical effects like particles, paralaxing background, and screen-shake. The entire game is coded in Nim, which makes the code nice and readable while still being just as efficient as C. It also has some neat tricks with macros that means it will read the BMP files used for sprites and levels on compile-time and automatically convert them to progmem arrays. Read more in the GitHub README.

Controls:

  • Up or B - Jump
  • Down or A - Morph (changes state between man, bear, and pig, in that order)

Read more or grab the binary releases on GitHub:

Or play the low-fi version directly in the emulator (the emulator doesn’t handle the shades of gray very well):
paralax.hex
EDIT: I’ve been made aware that this doesn’t work when the emulator is run under Chrome/Chromium. It works fine with the downloaded version and in Firefox.

Disclaimer:
This isn’t particularly optimised. You will experience slow-downs, especially in the web-based emulator (it’s slightly better on the desktop version, and better yet on actual hardware).

6 Likes

I have never coded in Nim so congratulations on making it work. I have no idea about Nim so when I look at the code, I cannot determine which is code the ‘framework’ provided and which is code you wrote yourself. It would be awesome if you could do a write up on this - how to get started, a couple of simple programs, etc.

As for the game itself, the running from right to left is different to every other sideways scroller I have ever seen.

You should be able to add the Hex to your listing using the image to embed the emulator in this page.

1 Like

You should add a LICENSE or LICENSE.md to your GitHub repository, so people will know what they can do with your code.

1 Like

I think I’ve read about Nim eons ago, this project put it back on my radar. I’d love to know more about your setup and experience developing this game with Nim instead of C++!

This sounds pretty cool

I think if you edit your post you can drag and drop your full.hex file. If not, there’s the Upload button to the left of the bullet points. Once it’s uploaded, the emulator will pop up automagically :slight_smile:

The game is fun and simple. It took me a while to differentiate when I should M, B or P - this is the one time I wouldn’t mind colour on an Arduboy lol. I got accustomed to the visual cues. Probably got a couple of slow downs but they didn’t last long thankfully. If you can, add a screen to show the final score after we die. Good stuff @PMunch!

When I upload this to my Arduboy, I can’t upload other games :confused:. I needed to go to flashlight mode and then upload. Maybe it’s only me, but please check that out!

A reference to https://en.wikipedia.org/wiki/ManBearPig perhaps?

1 Like

Not a whole lot of people have heard of it to be honest, but it should be a great fit for microcontrollers in general, so I wanted to give it a try on the Arduboy. As for the code it’s all written by me, however the nimfiles folder contains files that was originally generated by a program based on the Arduboy2 files. Nim compiles to C/C++ before it compiles to a binary, so these files are just there in order to tell Nim how to represent the Arduboy2 C++ library and what code to generate for it. The ardusprite.nim and levelloader.nim files are more like library files as they could be easily dropped into different projects. The only file that is exclusive to this game (apart from the sprites and level BMPs) is the ardu.nim file.

I plan on doing a write-up of how I got it all working, so far I’ve just been focused on making it work. I also plan on polishing the wrappers and publishing them so it’s easier to get started for others.

The right-to-left running certainly is a bit odd, but you get used to in surprisingly fast. No good reason why it’s made like that really, just to make it different.

2 Likes

The slow downs are a bit silly. It’s mostly down to the paralaxing background being gray, this means it’s only drawn on the 3rd subframe, after all the brighter elements. But since this would overwrite all the stuff that’s supposed to be in front of it I just set it to draw all these sprites again on top. So for each frame it has to draw the completely white things three times, the light gray things twice, and the dark gray things once. This means that when there are many things on the screen it will slow down a bit.

The high-score is the number in brackets after your current score. I initially had a full blown high-score screen, but whenever I died I just wanted to jump right into the game so I never bothered putting in my initials and stuff so I just took it out. But having a screen that shows the final score could be nice (or just write a “you died, press A to restart” over the game instead of going back to the title screen, this would allow you to still read the score.

And yes, I plan on doing a write-up of how I wrote this in Nim, so stay tuned for that!

Bit worrisome that you weren’t able to flash over it, never experienced that myself with this game, so hopefully it was just a fluke.

2 Likes

If it’s due to the bootloader magic key problem, then there’s not much that can be done to consistently fix it. As long as the sketch uses begin(), or you include flashlight() or safeMode(), you’ve addressed the problem in an acceptable way.

Well if it was that wouldn’t I consistently see it myself as well? And yeah, the sketch calls begin() so it will always be possible to get into flashlight mode and fix it.

1 Like

Yes, for a given version of your code, the Arduino core code, libraries and compiler system you use. If any of those change such that they affect the resulting RAM map of your program, the problem could appear or disappear. I.e. It should be consistent for a given .hex file.

However, even the state the program is in could have an effect. E.g. Sitting on a menu may not be changing the “magic key” bytes. In an active game mode, the stack, heap or other RAM used could end up constantly overwriting the “magic key”. By design, flashlight mode or safe mode (using safeMode()) just happens to be a really safe state of your program.

With my ArduboyLife sketch the problem is almost guaranteed to happen if it’s running at one of the higher speeds because the double buffering of the screen takes up 2K of RAM, thus occupying the “magic key” bytes. But, if you use the A button to pause on the instruction screen, uploading will work fine. (The game doesn’t continually refresh the screen buffer(s) when paused.)

I see, and there is no way to tell the compiler that those bytes are in fact being used? I guess most games would be fine with having those few bytes of RAM being reserved throughout the program as long as they aren’t in the middle of the allocatable memory and would interfere with large buffers. But then I guess just including some foolproof way of getting into flashlight or safe mode would be just as good.

Not that I know of. For instance, again with my Life sketch, I need two blocks of 1K consecutive each. There would be no way to place those blocks such that one of them didn’t fall over the “magic” bytes.

The Arduino USB code that causes the problem contains a fix. It recognises a signature in the bootloader that indicates that the “magic” bytes will be at the very end of RAM, which is off limits to the sketch.

@bateske could ship new Arduboys with this slightly modified bootloader to fix it for them. However, if the bootloader were to change, it may as well be one of those made by @Mr.Blinky, which also contain the fix and offer certain other advantages.

Of course, anyone with the equipment and skills can also change the bootloader themselves, to fix their own unit(s).

Something that’s been bothering me: last time I checked Nim used a GC.
Presumably there’s a way to disable it for working in embedded systems?
Or perhaps not explicitly using it means it isn’t included in the object code?

A quick search shows that there’s a --gc:none option but I didn’t look very far into what using it entails.

Is it possible to save this intermediate C++ source code and include it with a release? Is it in a form that the Arduino IDE could compile? If so, even if it’s not in a form that’s easy to read or manipulate, it would be nice to have it for people (like me) who like to have all their sketches in the Arduino sketchbook and use the IDE to compile and upload them.

Ah yes, Nim by default has a GC, but as @MLXXXP pointed out it can be disabled. It can also be tuned to provide various guarantees, and you can choose from a couple different ones. When disabling the GC outright you will be warned if you’re using something that requires managed memory (such as a hashmap, a resizeable array, etc.). For this game I just disabled it, but there is a new interesting mode called ARC (Automatic Reference Counting) that can in fact work on these kinds of microcontrollers.

Yes, the output can indeed be stored and shipped separately without requiring Nim. It is certainly possible to compile it with the Arduino IDE as well, you could even make libraries in Nim and import them into your C++ projects. There has also been some work on integrating Nim directly into the Arduino IDE, although it’s currently a bit of a hacky solution.

I expected there probably would be, but didn’t have time to look into it.

Most GCed languages have a near symbiotic relationship with their GC,
so it’s interesting to see a case where it can be disabled.
It reminds me of Visual C++ (which I’ve never used, but am aware of).

I’m aware of what ARC is because I’ve read about it before (assuming this is the same as the general concept and isn’t doing something unusual). Objective C and Swift have the same thing.

(I’ve never written any Obejctive C or Swift, but I have an interest in language design so I’ve read a bit about various different languages and their unique features. E.g. I was actually aware of Nim’s existance before this thread, which I suspect would put me in the minority.)

Either way it’s pretty much pointless on AVR because even basic dynamic allocation on the heap is asking for trouble when you only have 2.5KB to work with (of which 1KB is reserved for the screen buffer and at least some of the remaining memory must be used for the stack).

On something like an ARM chip it might be worthwhile because you’ve got quite a bit more RAM to work with, but on AVR you’re better off just not doing dynamic allocation full stop, and without dynamic allocation there’s no resources to track so all resource management systems are redundant.

1 Like

Oh yeah, there’s a reason why I’ve left it completely disabled for this project. Since there is so little memory it’s easy to keep track of it all and not end up creating garbage. Besides, most things would live in memory for the entire duration of an Arduboy game.