More refactoring. I’m now splitting most of the ScrollingText class into a ScrollingTextBase base class. That will reduce the amount of repeated code in the sine scroller to almost none.
This is the first time I’ve tried working with inheritance in C++ in about 3 or 4 years, during which time I’ve used several other more modern OO languages, so trying to switch back to the unfriendly syntax employed in C++ is difficult. Still, after an hour or so of fiddling and reading I’ve got it all working. Now on to the sine scroller.
(Some time later)
The sine scroller now works, and I’ve fixed a few bugs in the rest of the code. It uses the same FIFO system as the scroller to move the Y position of each letter around.
Uploaded it to Simian Zombie.
Ah, it seems I’ll need to recompile the PALib with a specific commandline argument to enable WiFi support. I’ll probably ignore it for the moment and come back to it when I’ve got everything else finished. Assuming I structure everything properly, which is the reason I’m tackling presentation before the game itself, it should be easy to add it in at the end.
Menus, then. Structuring them is easy - this is exactly what I do every day at work. So, I’ve got a MenuButton class, a Menu class that contains a vector of buttons and sub-menus (instant menu tree) and a MenuSet class. The last one isn’t strictly necessary, but I’m planning to wrap a lot of generic functionality into that class instead of duplicating it down the tree and wasting memory. The only difficulty here is working out how to receive events from the menu - does C++ have an event system? Will I need to write one myself? How about a message queue instead? Or just using delegates? How do delegates work? (One phonecall later - they’re apparently “pointers to functions” in C++, not “delegates”.) Lots of research needed here…
(Half an hour later)
Not as difficult as I thought, then! Heh. It works like this. Inside the button class, we declare a pointer to a function as a member, like so:
private: void (*action)();
There are three things to note here. The type of the member should match the return type of the function that we’re making a pointer to, so the function “void myFunction()” would work, whilst the function “int anotherFunction()” would not. The next thing to note is that we declare the pointer inside brackets; this isn’t strictly necessary, but it’s apparently a convention that indicates the variable is a function pointer. The last thing to notice is the pair of brackets after the declaration - this lets the compiler know that we’re creating a function pointer. If the function we’re making a pointer to has arguments, these should be specified in the brackets. If we wanted to make a pointer to this function, for example:
int myFunction(int myInt, int anotherInt);
We’d use the following pointer:
int (*myPointer)(int myInt, int anotherInt);
For the purposes of the menu system, we just need to use the first example - a function with a void return type and no arguments. Once we’ve assigned the pointer a memory address (as you would with any other pointer, ie. “action = myFunction” - note the lack of brackets after the function), we call it like this:
All I have to do to make a button execute a function (defined in the main.cpp file) is pass the function to the button object as an argument and then click the button. Fantastic!
Another PALib bug that I’d spotted before but hadn’t noted down. There’s an odd problem with the DMA_Copy() function. All of the parameters have to be in brackets or it doesn’t work properly. For example, the top line gives different results to the second line:
DMA_Copy(100 + 120, 200 + 220, 12, DMA_16NOW); DMA_Copy((100 + 120), (200 + 220), 12, DMA_16NOW);
Aside from the new bug, which I’ve worked around, the menu system works! I can display buttons of any size at any position on the screen. Clicking and holding a button changes its image to “selected”; releasing it performs the button’s action; and dragging the stylus off the button resets it to “unselected”. Once whatever it was that ran drops us back into the menu system it redraws itself. Each menu can have its own background image.
Things to do:
- Buttons need a “selected by keypad” image, to allow the pad to work;
- Keypad needs wiring up;
- Functions to allow changing between submenus;
- Refresh() function to force a menu to redraw (useful if the menu changes a variable (“lives”, for example) and needs to update itself);
- Need a “back” button;
- Animated buttons? Possibly not this time around…
- Attach sounds to click and release events;
- Transitions? Again, possibly not this time around.
It looks like the slideshow will only run once - trying to run it again crashes the DS. Need to look into that.