Problem with frame counter when called by a function

Hello !

I have a small problem with a frame counter that is not updating. Since I don’t know very much things about C/C++, I’m pretty sure I am missing something, but I don’t know what…

So what’s the problem ?

In my game, I want to animate my enemies. I created a struct to store some informations about them, x position, y position, etc… including a frame counter.

I also create a function to create an enemy. This function returns a enemy struct, which is then stored in an array containing all the enemies.

Finally I created a function to draw the enemies. the function takes as an argument en enemy struct and draws it. Thus, I’m iterating through the array containing the enemies and I’m drawing them one by one. In this function I’m updating the frame counter of the struct. But it is not working. However, if I update the frame counter directly in the main loop of the arduino sketch, it works.

Here is the code (obviously simplified) to enlighten things a bit :

the enemy.h file

// the struct containing the information for the enemies
struct Enemy {
  byte spriteSize;
  byte state; // state of the player = 0: idle, 1: kicking, 2: jumping, 3: walking, 4: punching 
  byte x;
  int y;
  int dy;
  byte frcount;
};

// create the array containing the enemies
struct Enemy enemyArray[10];

// create one enemy
struct Enemy createEnemy(int xLoc, int yLoc){
  struct Enemy locEnemy;
  
  locEnemy.state=0;
  locEnemy.spriteSize=32;
  locEnemy.x= xLoc;
  locEnemy.y= yLoc-player.spriteSize;
  locEnemy.dy=0;
  locEnemy.frcount = 0;


  return locEnemy;
}

// draw enemies
void drawEnemy(Enemy myEnemy){
      if(arduboy.everyXFrames(7)) myEnemy.frcount++;
      if(myEnemy.frcount >3)   myEnemy.frcount = 0;
      sprite.drawPlusMask(myEnemy.x-camera.offx,myEnemy.y-camera.offy,ENEMY1_WALK,myEnemy.frcount);
}

And the main file :

void setup() {
  
  // populate the enemy array
  for(int j=0; j<9; j++) {
     // create enemies at random spots on the x axis
    enemyArray[j] = createEnemy(random(512),63);
  }
  
} 

void loop() {

  if (!arduboy.nextFrame()) return;

  for( int i=0; i<9;i++){
    drawEnemy(enemyArray[i]);
  }
}

With this setup, it is not working : the frame counter appears to be constant : always the value set in createEnemy, with the line locEnemy.frcount = 0; :thinking:

However, if I remove the code in charge of the frame counter update in enemy.h and I write this in the loop() of the main file :

 for( int i=0; i<9;i++){
    drawEnemy(enemyArray[i]);
    if(arduboy.everyXFrames(7)) enemyArray[i].frcount++;
    if(enemyArray[i].frcount >3)   enemyArray[i].frcount = 0;
  }

Then it’s working.

Obviously I found a way to solve my problem. However, I’d like to understand why the idea I had in the first place (to update the frame counter in drawEnemy) was not working !

Sorry if my mistake is trivial, but as I said, I know almost nothing about the specificity of C/C++ :frowning_face:

Regards.

EDIT :

I manage to solve my problem with the following tweaks :
in the main loop :

 for( int i=0; i<9;i++){
    drawEnemy(&enemyArray[i]);
  
  } 

in enemy.h

void drawEnemy(Enemy *myEnemy){

      if(arduboy.everyXFrames(7)) myEnemy->frcount++;
      if(myEnemy->frcount >3)   myEnemy->frcount = 0;
      sprite.drawPlusMask(myEnemy->x-camera.offx,myEnemy->y-camera.offy,ENEMY1_WALK,myEnemy->frcount);

}

Although I don’t exactly understood why I had to change . into ->, it’s now working !
I’m no longer updating a copy of the enemy !

EDIT 2 :

For those who might be interested, this links provides an interesting answer : https://stackoverflow.com/questions/13366083/why-does-the-arrow-operator-in-c-exist#

1 Like

From a C perspective (C++ may be different), you have to change the . to a -> because you changed the type of the argument from Enemy to Enemy *.

Since you didn’t explicitly explain why your change worked for the record, it’s because C is a call-by-value language, and always passes copies of arguments. So when the argument is an Enemy, you pass a copy of the structure, which is what gets updated. When the argument is an Enemy *, you pass a copy of the address of the structure, so changes made through the pointer (via ->) change the structure whose address was passed in (taking the address via &).

For what it’s worth you can also do:

void drawEnemy(Enemy & myEnemy){

      if(arduboy.everyXFrames(7)) myEnemy.frcount++;
      if(myEnemy.frcount > 3)  myEnemy.frcount = 0;
      sprite.drawPlusMask(myEnemy.x - camera.offx, myEnemy.y - camera.offy,ENEMY1_WALK, myEnemy.frcount);

}

And the result will be the same as using the arrow operator.

The magic & thing makes the argument a ‘reference’ which acts similarly to using a pointer without having to actually work with a pointer.