Ardynia - a Zelda style adventure

ardynia (1).hex

Ardynia is now available, grab it here:

More info here:


Thanks to @Dreamer3 for his help with the game, would have taken a lot longer without him.

Original Post below

Hey everyone, thought I’d post about the game I’m working on, called Ardynia. It is styled after Zelda, mostly Link’s Awakening.


All of these screenshots/gifs are from the game, no mock ups





The boomerang stuns enemies, picks up items, and triggers out of reach switches.


The game auto saves, beating the game will cause about 20 auto saves to occur.

The game will have a large overworld to explore, three dungeons, three equipable items beyond your sword, three bosses, six enemy types, and several secret areas. The average dungeon size is 29 rooms.

The entire engine is fully implemented, the overworld is in place as are the dungeons. I’m now working on filling the dungeons with content and coming up with fun puzzles.

Still to do:

  • implement the logic for the rest of the enemies and items
  • implement the bosses
  • design the dungeons
  • fix bugs and test test test, and test some more
  • sound effects and music (help wanted! see below)

I am at 69% RAM used and 80% flash. However, I’ve already added all enemies, items and bosses into the sketch such that they use up all of the RAM they will need and most of the Flash. The remaining 20% of Flash will largely go to enemy AI routines, item logic routines, a few animation frames I’ve yet to draw and audio.

I don’t plan to leave any byte unused, so if there’s still space, I plan to add another enemy type.

Help wanted! I am terrible with sound. If anyone is good with ArduBoy audio and wants to help with sound effects and music, please contact me.

I’m using many things from the community: Arduboy2, ArdBitmap, TinyFont, ArduRPG sprites, etc etc. Thanks everyone, this community rocks!


you seem to have done a very good job! do not let go! :wink:


Wow this is looking really hot :+1:t2:

1 Like

What did you have in mind? If you’re pushing the limits of flash with the game you aren’t going to have much room for anything other than simple tones or maybe small tone basic music. Synth stuff is probably out.

Can’t wait to play it


What did you have in mind?

That’s a good question. I’m not really sure yet to be honest. I was really encouraged by this post: Writing Music in 2017 for the Arduboy -- What do you use? where Jay went from 2 channels at 1331 bytes with PlayTunes to 4 channels at 357 bytes with ATMLib. Although I’m sure ATMLib must be using a decent chunk of RAM?

I don’t know too much about ArduBoy music yet. I would be ok with simple music and even just sound effects if space/memory forces that.

I might just find some nice creative commons MIDIs and convert them to ATMLib, at least as a first pass.

I’ve also got a few places in the game I can squeeze out more flash. For example with TinyFont I’m only using capital letters. So I can remove lowercase and punctuation. I’ve got a list of potential optimizations like that that can be made for a handful of bytes here, handful there.

I’d worry more about the flash space the code itself requires. I don’t THINK it uses much RAM (maybe a bit per channel to store the effect states, etc.)

1 Like

Ah gotcha. Yeah, I think I’ll get ATMLib going tonight to get a sense of what I’m looking at.

Ok, well probably not using ATMLib :slight_smile: It takes up about 10% of flash space. I think I could make that work, but I’m much more worried it pushes RAM up to around 85%, I don’t think can recover from that. ArduboyTones only uses a little bit of RAM it looks like.

Wow, fantastic! When do you plan on having this complete?

Wow, fantastic! When do you plan on having this complete?

Thanks! Hard to say when it will be done. I’ll have the coding done pretty soon, but I suspect tweaking things, getting the balance just right, and testing it all out to make sure it’s all good could take a while. The sound is an unknown at this point too.

1 Like

Hmmm, I wonder why it uses so much RAM.

I cannot stress enough how much ATMLib 2 made Evade2 enjoyable to both make and play.

It came at a cost on all fronts. RAM, CPU, Storage.

RAM: each channel requires structs to manage the place in the patterns, oscillators, etc. add to that any SFX you want to play and track.

CPU: real-time generation of the sound waves took considerable CPU. Without ATMLib2, EVADE 2 exceeded 45-50FPS. With ATMLib2, we got about 30FPS. A worthwhile sacrifice for the audio.

Storage: the library itself takes space, and while the format of the music is very optimized, songs and SFX do compete with assets such as bitmaps. This is part of the reason why we went with a vector based game instead of a bitmap based game. Also, we ended up stripping out some bootloader code to allow us to stuff even more music and other assets. Music had to be written with storage optimization in mind (not too many notes, using ATMLib effects such as arpeggiator, retrigger etc. ). If you listen to the sound track, the later songs have lots of LONG playing notes. This allowed me to keep harmony and reduce storage requirements.

All of this work and effort, and I regret nothing of what we’ve accomplished. Even though some have complained that there is no runtime option to turn sound, or what we did was overkill. :slight_smile:

@dxb please chime in when you have a moment. (He was the brains behind the evolution of the the library. I was the person pushing the boundaries of the lib).

My workflow used some tools that are not fully baked for public use.

Developed Music in Reason, exported it to 4 track midi. I then used a customized version of LibOpenMPT to extract the midi notes and export them to JSON format. LibOpenMPT quantized the notes to fit very well with ATMLib’s timing. The Tool I wrote was in OBJC because I wasn’t comfortable with C++ at the time.

Then I wrote a custom Node CLi tool to grab that stream of tracked notes and export a JSON stream that the web version of LibATM could read. This CLI tool detected repetitive patterns and was able to reduce size of music by working hard not to repeat data. I loaded the Web ATM JSON into the browser so I can further optimize the patterns.

Hope any of this helps.

1 Like

I imagine there are code and data structures there that could be eliminated if someone wasn’t using those features of ATMlib. Also is the frequency adjustable? That would potentially lower the CPU usage.

Yes. We have preprocessor directives to remove features. EVADE2 utilized this early on in development. I elected to use most of ATMLib2’s featureset because I ended up using those SFX capabilities towards the end.

If you want someone to have a quick skim over the code in an attempt to find memory savings then I’d be happy to volunteer.
I’ve been responsible for finding memory savings in a handful of games (e.g. Dark & Under, Lode Runner).



Code for unused effects can be removed at compile time by setting the right #define and sample rate can be reduced. I tried halving it during EVADE2 development and it worked but of course the sound quality is reduced but it may not matter much considering the piezo is not exactly a hi fidelity speaker…

For ATMLib 1 and 2 RAM usage is proportional to the number of channels used (about 60 bytes per channel if memory serves…) and which effects are enabled at compile time. The new version I am working on allocates memory from a fixed size pool declared at compile time and shared by all voices and players (it supports multiple players, each with multiple voices).

Minimum memory usage is 8 bytes per player plus 24 bytes per voice = 32 bytes. Players have independent tempo and score data, voices have independent waveform selection, frequency, square duty cycle and volume plus slide, LFO, arpeggio effects. Slide and LFO effects can be applied to any of: volume, duty cycle, frequency and note transposition. LFO uses a triangular waveform instead of sine to save space/CPU.

Each active effect uses 8 bytes. The maximum pool size is determined by how many concurrent effects and voices are active at any point in time but one could decide to ignore worst case scenario memory usage and the library will simply skip an effect if there isn’t enough memory so you get a graceful (but probably audible) degradation instead of a lockup or a total audio stoppage.

There is also a third way: use the voice oscillator from ATMlib2 (or the work in progress one). It’s small (less than 500 bytes of flash, probably around 300) and uses 7 bytes of RAM per voice (defaults to 4 channels). Your code would control each voice by writing to a global array of voice parameters.

struct osc_params {
	int8_t  mod; /* square wave duty cycle: -128-127, center 0 */
	uint8_t  vol; /* volume: 0-127 */
	union osc_u16 phase_inc; /*
						bits 0:13: phase accumulator increment per sample
						bit 14: reserved
						bit 15: waveform select 0 square, 1 noise

I can assist if you decide to use the latest version of ATMlib or just its voice oscillator module.


This is great, thanks everyone. I was also pointed at ArduboyBeep as a possibility. The voice oscillator is intriguing.

I am using to build and after a compile it reports:

Program: 27084 bytes (82.7% Full)
(.text + .data + .bootloader)
Data: 1764 bytes (68.9% Full)
(.data + .bss + .noinit)

and I thought I had way more space than I actually did, doh.

@Pharap thanks for the offer. I will probably take you up on it. Right now I’ve identified about 500 bytes of savings I’m going after. Then I want to clean up the code a bit and I’ll throw it up on github.


we found extra code savings by removing some boot loader code. just an option to consider.

I already stole that idea from you guys :slight_smile:

Things are looking a lot better, I’m up to 3k of space recovered, and I think I can push it to 3.5k.