ArduEngine: Simple Arduboy Scene Management Framework

(Vincentius Madya) #1

Hi everyone,

I’ve created a simple scene management framework for game development called ArduEngine.

Link: https://github.com/madya121/ArduEngine

Basically, in ArduEngine, you will be working inside a ‘Scene’, and you can move to a different ‘Scene’ with a simple cycle flow.

Also, I’ve created a simple python script to remove all boilerplate when you’re creating a scene. All the documentation is on the GitHub page.

If you’re curious about how to create a game using ArduEngine, you can check TNTANK

Hope you like it :slight_smile:

TNTANK.ino.leonardo.hex (58.1 KB)

4 Likes
(Pharap) #2

I’m concerned about the use of dynamic allocation and virtual functions.
Those things both chew up RAM and progmem in large quantities.

I speak from experience. I created a similar system for Minesweeper.

How/why they eat memory

Dynamic allocation adds a speed cost, a RAM cost and a progmem cost:

  • Allocating memory can be slow depending on the implementation. Often it involves stepping through unallocated blocks to find a block large enough
  • There’s an overhead for every allocated memory block. Typically that consists of at least the size of the allocated block and possibly an offset to another block (to allow walking the block list like a linked list)
  • new and delete are backed by malloc and free, meaning those functions have to be compiled and included in the output. On top of which, every time new and delete are called, that call itself requires extra calling code.

Virtual functions also add overhead:

  • They add an implicit pointer to every instance of a class that has a virtual function
  • The implicit pointer must be initialised every time an object of the class is constructed
  • To work, everay function needs a virtual function table, which eats quite a bit of progmem
  • Every time a virtual function is called, an indirect call must be used, which is more expensive

There’s also the fact your ArduText class is using a 64 character buffer instead of just storing a pointer to the text and the size of the text.

If you just stored the pointer and the size, it would cost 4 bytes instead of 64 bytes.
Though it would make it difficult to store integers.

You could also make a version of ArduText that accepts pointers to text in progmem rather than storing the text in RAM.


Don’t get me wrong, this system would be fine on a desktop,
but on the Arduboy it’s going to eat a lot of memory,
and thus reduce the size of the game you can make with it.

It will probably be alright for small games, but not large games.

1 Like
(Kevin) #3

Eternally concerned about efficient code execution. Overworked transistor, @pharap is your savior.

2 Likes
(Josh Goebel) #4

Couldn’t you just cast the pointer to an int directly if say the first bit was high/low…? So then you could store strings pointers OR raw ints up to 3.9 bytes long. :slight_smile:

(Pharap) #5

It’s possible, but you’d have to put up a big warning sign.
Pointer tagging can be dangerous,
and it automatically makes the code dependent on details of the underlying system.

Also you’d have to make sure to use intptr_t or uintptr_t,
because those are the proper types for converting a pointer to an integer.

It would be safer and more portable (though certainly a little bit more expensive) to use a union and a scoped enumeration to manually implement a tagged union (a.k.a. a ‘sum type’).

Technically it’s up to 3.875 bytes. :P

(Josh Goebel) #6

Well, obviously you’d wrap that up nicely in the library’s API. The end-user would just be calling functions and getting back whatever - the underlying implementation could change over time.

And that’s why you’d have portable and non-portable parts of the code. :wink:

(Pharap) #7

The other advantage of a tagged union is that you could store other types too,
like float and const __FlashStringHelper *.

(Josh Goebel) #8

I’m not suggesting how to implement it. :slight_smile: Just that it’s possible. :slight_smile:

(Pharap) #9

It’s possible, but that doesn’t mean it’s a good idea.

It’s riddled with problems:

  • It can only be used with 2 types
  • If one of those types is ‘integer’ then you can’t use signed numbers
  • You have to mask off the most significant bit before you can use one of the values
  • It relies on platform specific behaviour

The tagged union approach solves all these problems for just 1 byte extra.

(Josh Goebel) #10

This is all I was commenting on. Now we’re just talking around each other lol. I was pointing out that there ARE easy ways to do both here without incurring a cost of 64 bytes. My implementation suggestion was just the first thing I thought of - not a recommendation from the almighty - or even a strong suggestion. Just “heres one way you could do it”.