#include <Arduboy2.h>
Arduboy2 arduboy;
bool Menu = false;
int Menu_choice = 1;
void display_menu()
{
arduboy.setCursor(10, (1 * 10));
arduboy.print(F("Back"));
arduboy.setCursor(10, (2 * 10));
arduboy.print(F("New"));
arduboy.setCursor(10, (3 * 10));
arduboy.print(F("Load"));
arduboy.setCursor(10, (4 * 10));
arduboy.print(F("Save"));
}
void display_menu_cursor()
{
arduboy.setCursor(0, (Menu_choice * 10));
arduboy.print(F(">"));
}
void setup() {
// initiate arduboy instance
Serial.begin(9600);
arduboy.begin();
// here we set the framerate to 15, we do not need to run at
// default 60 and it saves us battery life
arduboy.setFrameRate(25);
arduboy.clear();
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
arduboy.display();
}
// our main game loop, this runs once every cycle/frame.
// this is where our game logic goes.
void loop() {
if (!(arduboy.nextFrame()))
return;
arduboy.pollButtons();
if ( arduboy.justPressed(B_BUTTON) and Menu == false) {
arduboy.clear();
display_menu();
display_menu_cursor();
Menu = true;
}
Serial.print(Menu);
switch (Menu) {
case 0:
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
arduboy.display();
break;
case 1:
if ( arduboy.justPressed(DOWN_BUTTON)) {
arduboy.clear();
Menu_choice++;
if (Menu_choice >= 4)Menu_choice = 4;
display_menu();
display_menu_cursor();
}
if ( arduboy.justPressed(UP_BUTTON)) {
arduboy.clear();
Menu_choice--;
if (Menu_choice <= 1)Menu_choice = 1;
display_menu();
display_menu_cursor();
}
if ( arduboy.justPressed(B_BUTTON) and Menu == true) {
switch (Menu_choice) {
case 1:
arduboy.clear();
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
Menu = false;
break;
case 2:
break;
case 3:
break;
case 4:
break;
}
}
arduboy.display();
break;
}
}
when pushing button B Nothing happens because there is a loop that makes enter the menu and go away from it instantaneously. I Don’t know how to solve that.
Firstly, when you are postng code you need to wrap it within three back ticks (`).
A couple of problems:
if ( arduboy.justPressed(B_BUTTON) and Menu == false) {
arduboy.clear();
display_menu();
display_menu_cursor();
Menu = true;
}
If the player presses the B button, you immediately show the menu.
Then in this code …
switch (Menu) {
case 0:
...
break;
case 1:
...
if (arduboy.justPressed(B_BUTTON) and Menu == true) {
switch (Menu_choice) {
case 1:
arduboy.clear();
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
Menu = false;
...
}
}
arduboy.display();
break;
}
You immediately clear the screen because within the same loop the criteria matches.
The problem is fundamentally how you have intertwined the logic for handling user and rendering the screen. You should restructure your code to do all of the user handling and then render the screen based on the results.
#include <Arduboy2.h>
Arduboy2 arduboy;
bool menu = false;
int menu_choice = 1;
void displayMenu() {
arduboy.setCursor(10, (1 * 10));
arduboy.print(F("Back"));
arduboy.setCursor(10, (2 * 10));
arduboy.print(F("New"));
arduboy.setCursor(10, (3 * 10));
arduboy.print(F("Load"));
arduboy.setCursor(10, (4 * 10));
arduboy.print(F("Save"));
}
void displayMenuCursor() {
arduboy.setCursor(0, (menu_choice * 10));
arduboy.print(F(">"));
}
void setup() {
// initiate arduboy instance
arduboy.begin();
// here we set the framerate to 15, we do not need to run at
// default 60 and it saves us battery life
arduboy.setFrameRate(25);
arduboy.clear();
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
arduboy.display();
}
// our main game loop, this runs once every cycle/frame.
// this is where our game logic goes.
void loop() {
if (!(arduboy.nextFrame())) return;
arduboy.pollButtons();
arduboy.clear();
// Handle player input ..
if (menu) {
if (arduboy.justPressed(DOWN_BUTTON)) {
menu_choice++;
if (menu_choice >= 4) menu_choice = 4;
}
if (arduboy.justPressed(UP_BUTTON)) {
menu_choice--;
if (menu_choice <= 1) menu_choice = 1;
}
if (arduboy.justPressed(B_BUTTON)) {
switch (menu_choice) {
case 1:
menu = false;
break;
case 2:
// update the screen for the New function
break;
case 3:
// update the screen for the Load function
break;
case 4:
// update the screen for the Save function
break;
}
}
}
else {
if (arduboy.justPressed(B_BUTTON)) {
menu = true;
}
}
// Render screen and menu ..
switch (menu) {
case false:
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
break;
case true:
displayMenu();
displayMenuCursor();
break;
}
arduboy.display();
}
Hello.
I’ve progressed in my project.
The code below contains exactly what i want to do with my arduboy. If you compile you’ll see how i want my program respond.
In the code there are only Menus, I find my organisation with menus messy so I just wanted to know if there are possibly improvements or not to make the code clearer that it is now.
Main file:
#include <Arduboy2.h>
#include "Functions.h"
void setup() {
Serial.begin(9600);
arduboy.begin();
arduboy.setFrameRate(25);
}
void loop() {
if (!(arduboy.nextFrame()))
return;
arduboy.pollButtons();
arduboy.clear();
/////////////////HANDLING//////////////////////////
if (Menu == 1) {
if (arduboy.justPressed(B_BUTTON)) {
Menu = 2;
}
/////////////////////Do stuff//////////
}
else if (Menu == 2) {
if (arduboy.justPressed(DOWN_BUTTON)) {
Menu_choice++;
if (Menu_choice >= 4) Menu_choice = 4;
}
if (arduboy.justPressed(UP_BUTTON)) {
Menu_choice--;
if (Menu_choice <= 1) Menu_choice = 1;
}
if (arduboy.justPressed(B_BUTTON)) {
switch (Menu_choice) {
case 1:
Menu = 1;
break;
case 2:
// update the screen for the New function
Menu = 3;
Last_menu_choice = 2;
break;
case 3:
// update the screen for the Load function
Menu = 4;
Last_menu_choice = 3;
break;
case 4:
// update the screen for the Save function
Menu = 4;
Last_menu_choice = 4;
break;
}
}
}
else if (Menu == 3) {
if (arduboy.justPressed(DOWN_BUTTON)) {
Confirm_menu_choice++;
if (Confirm_menu_choice >= 1) Confirm_menu_choice = 1;
}
if (arduboy.justPressed(UP_BUTTON)) {
Confirm_menu_choice--;
if (Confirm_menu_choice <= 0) Confirm_menu_choice = 0;
}
if (arduboy.justPressed(B_BUTTON)) {
switch (Confirm_menu_choice) {
case 0:
// update the screen for the New function
Confirm_menu_choice = 0;
Menu = 2;
break;
case 1:
if (Last_menu_choice == 2) {
//Stuff for the 'NEW' choice
}
if (Last_menu_choice == 3) {
//Stuff for the 'LOAD' choice
}
if (Last_menu_choice == 4) {
//Stuff for the 'SAVE' choice
}
Menu = 1;
break;
}
}
}
else if (Menu == 4) {
if (arduboy.justPressed(DOWN_BUTTON)) {
Slot_Menu_choice++;
if (Slot_Menu_choice >= 4) Slot_Menu_choice = 4;
}
if (arduboy.justPressed(UP_BUTTON)) {
Slot_Menu_choice--;
if (Slot_Menu_choice <= 1) Slot_Menu_choice = 1;
}
if (arduboy.justPressed(B_BUTTON)) {
Menu = 3;
}
}
///////////////////////////DISPLAY//////////////////////
switch (Menu) {
case 1:
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
break;
case 2:
display_menu();
display_menu_cursor();
break;
case 3:
display_confirm_menu();
display_confirm_menu_cursor();
break;
case 4:
display_slots_menu();
display_slots_menu_cursor();
break;
}
arduboy.display();
}
Thank for your answer Pharap but you know the way you code is out of my hands.
Class methods are Something i Don’t understand yet, for the future i want to add more code.
I’d rather have a simpler answer that i’ll master.
I receive an error when compiling:
(‘Menu’ is not a class, namespace, or enumeration) at the line 124:
#include <Arduboy2.h>
#include "Functions.h"
enum class Menu : uint8_t {
Screen1,
Menu,
ConfirmMenu,
SlotsMenu,
};
void setup() {
Serial.begin(9600);
arduboy.begin();
arduboy.setFrameRate(25);
}
void loop() {
if (!(arduboy.nextFrame())) return;
arduboy.pollButtons();
arduboy.clear();
/////////////////HANDLING//////////////////////////
switch (Menu) {
case Menu::Screen1:
if (arduboy.justPressed(B_BUTTON)) {
Menu = 2;
}
break;
case Menu::Menu:
if (arduboy.justPressed(DOWN_BUTTON)) {
if (Menu_choice < 4) Menu_choice++;
}
if (arduboy.justPressed(UP_BUTTON)) {
if (Menu_choice > 1) Menu_choice++;
}
if (arduboy.justPressed(B_BUTTON)) {
switch (Menu_choice) {
case 1:
Menu = 1;
break;
case 2:
// update the screen for the New function
Menu = 3;
Last_menu_choice = 2;
break;
case 3:
// update the screen for the Load function
Menu = 4;
Last_menu_choice = 3;
break;
case 4:
// update the screen for the Save function
Menu = 4;
Last_menu_choice = 4;
break;
}
}
break;
case Menu::ConfirmMenu:
if (arduboy.justPressed(DOWN_BUTTON)) {
if (Confirm_menu_choice < 1) Confirm_menu_choice++;
}
if (arduboy.justPressed(UP_BUTTON)) {
if (Confirm_menu_choice > 0) Confirm_menu_choice--;
}
if (arduboy.justPressed(B_BUTTON)) {
switch (Confirm_menu_choice) {
case 0:
// update the screen for the New function
Confirm_menu_choice = 0;
Menu = 2;
break;
case 1:
if (Last_menu_choice == 2) {
//Stuff for the 'NEW' choice
}
if (Last_menu_choice == 3) {
//Stuff for the 'LOAD' choice
}
if (Last_menu_choice == 4) {
//Stuff for the 'SAVE' choice
}
Menu = 1;
break;
}
}
break;
case Menu::SlotsMenu:
if (arduboy.justPressed(DOWN_BUTTON)) {
if (Slot_Menu_choice < 4) Slot_Menu_choice++;
}
if (arduboy.justPressed(UP_BUTTON)) {
if (Slot_Menu_choice > 1) Slot_Menu_choice--;
}
if (arduboy.justPressed(B_BUTTON)) {
Menu = 3;
}
break;
}
///////////////////////////DISPLAY//////////////////////
switch (Menu) {
case 1:
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
break;
case 2:
display_menu();
display_menu_cursor();
break;
case 3:
display_confirm_menu();
display_confirm_menu_cursor();
break;
case 4:
display_slots_menu();
display_slots_menu_cursor();
break;
}
arduboy.display();
}
I have to say that i wish to remove the ‘Last_menu_choice’ variable that is in the ‘Menu_choice’ switch.
That’s all i want by now.
Thanks, I’ll look at it. I’ll keep adding things in this list:
Functions.h should have #include <Arduboy2.h> at the top, because now it relies on the main file to do this before including functions.h – that’s not a good practice, if a file uses a library, it should include it itself. (You can still include it in the main file as well.)
The cause of the error you’re getting is that in functions.h you already have a variable named Menu, and you’re then trying to declare an enum named Menu as well in the main file. To avoid this, name variables lowecase, that is menu, and types (for example enums) with starting uppercase, that is Menu. So you should delete the int Menu = 1; from functions.h, and instead create Menu menu = Menu::Menu; in the main file, somewhere after the enum class Menu .... Then you must change all places where you assign integers to menu (such as menu = 2) to assigning the enum values instead (e.g. menu = Menu::ConfirmMenu). Also everywhere you do switch (menu) you must use the enum values instead of integers in the case labels (e.g. case Menu::Screen1: instead of case 0:).
You should add #pragma once at the beginning of the functions.h file – it’s not an error at this moment, but it helps prevent some in the future.
Okay, here are the files edited so that they compile:
main:
Summary
#include <Arduboy2.h>
#include "Functions.h"
enum class Menu : uint8_t {
Screen1,
Menu,
ConfirmMenu,
SlotsMenu,
};
Menu menu = Menu::Menu;
void setup() {
Serial.begin(9600);
arduboy.begin();
arduboy.setFrameRate(25);
}
void loop() {
if (!(arduboy.nextFrame())) return;
arduboy.pollButtons();
arduboy.clear();
/////////////////HANDLING//////////////////////////
switch (menu) {
case Menu::Screen1:
if (arduboy.justPressed(B_BUTTON)) {
menu = Menu::ConfirmMenu;
}
break;
case Menu::Menu:
if (arduboy.justPressed(DOWN_BUTTON)) {
if (menu_choice < 4) menu_choice++;
}
if (arduboy.justPressed(UP_BUTTON)) {
if (menu_choice > 1) menu_choice++;
}
if (arduboy.justPressed(B_BUTTON)) {
switch (menu_choice) {
case 1:
menu = Menu::Screen1;
break;
case 2:
// update the screen for the New function
menu = Menu::SlotsMenu;
last_menu_choice = 2;
break;
case 3:
// update the screen for the Load function
menu = Menu::SlotsMenu;
last_menu_choice = 3;
break;
case 4:
// update the screen for the Save function
menu = Menu::SlotsMenu;
last_menu_choice = 4;
break;
}
}
break;
case Menu::ConfirmMenu:
if (arduboy.justPressed(DOWN_BUTTON)) {
if (confirm_menu_choice < 1) confirm_menu_choice++;
}
if (arduboy.justPressed(UP_BUTTON)) {
if (confirm_menu_choice > 0) confirm_menu_choice--;
}
if (arduboy.justPressed(B_BUTTON)) {
switch (confirm_menu_choice) {
case 0:
// update the screen for the New function
confirm_menu_choice = 0;
menu = Menu::ConfirmMenu;
break;
case 1:
if (last_menu_choice == 2) {
//Stuff for the 'NEW' choice
}
if (last_menu_choice == 3) {
//Stuff for the 'LOAD' choice
}
if (last_menu_choice == 4) {
//Stuff for the 'SAVE' choice
}
menu = Menu::Menu;
break;
}
}
break;
case Menu::SlotsMenu:
if (arduboy.justPressed(DOWN_BUTTON)) {
if (slot_menu_choice < 4) slot_menu_choice++;
}
if (arduboy.justPressed(UP_BUTTON)) {
if (slot_menu_choice > 1) slot_menu_choice--;
}
if (arduboy.justPressed(B_BUTTON)) {
menu = Menu::SlotsMenu;
}
break;
}
///////////////////////////DISPLAY//////////////////////
switch (menu) {
case Menu::Screen1:
arduboy.setCursor(10, 10);
arduboy.print(F("Screen 1"));
break;
case Menu::Menu:
display_menu();
display_menu_cursor();
break;
case Menu::ConfirmMenu:
display_confirm_menu();
display_confirm_menu_cursor();
break;
case Menu::SlotsMenu:
display_slots_menu();
display_slots_menu_cursor();
break;
}
arduboy.display();
}
But I’ve messed with the switches and they won’t do what they’re supposed to, and I think you shouldn’t use this anyway. I’d suggest we could write this all in a slightly better way, okay? What exactly are you trying to achieve?
EDIT:
Okay, I see what you’re doing. I’m thinking about how to create a dead-simple menu implementation. @Pharap, do you maybe know any elegant pattern for menus?