If the the user presses up or down the arrow should move too, and that’s where I’m failing, I can’t get the the arrow to move like I’d like to, I found code made by Pharap here that is what I’m trying to do but I had no idea how to convert it into graphics.
Here’s what I got.
//arrow is 6 by 5
const char arrow[] PROGMEM = {0x4, 0x4, 0x4, 0x15, 0xe, 0x4,};
//menu is 27 by 23
const char menu[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x51, 0x55, 0x45, 0x7f, 0x7d, 0x41, 0x7d, 0x7f, 0x43, 0x6d, 0x43, 0x7f, 0x41, 0x6d, 0x53, 0x7f, 0x7d, 0x41, 0x7d, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x41, 0x5d, 0x7f, 0x41, 0x6d, 0x53, 0x7f, 0x41, 0x55, 0x7f, 0x41, 0x5d, 0x63, 0x7f, 0x41, 0x7f, 0x7d, 0x41, 0x7d, 0x7f, 0x7f, 0x41, 0x5d, 0x7f, 0x41, 0x5d, 0x41, 0x7f, 0x41, 0x7d, 0x41, 0x7f, 0x7d, 0x41, 0x7d, 0x7f, 0x41, 0x6d, 0x53, 0x7f, 0x41, 0x5d, 0x41, 0x7f, 0x41, 0x5f, 0x7f, };
void setup()
{
arduboy.begin();
arduboy.clear();
}
void loop()
{
arduboy.clear();
arduboy.setCursor(0, 0);
//arrow placement
short arrowX, arrowY;
//displaying menu options
arduboy.drawBitmap(99, 39, menu, 27, 23, WHITE);
//x is the selected item
short x = 3;
//is the player presses up or down it will change
if (arduboy.pressed(DOWN_BUTTON))
{
arduboy.print("Down.");
}
if (arduboy.pressed(UP_BUTTON))
{
arduboy.print("Up.");
}
//using x which stores the selected item, the arrow will change it's position
if (x == 1)
//like this, the arrow will be placed next to "start"
arrowX = 98, arrowY = 40;
if (x == 2)
arrowX = 98, arrowY = 48;
if (x == 3)
arrowX = 92, arrowY = 56;
arduboy.drawBitmap (arrowX, arrowY, arrow, 6, 5, WHITE);
arduboy.display();
}
I don’t get a notification if you forget to use the @ symbol.
E.g. @Pharap, @VivaPerosa
That code’s actually a lot more flexible and quite a bit more advanced.
The reason I wrote it in the first place was because someone was asking about how to make an equipment menu:
The code in the comment below what you linked to is actually probably closer to what you intended:
Firstly, some things I have to point out about your current code.
You don’t have to call clear after begin. begin already clears the screen.
I don’t know why people keep doing this.
Is one of the tutorials telling people to do this?
You’re missing if(!arduboy.nextFrame()) return;. arduboy.nextFrame() is what enforces the frame rate.
arduboy.clear() already calls arduboy.setCursor(0, 0), so this is redundant.
These variables aren’t initialised.
You do assign to them later,
but it’s still best to make sure all variables are initialised,
otherwise you could end up with junk memory,
which could lead to bugs.
This x is local, so it won’t persist past the frame even if you were modifying it.
The string literals should be inside an F macro to make sure they stay in progmem and don’t use any RAM.
Please do not use the comma operator like that. It’s a bad idea.
Try to stick to one assignment per line.
The more variables you modify per line,
the harder it becomes to track down assignment-related bugs.
Here’s a modified, fully functional version of your code:
#include <Arduboy2.h>
// The arrow sprite
const uint8_t arrowSprite[] PROGMEM
{
// Width, Height
6, 5,
// Frame 0
0x04, 0x04, 0x04, 0x15, 0x0E, 0x04,
};
// The menu sprit
const uint8_t menuSprite[] PROGMEM
{
// Width, Height
27, 23,
// Frame 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x51, 0x55, 0x45, 0x7F, 0x7D, 0x41, 0x7D, 0x7F, 0x43, 0x6D, 0x43, 0x7F, 0x41, 0x6D, 0x53, 0x7F, 0x7D, 0x41, 0x7D, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x41, 0x5D, 0x7F, 0x41, 0x6D, 0x53, 0x7F, 0x41, 0x55, 0x7F, 0x41, 0x5D, 0x63, 0x7F, 0x41, 0x7F, 0x7D, 0x41, 0x7D, 0x7F, 0x7F, 0x41, 0x5D, 0x7F, 0x41, 0x5D, 0x41, 0x7F, 0x41, 0x7D, 0x41, 0x7F, 0x7D, 0x41, 0x7D, 0x7F, 0x41, 0x6D, 0x53, 0x7F, 0x41, 0x5D, 0x41, 0x7F, 0x41, 0x5F, 0x7F,
};
Arduboy2 arduboy;
// The number of available menu options
constexpr uint8_t menuOptions = 3;
// The index of the first menu item
constexpr uint8_t minIndex = 0;
// The index of the last menu item
constexpr uint8_t maxIndex = (menuOptions - 1);
// The index of the currently selected menu item
uint8_t selectedIndex = 0;
void setup()
{
arduboy.begin();
}
void loop()
{
if(!arduboy.nextFrame())
return;
// Update the button state
arduboy.pollButtons();
// If up is pressed
if (arduboy.justPressed(UP_BUTTON))
{
// Decrease the selectedIndex
// (Making sure it stays in range)
if(selectedIndex > minIndex)
--selectedIndex;
}
// If down is pressed
if (arduboy.justPressed(DOWN_BUTTON))
{
// Increase the selectedIndex
// (Making sure it stays in range)
if(selectedIndex < maxIndex)
++selectedIndex;
}
// Clear the screen
arduboy.clear();
// Draw the menu
Sprites::drawOverwrite(99, 39, menuSprite, 0);
// Store potential coordinates in arrays
static const uint8_t arrowCoordsX[menuOptions] PROGMEM { 98, 98, 92 };
static const uint8_t arrowCoordsY[menuOptions] PROGMEM { 40, 48, 56 };
// Read the arrow coordinates from the progmem arrays
// (This is usually cheaper than using lots of if statements)
const uint8_t arrowX = pgm_read_byte(&arrowCoordsX[selectedIndex]);
const uint8_t arrowY = pgm_read_byte(&arrowCoordsY[selectedIndex]);
// Draw the arrow
Sprites::drawSelfMasked(arrowX, arrowY, arrowSprite, 0);
// Update the display
arduboy.display();
}
Aside from getting the code to work, I’ve made a handful of other significant changes:
I’ve fixed all the problems I mentioned above
x has been replaced with selectedIndex. Selecting good, descriptive names for your variables is important, it makes it easier to understand the code, for you and for everybody else.
I’ve introduced some constants (using constexpr) to make the code easier to read, and to avoid ‘magic numbers’ (‘magic numbers’ are bad because they make code harder to understand).
I’ve changed your images to Sprites format, so the code now uses the Sprites functions. They’re much more versatile.
arrowX and arrowY are now selected through array indexing rather than having a long list of if statements. This is a much more efficient way of selecting values from a list of alternatives when the selection depends on an index.
I’ve fixed the button handling code so it properly handles the menu index. This is implemented similarly to how @rprouse suggested, but I’ve got rid of the magic numbers and structured it slightly differently.
If there’s anything you don’t understand, please ask and I will explain it.
(I suspect if you don’t know much about progmem you’ll at least want to know more about pgm_read_byte and what & is, or perhaps why static is needed.)
There are a handful of alternative ways to do this,
but whether they’re worthwhile or not depends on:
Is the text being on the right hand side rather than the left hand side important?
How many menu options will there be?
Is not using the built-in font important?
(Having tested quickly, I think your font looks better in this case.)
Well, it’s a frankenstein version of what you made, it’s not something I would make on my own at my current skill-level.
Yeah, in crait’s tutorial had arduboy.begin(); and arduboy.clear(); in the setup function, new people are going to do what he did because we don’t what we’re doing.
Noted.
That explains the errors I kept getting.
I didn’t think there would be an issues modifying multiple variables on one line; I’ve never did it in my class assignments but my teacher had mentioned it something we could do, though I probably misinterpret what she said.
That’s a list, your code is beyond what I understand, I haven’t done advance C++… yet.
Here’s what I know:
Expression and Interactivity
Making Decisions
Loops and Files
Functions
Arrays
Searching and Sorting Arrays
Characters, C-Strings, and string Class
Here is what I don’t know:
F macro
uint8_t
That you can use uint8_t to make sprites
PROGMEM
You can set the height and width in a array like tat
Originally it was called menuSelected but I kept editing the code (swapping names and stuff like that) so much that I got confused, threw my hands in the air, said “forget it”, and changed it to x.
Is the text being on the right hand side rather than the left hand side important?
To stay consistent I wanted the menus to be on the right side.
How many menu options will there be?
I haven’t decided, I’m making an RPG so there will be a few.
Is not using the built-in font important?
(Having tested quickly, I think your font looks better in this case.)
Yeah, I’m using a custom font you made, I like the font a lot so I’m sticking with it.
Edit: One last thing, here is pseudocode of what I’m trying to do.
short gamestate = 0;
void loop()
{
switch(gamestate)
{
case 0:
//this of course would be the title screen
//by assigning gamestate a number it can change which screen it's on
gamestate = shortFuncition();
break;
case 1:
//this would be the start screen
//these screeens wouldn't do anything other than display which screen it is
//user would press button "A" to return to the title screen
break;
case 2:
//this would be the credit screen
break;
case 3:
//and this would be the control screen
arduboy.display();
}
}
short shortFunction();
{
/*
the main idea for this function to be used over and over again through out the game
the name of the function does not reflect what i want it to do
but this is just a proof of concept so the name really doesn't matter to to me
once i plug it in into a main code ill name it properly
looking at your code i hope to change menuOptions depending on when shortFunction is called
example: title screen has 3 options, in-game menu has 6 options, npc dialog has 2 options, etc
when the user press "A" selectedIndex is returned
in this case selectedIndex will be returned to gamestate
*/
}
Technically you can do it, but from experience I’d say it’s better to avoid it.
If you stick to one assignment per statement and one statement per line then it makes it a bit harder to make mistakes and a bit easier to see what’s happening on each line.
Also if you really must do more than one assignment per line, use semicolons, not a comma.
The comma you used is an obscure thing called ‘the comma operator’ which most people probably don’t know about, and although it technically behaves as you intended, it also means you’re technically doing multiple assignments in a single statement instead of having two statements on a single line.
The only bits I’d class as ‘advanced’ is the use of PROGMEM, pgm_read_byte, static and &.
constexpr isn’t commonly used (unfortunately), but it’s not advanced.
I’ll start with the easier stuff and move on to the harder stuff.
constexpr is a C++11 feature.
When applied to a variable it means ‘this variable is constant and can be evaluated at compile time’.
It’s like const, but better. It’s what you should use for constants.
(The tutorials are teaching people to use #define, but that’s a really bad way of doing constants.)
(‘Compile time’ is when the program is being compiled,
‘run time’ or ‘runtime’ means when the program is being run.)
This is a feature of Arduboy2.
This stores the current state of the buttons so it can be compared against the previous state of the buttons,
which is what allows the justPressed and justReleased functions to know when a button has just transitioned from being not pressed to being pressed (and vice versa).
justPressed is only true on the first frame that a button is pressed,
after which it remains false until the button is released and pressed again.
Without calling pollButtons, justPressed wouldn’t work properly.
Without justPressed it would be very hard to accurately select a menu option because using pressed instead would mean that the option selector would fly past the second option too quickly.
uint8_t is an unsigned integer type with a width of precisely 8 bits (i.e. an ‘octet’ or (arguably) a ‘byte’).
It’s one of the fixed width integer types introduced in C++11.
Technically because Arduino uses the C standard library rather than the C++ standard library, it’s actually C’s version, but the definition is equivalent.
uint8_t is actually what you’re supposed to use.
You’re not supposed to use char.
The function signature for drawBitmap is:
static void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color = WHITE);
(Don’t worry too much about what the * means.)
It’s a similar situation with Sprites, the Sprites functions all use const uint8_t *.
The Sprites class is a more flexible way to draw sprites.
There are several different functions that draw sprites in different ways,
which you can read about here.
drawOverwrite directly draws the sprite to the screen,
replacing whatever was underneath.
drawSelfMasked only draws the white pixels of a sprite.
The black pixels won’t be drawn.
It’s not setting the width and height of the array, it’s putting the image’s height and width in the array.
That’s what the Sprites functions expect - they expect the width and the height to be the first two values in the array.
That’s so that you don’t have to provide the width and the height every time you call the drawing functions, because that wastes memory.
static has many different meanings in many different contexts.
This this case the arrays being static means that they behave similarly to global variables rather than local variables.
If this confuses you, just make them global instead (i.e. remove the static and put them outside the function).
All AVR chips (like the ATmega32u4 found in the Arduboy) have different memory sections:
ROM/Progmem (or ‘flahs memory’), which can be modified, but not while the program is running, and persists after the device is turned off (i.e. non-volatile memory)
RAM, which is readable and writable at runtime, but gets erased when the device is turned off (i.e. volatile memory)
EEPROM, which is readable and writable at runtime, and it persists after the device is turned off (i.e. non-volatile memory)
Progmem is where all the code and some of the data is kept.
There’s more progmem than RAM.
To specify that you want a variable to be stored in progmem, you have to use the PROGMEM macro,
and to retrieve data from progmem you must use one of the pgm_ macros,
which you can read about here.
To read something from progmem using one of the pgm_ macros,
you have to give it the memory address of the data you want to read (every byte in progmem has a distinct ‘address’),
which is what the & is for - getting the address of a variable.
To understand the F macro you first need to understand progmem, so read the above section first.
Normally if you just write a bare string,
that string will be stored in progmem and then copied to RAM later.
In general you want to avoid the string being copied into RAM,
which is what the F macro does.
The F macro makes sure that your string is only ever kept in progmem,
so it doesn’t eat into your RAM, which is important because RAM is limited.
If the progmem stuff confuses you too much then you can get rid of the arrays and just do this:
I could rewrite the code to cut out some of the other stuff you don’t understand if you want (e.g. get rid of Sprites), but I don’t really want to cut out too much because the techniques I’ve demonstrated are generally better ones than the alternatives.
When learning to program it’s important to not let new things scare you off because programming by its very nature means you’ll regularly be encountering and learning new things.
Fair enough.
It’s just a little bit more expensive that way, and a little bit more difficult to program.
If it were on the left side then you’d be able to draw the arrow on the same x coordinate each time and just change the y coordinate.
I made?
Edit:
Oh, now I remember!
Is that font going to be used a lot in your game by the way?
If it’s just for the menu then plain old bitmaps will suffice,
but if you’re intending to use it all throughout your game then you might be better off having a custom font rendering class.
(Presumably you don’t have the skill to do that at the moment, but I’m sure I or someone else could help you.)
There is actually a better way to do this,
but it involves learning another new thing.
Here’s the demo code:
// Include Arduboy2 library
#include <Arduboy2.h>
// Define a scoped enumeration called 'GameState'
// with the size and characteristics of a 'uint8_t'.
enum class GameState : uint8_t
{
// The possible values that a 'GameState' object can store
TitleScreen,
Settings,
Credits,
Gameplay,
};
// Declare an 'Arduboy2' object called 'arduboy'
Arduboy2 arduboy;
// Declare a 'GameState' object called 'gameState',
// initialising it with a value of 'GameState::TitleScreen'
GameState gameState = GameState::TitleScreen;
// Define a function for setting the game state
void setGameState(GameState newGameState)
{
gameState = newGameState;
}
// The 'setup' function, as required by Arduino
void setup()
{
// Initialise the Arduboy
arduboy.begin();
}
// The 'loop' function, as required by Arduino
void loop()
{
// If it's not time to draw the next frame
if(!arduboy.nextFrame())
// Exit the function
return;
// Update the button state
arduboy.pollButtons();
// Do all updating
update();
// Clear the screen buffer
arduboy.clear();
// Do all drawing
draw();
// Update the screen
arduboy.display();
}
void update()
{
// Choose an update function to call depending on the current state
switch(gameState)
{
case GameState::TitleScreen:
updateTitleScreen();
break;
case GameState::Settings:
updateSettings();
break;
case GameState::Credits:
updateCredits();
break;
case GameState::Gameplay:
updateGameplay();
break;
}
}
void draw()
{
// Choose a drawing function to call depending on the current state
switch(gameState)
{
case GameState::TitleScreen:
drawTitleScreen();
break;
case GameState::Settings:
drawSettings();
break;
case GameState::Credits:
drawCredits();
break;
case GameState::Gameplay:
drawGameplay();
break;
}
}
//
// TitleScreen updating and rendering
//
void updateTitleScreen()
{
if(arduboy.justPressed(DOWN_BUTTON))
setGameState(GameState::Settings);
}
void drawTitleScreen()
{
arduboy.println(F("Title Screen"));
}
//
// Settings updating and rendering
//
void updateSettings()
{
if(arduboy.justPressed(UP_BUTTON))
setGameState(GameState::TitleScreen);
if(arduboy.justPressed(DOWN_BUTTON))
setGameState(GameState::Credits);
}
void drawSettings()
{
arduboy.println(F("Settings"));
}
//
// Credits updating and rendering
//
void updateCredits()
{
if(arduboy.justPressed(UP_BUTTON))
setGameState(GameState::Settings);
if(arduboy.justPressed(DOWN_BUTTON))
setGameState(GameState::Gameplay);
}
void drawCredits()
{
arduboy.println(F("Credits"));
}
//
// Gameplay updating and rendering
//
void updateGameplay()
{
if(arduboy.justPressed(UP_BUTTON))
setGameState(GameState::Credits);
}
void drawGameplay()
{
arduboy.println(F("Gameplay"));
}
Obviously the real thing would have more complex conditions than just whether the up or down buttons were pressed,
but the point is to demonstrate how to transition from one state to another.
The enum class (technically ‘scoped enumeration’) is a special construct designed for doing precisely this sort of thing.
Underneath the compiler magic it’s still using integers,
but instead of remembering what state ‘0’ is and what state ‘1’ is,
you can just use names instead.
It’s also type safe, so you can’t accidentally do:
// Oops, 10 isn't a valid game state
setGameState(10);
Using an enum class you get a compiler error,
which you wouldn’t get with short.
By the way, short on the Arduboy is 16 bits, so it’s equivalent to int16_t (and int for that matter).
If you only need 0 to 255 then you can use uint8_t (or unsigned char).
If you only need -128 to 127 then you can use int8_t (or signed char).
Using smaller types is cheaper.
By the way, I don’t know if you’ve been taught this or not (because I know nothing about your programming course):
The core C++ types (char, short, int and long) are actually different sizes on different platforms, which is why the fixed width types were introduced - to provide a standard way of indicating types of a certain size.
Thank goodness, I was going to ask if one exists, but oh boy, there is a lot to learn but I have an entire Summer I’ll be fine.
So if a variable like arrowCoordsX acts like a global variable why not just make it global variable instead oppose to static?
So it allows me to use strings without using ram? Neat.
I came into programing and Arduboy knowing I know nothing but the main motivation is creating games. I love technology (software and hardware) so it was only natural for me to gravitate to programming, I like programming even when I hit road blocks.
I have a request: could you add comments to it? My brain broke trying to understand what you did.
Also what is : and ::?
Knowing nothing about Arduino I used short because it’s the only C++ variable I know that used less memory, at least now I know uint8_t and int8_t exist.
I didn’t think I’d be overwhelmed by a open-sourced Gameboy but here we are.
Edit: At this point I’m not even sure where to start with the Arduboy now, like do I try to understand how it works first or should I make this game while learning. I’m thinking about doing the latter.
Your code was already making use of one,
but given that you were following crait’s tutorials I suspect it was making use of the old library that is no longer maintained.
Because it’s only being used by one function.
Making it static means that only the function it’s declared in can ‘see’ and make use of it,
and it allows it to be defined close to where it’s used.
If more than one function needed it then it would make sense to make it global instead.
Generally speaking the only time I’d make a static variable in a function is for a one-time-use lookup table like the one used here.
Apart from that they’re actually quite uncommon in general.
If it weren’t for the need to save memory by storing in progmem then I wouldn’t even be using it in the first place.
When programming for desktop I never use them.
That’s the idea.
Also you should generally only use it if you’re giving the string directly to the print or println function (on arduboy, or on Serial),
because in most other cases it won’t make sense.
(I won’t attempt to explain why, because I’d have to explain half a dozen other things first. The mechanism behind F is actually quite complicated.)
That’s good, because you’ll never stop hitting them. :P
It’s actually not all that different from what you did in your ‘pseudocode’.
Though in your case you’re returning the value of the next state and in my case the functions are setting the next state through a function (which is more flexible, but also has a higher chance of being misused).
I’ll add comments when I get chance.
Edit:
I’ve edited the earlier comment to include comments in the code.
If it’s not enough, just ask more questions.
I can give better answers when the questions are specific,
otherwise I’m left guessing what has and hasn’t been understood.
I’m not sure what you mean by :.
You mean the colon in enum class GameState : uint8_t?
If so, that means you’re asking for uint8_t to be the ‘underlying type’ of the enum class (technical name: ‘scoped enumeration’).
That means that when the compiler compiles the code, it will make sure GameState has the same size and binary representation as uint8_t.
Without that, the default underlying type is int, which is 16 bits on Arduboy, which is larger than the type needs to be,
so specifying : uint8_t saves memory.
As for ::, that’s the ‘scope resolution operator’.
It’s another thing that has slightly different meanings depending on how it’s used.
In the case of GameState::TitleScreen et cetera it’s needed because you can’t just say TitleScreen on its own.
If you just said TitleScreen the compiler wouldn’t know where to look, it needs you to specify GameState::TitleScreen.
That’s because of situations like this:
enum class Colour
{
Red,
Green,
Orange,
};
enum class Fruit
{
Apple,
Pear,
Orange,
};
If you were allowed to just say Orange then how would the compiler know whether you meant Colour::Orange or Fruit::Orange?
Another case you’ve seen :: used with is Sprites.
That’s because the functions in the Sprites class are static functions (an example of where static has a different meaning), so you can access them directly through Sprites wtihout making a sprites object (e.g. Sprites sprites;).
Some people prefer to make an object, others prefer not to.
I prefer to avoid making an object for various reasons.
Having keywords and symbols with different meanings in different contexts might seem confusing,
but it’s something that occurs in natural language too.
For example, the word ‘bark’ can mean tree bark or the barking of a dog, and a ‘mine’ could be a place where minerals are excavated or an explosive device.
The reason many keywords have different meanings is because the comittee that decides which features go into the language prefers to reuse old keywords instead of adding new ones.
Firstly, short is a type, not a variable.
If you say short x;, x is the variable, short is the type.
And secondly short doesn’t use ‘less memory’.
I’m assuming you mean 'less memory than int', in which case short and int are actually the same size on Arduboy - they’re both 16 bits (or 2 bytes).
If I had £1 for every person I’ve encountered who thought “oh I know, I’ll learn how to make games, it’ll be easy”, I could probably afford to upgrade my GPU. :P
The fact of the matter is that programming is hard, and so is making games.
Pretty much anything to do with technology is difficult.
But so is playing an instrument, and upholstery, and clock making, and blacksmithing…
Pretty much any skill worth having is difficult to learn.
Anyone who tells you otherwise is lying to you.
The important thing is to not let the difficulty put you off.
If you want to develop any skill (especially programming) then you have to be determined.
You don’t really need to understand the electronics side of things to be able to make games.
There are some low level things that it helps to know about,
but in general you don’t need to know that much because the library already takes care of communicating with the hardware for you.
Just start small and work your way up.
Make a hello world program, make a menu, start with some relatively simple games.
When you’re just beginning even games you consider to be simple (space invaders, pacman, noughts and crosses et cetera) will actually be quite difficult.
There’s no rush, you can take as long as it takes.
The important thing is to not give up.
The only failure is to not try.
To be fair, when I saw:
And reading through @crait’s tutorial it definitely looked easy but now I’m confused. Like I don’t know what to do, as of now all I can say is that I can confidently make a hello world.
My original plan was to build pieces of a game in separate ino files (menuSelect.ino, worldGeneration.ino, etc.) then splice it together.
But this isn’t as good as the version using the enum class because it lacks some of the important benefits of using an enum class:
It’s not type-safe (i.e. you could easily do gameState = 10; by mistake)
You have to assign the values yourself, so you could accidentally give two names the same value (e.g. you could accidentally make Credits = 2; and Gameplay = 2;)
There could be a clash with the state names if you tried to use them for something else (e.g. if you tried to do something like char Credits[] PROGMEM = "Programming: VivaPerosa\nArt:VivaPerosa";)
(You could use short instead of uint8_t, but gameState would then use 2 bytes instead of 1 byte.)
Okay, I’m doing the basics but I ran into a problem. I’m simply making a code that says something when “A” button is pressed, when I used this code it doesn’t work.
But when I use static aButton or make aButtona global variable it works just fine, why? Shouldn’t it work regardless if aButton is a local variable or global?
‘Code’ is uncountable, like sand and water.
You don’t “make a code”, you just “write code”,
just like you don’t “drink a water”, you “drink water”.
This is another one of those mysteries I really wish I could solve.
I don’t think I’ve ever seen any experienced programmers say “a code”,
so I don’t know where people get it from.
No, because local variables are destroyed at the end of the function they’re declared in.
If you want something to persist between calls to a particular function (e.g. loop) then you must make the variable global.
While I was at it I added the mising if(!arduboy.nextFrame()) return;.
That’s necessary for the frame rate limiting mechanism to function properly.
I also moved the calls to pollButtons and clear.
Usually it makes more sense to clear just before you start drawing things and to pollButtons just before you start handling input.
Because (to get technical for a moment) static local variables and global variables both have what’s called “static storage duration”,
which means they are stored in the section of RAM reserved for global variables.
This means they exist for the entire duration of the program and aren’t destroyed when a function ends.
Local variables have “automatic storage duration”, which means they are stored somewhere else (either in things called ‘registers’ or on a thing called ‘the stack’ or ‘the call stack’) and they are destroyed when the function ends.
While I’m at it, I’d like to introduce you to a new type.
You might already know about it, I’m not sure,
but it’s a very important type so I’ll mention it anyway.
The bool type can hold either true or false,
and it’s the type you should use whenever you have something that should be represented as true or false.
In this case aButton probably makes more sense as a bool:
A lot of people seem to think that using an integer type and treating 0 as false and 1 as ‘true’ is fine,
but if it’s a question of whether something is true or false (and there are no other options) then you should always use bool because that’s what bool is designed for.
Part of the reason you might see other people use 0 and 1 is because back in the early days of C (before C99) there was no bool,
but C++ has always had bool (or at least it has since the first standard, C++98).
But I didn’t use setFrameRate or does Arduboy2 has it’s own default frame rate?
Huh, that explains when I use uint8_t aButton and press “A” nothing happens or I see “A BUTTON PRESSED” appear quickly. Before I was questioning why use static but I’m starting to see why.
I have written bool functions before but not many assignments I wrote required it so using bool hasn’t came to mind; actually I did have to use bool a lot in VB.
At this point I’m starting to have a better understanding of Arduboy2 either tonight or when I wake up I’ll I’m going to start messing with sprites.
To clarify, there seems to be a group of people that go around thinking code is countable and saying either “a code” or “codes” in a programming context.
I’ve never been able to figure out where this habit comes from,
whether it’s due to mistranslation from other languages or whether there actually is an English-speaking (or partially English-speaking) country out there where getting it wrong (i.e. treating it as countable) is the norm.
Either way, whenever I see someone use ‘code’ as if it were countable,
I correct them because I want to help prevent it spreading.
(Also it drives me (and various other programmers) nuts. :P)
Arduboy2 sets the framerate to 60 by default in the begin function.
Precisely.
Prefer to use global variables rather than static local variables. static local variables should be avoided in general.
Like I said before, the only time I ever use them is on Arduboy when I’ve got a ‘lookup table’ that’s only used in one function.
Also there are certain situations where static local variables behave differently and can end up being more expensive.
They’re still teaching VB!?
You have my sympathies. It’s an awful language.
(VB was what they taught me in college.)
For the record, what I’m telling you about bool and how locals behave versus globals applies to C++ in general, not just the Arduboy,
just in case you were getting the impression that the language used to program the Arduboy is Arduboy (or even Arduino) specific.
Glad to hear it though.
There’s quite a few threads around with info about sprites,
and obviously there’s the documentation.
VB is also taught at my college, I only took it because one of my professors said “If you’re serious about programming make sure to take [langauge1], [langauage2], and Visual Basic.” When I was taking VB my professor said that VB is obsolete but gives us a good idea on how to build a user interface - she was right. When we had to deal with one windows form it was fairly easy but when we had to deal with multiple forms that had to work together was when things got difficult before I dropped the class we was doing parallel arrays and was about to do databases - I could’ve only imagine how hard that would’ve been for me, I’ll find that out next year.
When I talk about Arduboy2 I’m talking about the library.
Honestly I’m using @crait’s tutorial as a base, using your code as a “this is how you should do it”, the documenation on the other hand is kind of useful? In this case aside from drawErase I’m having a hard time understanding knowing what each function does, so I just threw stuff at a wall to see what sticks and this is the code I came up with that moves a sprite around.