Arduboy Visual Novel Demo

Arduboy_Visual_Novel_Demo.ino.arduino_leonardo.hex (44.3 KB)
About
A quick demo to showcase Visual Novel mechanics running on the Arduboy.

Download it here!

2 Likes

This would really lend itself to the FX where you have a lot of space for text and graphics!

You could use the new FX::drawString(), here.

Will you be sharing the source code at any point?
I’m interested to see what kind of approach you’ve opted for.

I started making a VN engine for Arduboy myself once, but I never actually made anything with it because I couldn’t think of a decent story to show it off with.

Admittedly the code is not clean at all but here it is if you want to give it a look!

1 Like

Ooh I had no idea. I will definitely check this out!

I’ve seen far worse. You’re at least using enums and proper variable names.
The indentation is a bit off, but if you wrote this in the Arduino IDE that’s unsurprising.

Are you open to advice on how to improve the code? E.g. how to save memory.


Would it be okay to embed the demo in the first/main post so people can try it in the emulator?

Absolutely! I was running out of memory while working on it so any advice to improve that is very welcome.

1 Like

At the moment, the best way to save memory would be to remove your reliance on the String class because it’s very bulky and wastes RAM.

Unfortunately that’s easier said than done because at the moment you’re relying on it quite heavily, and most of your strings are being stored in RAM rather than in progmem.

Fortunately I’m experienced with this kind of stuff, so I had a look through your code and made a fork with some memory-saving improvements. In particlar, I replaced the Strings with some more conservative techniques - putting the strings in progmem, referring to them with pointers, and making use of an Arduino-specific trick to print the strings.

Some of this stuff might be a bit advanced for you at the moment if you’re just starting out, but I’m happy to explain anything you want to know. I have commented some of the code and split my changes into small commits with descriptive names, so that should help a bit.

There’s other things you could do as well, like reencoding your images to use the Arduboy’s native image format instead of the format you’ve currently encoded them as, and you could save a lot of memory by trimming out all the empty blackness from your credits image.


If I might ask: are you actually planning to turn this into a fully fledged visual novel, or was this just a demo to learn the ropes?


Edit: I almost forgot; to reiterate my earlier question…

Would it be okay to embed the demo in the first/main post so people can try it in the emulator?


Edit: One last thing, just to prove what a difference avoiding String makes…

Before:

Sketch uses 16122 bytes (56%) of program storage space. Maximum is 28672 bytes.
Global variables use 1592 bytes (62%) of dynamic memory, leaving 968 bytes for local variables. Maximum is 2560 bytes.

After:

Sketch uses 14168 bytes (49%) of program storage space. Maximum is 28672 bytes.
Global variables use 1242 bytes (48%) of dynamic memory, leaving 1318 bytes for local variables. Maximum is 2560 bytes.

That’s 1954 bytes (7%) of progmem and 350 bytes (4%) of RAM saved.

1 Like

I am still a beginner in terms of working with Arduino code, I’m most accustomed to C# with Unity but even then I’m a game designer more so than a programmer. Looking over your fork though I definitely get the approach that’s taken so it’ll be a big help going forward. Thanks for the advice!

I had some plans to turn it into a full game of some sort but honestly I have no idea when anymore because I keep buying new tools and handhelds to toy with than I have time to make games with/for them :sweat_smile: Maybe one day!

As for embedding it, I’d be happy to although my account appears to be too new to do it myself.

1 Like

That makes sense. Pascal-cased function names usually mean someone has more experience with either C# or (much more rarely) Pascal than other languages.

I should have asked before: do you already know about pointers?
If so then at least some of it should make sense.

The stuff to do with progmem will only make sense if you know the difference between progmem and RAM. (And possibly why pgm_read_byte and pgm_read_ptr are needed.)

The FlashStringHelper thing is an Arduino-specific trick so you won’t know about that unless you’ve read the right thread or gone digging through Arduino’s source code.

As I say, I’m happy to explain any of this in more depth if you want to know more.

That’s kind of a shame. I was half hoping you were going to say that you had a story in mind and only lacked the skills/experience to make it, because I have the opposite problem: I know how to write a visual novel engine complete with scripting, but no story to actually implement. :P

I don’t have the ‘buying new tools and handhelds’ problem, but I know what it’s like to have lots of projects you want to do and never the time or focus to stick to just one of them.

Since you’re too new to do it, I’ve added that in for you.
Feel free to rearrange your first post with the pencil icon.
You might not be able to upload a .hex, but you can still edit your post however you want.

1 Like

I was always under the impression that drawSlowXYBitmap() just had each byte describe a horizontal 8 pixels instead of a vertical 8 pixels. Thus the image size would be the same just less optimally laid out for rendering.

Two other things here > the images are 88 pixels wide and are rendered at x = 50, so 10 pixels are not being displayed. Using the Sprites::drawOverwrite() approach would save 10 * 8 bytes per image.

Lastly, the difference between the girlHappy, girlSad, girlNeutral is just the mouth -likewise the boy. You could have one full size image and different mouths - that would save a heap!

1 Like

Actually, whether the image size would be the same depends on the dimensions of the image.

The native approach means that the width is exact and the height must be a multiple of 8, whereas the ‘slow’ approach means the height is exact and the width must be a multiple of 8, so each approach theoretically has a different amount of waste.

For example, a 4x8 image would take 4 bytes with the native encoding (because it’s 4 columns (of 8), thus 4 bytes), but 8 bytes with the ‘slow’ encoding (because it’s 8 rows (of 4), thus 8 bytes). For a 8x4 image the relationship would be reversed - 8 bytes for native, 4 for ‘slow’.

The one exception is the case where both dimensions are divisible by eight, in which case both approaches will be exactly the same.

That aside, there’s two other issues:

  • The rendering is slower. Granted, it’s not much of an issue for a visual novel, but it’s worth bearing in mind.
  • drawSlowXYBitmap must (almost by definition) use more instructions than a function that does the same kind of drawing but doesn’t have to perform the format conversion. I.e. theoretically drawBitmap should use less progmem simply by virtue of not performing that conversion.

Whether drawOverwrite uses more or less I don’t know, but it performs a slightly different operation anyway, and by opting for the Sprites functions you’re effectively trading an amount of memory for the benefit of having the other drawing methods and proper masking.


Your other points are completely correct though. I didn’t look too much into other images, I just plucked the obvious one as an example, but yes, the other images could also be made more conservative.

Except the images are 88 x 64 so both multiples of 8.

And yes I had considered the multiple of 8 issue

Hence the name ‘drawSlow …’

Right. So we could actually use the compressed utilities in ArdBitmap: Bitmap library & tools

Actually, they’re 85x64. So they’d be about 85 * (64 / 8) = 680 in the native format and (88 / 8) * 64 = 704 in the slow format, assuming I’m doing my calculations correctly.

That’s before you account for the fact both the boy and the girl image have lots of wasted horizontal space that could be stripped out (about 14 pixels for the boy and 25 for the girl, I think).

That is an option, but so is storing the sprites on the FX and using the FX drawing functions.

Also, if masks aren’t needed then drawCompressed is also an option. At the moment the images have lots of large blocks of colour so they’d likely compress well enough with the simple RLE encoding that drawCompressed uses.

But the best option would depend on scope, intent and details (e.g. how detailed/patterned the sprites will ultimately be).

Are they? I was going by the call …

arduboy.drawSlowXYBitmap(50, 0, girlHappy, 88, 64, WHITE);

Which was my first suggestion. Of course a lot of us are playing with the idea of an FX only version of a game or trying to support the original and FX versions of the Arduboy.

True. RLE loves large blocks of white or black.

1 Like

I was going by their actual image dimensions.
Properties

The 88 there is probably because of the 3 bits of padding introduced when using the ‘slow’ format.


At any rate, this is all just speculative unless @sebastianscaini finds the time to make a plan and develop such a game:

Unless of course you’re now planning to make your next game a visual novel?
(In which case, it’s probably better we discuss it in a PM or another thread rather than hijack someone’s demo.)

I would assume so.

Nope …not really my thing.

Not yet, not yet… but who know with vampirics help, could be a good challenge too or mix game and grphic novels parts between some parts of the game… and help of the fx to be able to store all this in memory… :smiley:

I feel it would be a much bigger imposition on Vanps to produce a heap of graphics.

I am thinking that you could just steal the script from a ‘Choose you own adventure’ book