Help me with C++ for my game


#1

I have experience programming but none with C++ except the Arduboy quick start guide.

Main file:

//Sam Sibbens
//November 1st, 2018

#include <Arduboy.h>
Arduboy arduboy;

// Game stuff
#include "Sprites.h"


void setup() {
    arduboy.begin();
    arduboy.clear();
    arduboy.setFrameRate(30);
}
void loop() {
    
    //Prevent the Arduboy from running too fast
    if(!arduboy.nextFrame()) {return;}
  
    arduboy.clear();
    if(arduboy.pressed(LEFT_BUTTON)) {
        playerx = playerx - playerspeed;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
        playerx = playerx + playerspeed;
    }
    if(arduboy.pressed(UP_BUTTON)) {
        playery = playery - playerspeed;
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        playery = playery + playerspeed;
    }

    arduboy.fillScreen(WHITE);
    draw_entity(playerx, playery, Sprites.PLAYER);
    arduboy.display();
}

Sprites.h

// Sprites.h
#if !defined(SPRITES)
#define SPRITES 1

/// w stands for "white pixels" and b stands for "black pixels"
const unsigned char spr_player_w[] PROGMEM;
const unsigned char spr_player_b[] PROGMEM;

void draw_entity(byte spr, byte x, byte y);

enum Sprites {
  PLAYER,
};

#endif

Sprites.cpp

#include "Sprites.h"

//Player
const unsigned char spr_player_w[] PROGMEM  = {
    0x00, 0x1e, 0x52, 0x5e, 0x5e, 0x52, 0x1e, 0x00,
};
const unsigned char spr_player_b[] PROGMEM  = {
    0x3f, 0xe1, 0xad, 0xa1, 0xa1, 0xad, 0xe1, 0x3f,
};

void draw_entity(byte spr, byte x, byte y) {
  switch(spr){
    case PLAYER:
      arduboy.drawBitmap(x, y, spr_player_w, 8, 8, WHITE);
      //arduboy.drawBitmap(x, y, spr_player_b, 8, 8, BLACK);
      break;
  }
}

What am I doing wrong that causes the expected initializer before ‘PROGMEM’ error?


(Matt) #2

Is it possible to post all of your code? Maybe put it up on github?

Which file and line number is the error for?

fwiw, I define my image data as const uint8_t PROGMEM foo[] = { ... }, but as I understand the PROGMEM macro can be anywhere.


#3

Try moving the Sprite data into just the header file instead of forward declaration.


#4

This is all my code, I started this today


#5

I did as you said but it gave the same error

It works if I put it in the main .ino file but I’d like to have it in a separate file


(Pharap) #6

Drat, I’m late to the party. :P

I think your problem is that you need to remove the PROGMEM from spr_player_w and spr_player_b in Sprites.h (but not Sprites.cpp).
PROGMEM only needs to be applied at the point of definition, not the point of declaration.


Three bits of unsolicited advice:

Firstly, you should use Arduboy2, not Arduboy.
Arduboy is no longer actively developed, and Arduboy2 has some particularly useful functions.

Secondly, I recommend using uint8_t instead of byte because byte is an Arduino-only thing and uint8_t is standardised and thus more portable.
(Technically in C++ it should be std::uint8_t and it comes from the cstdint library, but Arduino only has access to a version of the C standard library, so it’s uint8_t instead.)

Thirdly, I think the next thing to stick on your ‘to learn’ list should be enum class:

Hopefully you’ll see the benefit.


(Matt) #7

where are playerx and playery defined?


#8

Thanks! I actually understand that! I guess using SoloLearn wasn’t a waste. (I learned the difference between the two)

I then had to change my decleration to add 8 to the size of the image arrays, but that was an easy fix.

Here’s my new code:

Main .uino file hasn’t changed

#include <Arduboy.h>
Arduboy arduboy;

// Game stuff
#include "Sprites.h"

byte playerx = 0;
byte playery = 0;
byte playerspeed = 1;


void setup() {
    arduboy.begin();
    arduboy.clear();
    arduboy.setFrameRate(30);
}
void loop() {
    
    //Prevent the Arduboy from running too fast
    if(!arduboy.nextFrame()) {return;}
  
    arduboy.clear();
    if(arduboy.pressed(LEFT_BUTTON)) {
        playerx = playerx - playerspeed;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
        playerx = playerx + playerspeed;
    }
    if(arduboy.pressed(UP_BUTTON)) {
        playery = playery - playerspeed;
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        playery = playery + playerspeed;
    }

    arduboy.fillScreen(WHITE);
    draw_entity(playerx, playery, Sprites.PLAYER);
    arduboy.display();
}

Sprites.h

// Sprites.h
#if !defined(SPRITES)
#define SPRITES 1

/// w stands for "white pixels" and b stands for "black pixels"
const unsigned char spr_player_w[8];
const unsigned char spr_player_b[8];

void draw_entity(byte spr, byte x, byte y);

enum Sprites {
  PLAYER,
};

#endif

Sprites.cpp

#include "Sprites.h"

//Player
const unsigned char spr_player_w[] PROGMEM  = {
    0x00, 0x1e, 0x52, 0x5e, 0x5e, 0x52, 0x1e, 0x00,
};
const unsigned char spr_player_b[] PROGMEM  = {
    0x3f, 0xe1, 0xad, 0xa1, 0xa1, 0xad, 0xe1, 0x3f,
};

void draw_entity(byte spr, byte x, byte y) {
  switch(spr){
    case PLAYER:
      arduboy.drawBitmap(x, y, spr_player_w, 8, 8, WHITE);
      //arduboy.drawBitmap(x, y, spr_player_b, 8, 8, BLACK);
      break;
  }
}

The new bug I don’t know how to fix is
variable or field ‘draw_entity’ declared void.

I assume I declared or defined my draw_entity function wrong

EDIT: I removed draw_entity completely, and the “expected initializer before ‘PROGMEM’” came back. I assume the draw_entity bug somehow hid the PROGMEM bug once I removed PROGMEM keyword from the .h file


#9

I’ve had this same issue before but I can’t remember the root cause of it.

Try #include <avr/pgmspace.h> as well.
I’ve noticed some strange behavior with the aurdino ide sometimes needing certain includes and other times not.


#10

I had forgotten to define them but it never caused a bug, probably because I never had the opportunity to press the d-pad buttons

I put the updated code in the last code, I now get “variable or field ‘draw_entity’ declared void”

I probably declare or define my function wrong somehow


#11

I put this in my Sprites.h file, then I I got a “error trying to redefine const…” so I put the sprite definition in the .h file, and these two things together seemed to work

I probably just need to get my draw_entity() function working now


(Pharap) #12

I usually just define the array inside its own header.
Though sometimes that can go a bit weird for reasons I’m still not quite sure of.

Your code wouldn’t have compiled if you hadn’t defined them somewhere.


There are a handful of problems with your code.

Firstly I’d suggest just defining your sprites in Sprites.h instead of trying to separate the defnition.

Secondly, draw_entity can’t see arduboy from Sprites.cpp so you need to either:

  • #include <Arduboy.h> and extern Arduboy arduboy; in Sprites.cpp
  • #include <Arduboy.h> and extern Arduboy arduboy; in Sprites.h, then define draw_entity in Sprites.h instead and mark it as inline so it compiles properly.

Thirdly, you need to #include <Arduino.h> to get access to the byte datatype - as I said before, it’s not a fundamental datatype, it’s Arduino specific.

And finally you have to do Sprites::PLAYER, not Sprites.PLAYER.
Technically because you’re using enum rather than enum class you can just do PLAYER, but I’d advise against that.
(The thing I linked to about enum class should explain a lot.)


I had a few other problems when trying to compile, but I think the compiler might have been behaving a bit oddly.

Also I seemed to have better luck using #pragma once over include guards.
I think I’ve had that problem before on the Arduino IDE.
For some reason mixing include guards with PROGMEM upsets it.


So basically the code I ended up with looks like:

Game.ino:

#include <Arduboy.h>
Arduboy arduboy;

// Game stuff
#include "Sprites.h"

byte playerx = 0;
byte playery = 0;
byte playerspeed = 1;


void setup() {
    arduboy.begin();
    arduboy.clear();
    arduboy.setFrameRate(30);
}
void loop() {
    
    //Prevent the Arduboy from running too fast
    if(!arduboy.nextFrame()) {return;}
  
    arduboy.clear();
    if(arduboy.pressed(LEFT_BUTTON)) {
        playerx = playerx - playerspeed;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
        playerx = playerx + playerspeed;
    }
    if(arduboy.pressed(UP_BUTTON)) {
        playery = playery - playerspeed;
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        playery = playery + playerspeed;
    }

    arduboy.fillScreen(WHITE);
    draw_entity(playerx, playery, Sprites::PLAYER);
    arduboy.display();
}

Sprites.h:

#pragma once

#include <Arduino.h>
#include <Arduboy.h>

/// w stands for "white pixels" and b stands for "black pixels"
const unsigned char spr_player_w[] PROGMEM  = {
    0x00, 0x1e, 0x52, 0x5e, 0x5e, 0x52, 0x1e, 0x00,
};
const unsigned char spr_player_b[] PROGMEM  = {
    0x3f, 0xe1, 0xad, 0xa1, 0xa1, 0xad, 0xe1, 0x3f,
};

enum Sprites {
  PLAYER,
};

extern Arduboy arduboy;

inline void draw_entity(byte spr, byte x, byte y) {
  switch(spr){
    case PLAYER:
      arduboy.drawBitmap(x, y, spr_player_w, 8, 8, WHITE);
      //arduboy.drawBitmap(x, y, spr_player_b, 8, 8, BLACK);
      break;
  }
}

In case you’re wondering “what’s the diference between include guards and pragma once?”, they do roughly the same job, but technically #pragma once is actually a non-standard compiler extension.
However it’s available in all the major compilers so most people consider it as good as standard and don’t bother with include guards.
It’s a lot easier to use because you just have to stick it at the top of your file and it does its job, no questions asked.

(That said, there’s a big of a war about it. Not as bad as tabs vs spaces or K&R vs Allman.)


(Scott) #13

@SamSibbens,

Is there a reason you’re ignoring the suggestions to use the Arduboy2 library?


#14

None other than “still trying to figure out how to link files together and how C++ works”

I know I didn’t answer you in the other thread but I did read about it and if I remember correctly Arduboy2 is way more up to date, while Arduboy hasn’t seen an update since 2015, so I definitely do plan on using it


#15

Yeah I’m probably gonna have an .h file literally just for images and nothing else.

I’m not sure if I need to add “#pragma once”/"#ifndef #define #end" in the .cpp files as well as the .h files.

By the way even without #include <Arduino.h> the byte data type works

I didn’t comment on enumerators, but I did add it to my mental “to learn” list

So, here’s my code now. Compiles fine, no bugs:

Main stuff

#include <Arduboy.h>
Arduboy arduboy;

// Game stuff
#include "Sprites.h"

byte playerx = 0;
byte playery = 0;
byte playerspeed = 1;

void setup() {
    arduboy.begin();
    arduboy.clear();
    arduboy.setFrameRate(30);
}
void loop() {
    
    //Prevent the Arduboy from running too fast
    if(!arduboy.nextFrame()) {return;}
  
    arduboy.clear();
    if(arduboy.pressed(LEFT_BUTTON)) {
        playerx = playerx - playerspeed;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
        playerx = playerx + playerspeed;
    }
    if(arduboy.pressed(UP_BUTTON)) {
        playery = playery - playerspeed;
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        playery = playery + playerspeed;
    }

    arduboy.fillScreen(WHITE);
    draw_entity(playerx, playery, Sprites::PLAYER);
    arduboy.display();
}

Sprites.h

#pragma once

#include <Arduboy.h>

// _w means white pixels, _b means black pixels
//Player
const unsigned char spr_player_w[] PROGMEM  = {
    0x00, 0x1e, 0x52, 0x5e, 0x5e, 0x52, 0x1e, 0x00, 
};
const unsigned char spr_player_b[] PROGMEM  = {
    0x3f, 0xe1, 0xad, 0xa1, 0xa1, 0xad, 0xe1, 0x3f, 
};

enum Sprites {
  PLAYER,
};

extern Arduboy arduboy;

inline void draw_entity(byte x, byte y, byte spr) {
  switch(spr){
    case Sprites::PLAYER:
      arduboy.drawBitmap(x, y, spr_player_b, 8, 8, BLACK);
      arduboy.drawBitmap(x, y, spr_player_w, 8, 8, WHITE);
      break;
  }
}

Sprites.cpp is empty (should it be?)

Now I’ll need to understand classes better to have my entities. I’ll also need to figure out how to have an array (or list or other structure) that stores instances of the current entities so that I can update and draw them easily. I’m pretty sure I’ll keep the sprites separate instead of having them included in each entity type, unless I can reference constants instead of using my enum method

Once I’m comfortable and organised then I’ll start actually working on the game

I could ask all my other questions here but I think I should continue reading/watching videos and using SoloLearn a bit


(Scott) #16

If you plan to switch to Arduboy2, then I suggest you rename your Sprites.h (and Sprites.cpp if you keep it) file(s), to avoid file name conflicts with those in the Arduboy2 library.

Then, it’s just a matter of changing

#include <Arduboy.h>
Arduboy arduboy;

to

#include <Arduboy2.h>
Arduboy2 arduboy;

and making sure you’ve installed the Arduboy2 library in the Arduino IDE.


#17

Ok, I did what you said and it compiles perfectly:

// Sam Sibbens
// 2018 NOVEMBER 01
// Unnamed project

#include <Arduboy2.h>
Arduboy2 arduboy;

#include "my_sprites.h"

// Game stuff
#include "Sprites.h"

byte playerx = 0;
byte playery = 0;
byte playerspeed = 1;

void setup() {
    arduboy.begin();
    arduboy.clear();
    arduboy.setFrameRate(30);
}
void loop() {
    
    //Prevent the Arduboy from running too fast
    if(!arduboy.nextFrame()) {return;}
  
    arduboy.clear();
    if(arduboy.pressed(LEFT_BUTTON)) {
        playerx = playerx - playerspeed;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
        playerx = playerx + playerspeed;
    }
    if(arduboy.pressed(UP_BUTTON)) {
        playery = playery - playerspeed;
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        playery = playery + playerspeed;
    }

    arduboy.fillScreen(WHITE);
    draw_entity(playerx, playery, Images::PLAYER);
    arduboy.display();
}

my_sprites.h:

#pragma once

#include <Arduboy2.h>

// _w means white pixels, _b means black pixels
//Player
const unsigned char spr_player_w[] PROGMEM  = {
    0x00, 0x1e, 0x52, 0x5e, 0x5e, 0x52, 0x1e, 0x00, 
};
const unsigned char spr_player_b[] PROGMEM  = {
    0x3f, 0xe1, 0xad, 0xa1, 0xa1, 0xad, 0xe1, 0x3f, 
};

enum Images {
  PLAYER,
};

extern Arduboy2 arduboy;

inline void draw_entity(byte x, byte y, byte spr) {
  switch(spr){
    case Images::PLAYER:
      arduboy.drawBitmap(x, y, spr_player_b, 8, 8, BLACK);
      arduboy.drawBitmap(x, y, spr_player_w, 8, 8, WHITE);
      break;
  }
}

(Matt) #18

It’s ok to have just a header file. You can delete Sprites.cpp. For data like sprites I usually put it all in the header file.

you only need #pragma once or #ifndef ... in header files. That is because you include header files in other files, ie #include "Sprites.h", but you rarely (if ever) include cpp files in other files. Those macros (pragma or ifndef…) make sure only one copy of the file’s contents actually make it into the compiled binary.

#pragma once and #ifndef ... both accomplish the same thing. pragma is more modern. You should just pick one and stick with it.


(Pharap) #19

I believe that’s what most people here do.
(Or at least, most of the code I’ve read.)

(@city41 already answered this, but I’ll answer it again for completeness.)

Only .h files need #pragma once/include guards.
The point of them is to prevent the header being read multiple times when it’s included multiple times.
Without them you can end up with multiple definition errors.

This might seem a bit odd if you’re used to more modern languages.
There’s two main reasons for it, firstly because C++ inherited it from C, and secondly because it allows C++ to be compiled in a single ‘pass’.
Languages like C# where definitions are more flexible require multiple ‘passes’ to resolve everything.

Strictly speaking from a pure C++ point of view, you should have to have that include to be able to use byte.

However the Arduino toolchain does an extra stage of processing to translate the non-standard .ino files into valid .h/.cpp files and sometimes this has bizzare knock-on effects.
I believe this is one of them.

They’re worth knowing about. Enumerations are handy.
(‘enumerations’ are a different thing to ‘enumerators’ by the way.)

That’s fine.
Although it’s sometimes good practise to have the definition and implementation separate, it’s not strictly necessary.

class Entity
{
public:
    int x;
    int y;
};

// Array of 10 entities
Entity entities[10];

Note that the entities actually ‘live’ in the array.
Structurally the array is actually 10 Entity objects one after another, as opposed to 10 references to heap-allocated objects (which is what it would be in a language like C#/Java).

An int is 2 bytes on Arduboy (the size of int varies depending on the target platform), so by this definition Entity is 4 bytes large, so that array is actually 40 consecutive bytes in RAM - it’s comprised of 10x 4-byte entities, and each entity is comprised of a 2-byte x and a 2-byte y.
Hopefully that gives you a better idea of how the code relates to the hardware/what the semantics are.

I’m not sure what you mean by this.

It’s up to you which you do.
But as I say, I’m always happy to answer any C++-related questions.


A word about inline:
Typically the only time you need inline is when you want to define a free function in a header.
It gives the function ‘inline linkage’, which makes the linker (a component of the compilation process) treat it specially.
Without the inline linkage, you’d get an error.

Free functions in headers are the only time you need inline, no other form of function definition requires inline (i.e. you don’t need it for class member functions and you don’t need it if you’re defining a function in a .cpp file).
(If you want to know more, here’s an SO question about it.)


I’m not entirely sure about this, I’m pretty sure #pragma once is quite old.
I suspect it took a little while for it to be available in all of the big three (GCC, VC, Clang), but I’m sure it’s been around for quite some time.

I think people just became more accepting of it over time and slowly caved in until it was the norm.

I’d definitely say use #pragma once though.
For one thing the amount of time you save by typing just one line instead of three eventually adds up to a very big time saving.

You also don’t have to worry about what to call the include guard or what happens when you end up with two files with the same name in different areas of the directory tree.


(Matt) #20

I just meant in comparison to #ifndef which is as old as C is (looks like the preprocessor first came out in 1972). Most compilers didn’t support #pragma until around the mid nineties.