Help with collide or other method

Hi, I am new with arduboy and I want to improve the ‘Graphics’ tutorial for myself.

I’ve added two blocks in the screen of the arduboy, One rock and one flower.
I want the player to be blocked by the rock and by opposition when touching the flower, the latter disappear.
Finally, I would like one rock and one flower spawn randomly to the screen avoiding the player’s bitmap and avoiding spawning themselves each other too.

Here’s the current code.

#include <Arduboy.h>
Arduboy arduboy;

#define SCREENWIDTH  128
#define SCREENHEIGHT  64
#define PLAYERWIDTH   16
#define PLAYERHEIGHT  16

int playerx = 5;
int playery = 10;
int playerwidth = 16;
int playerheight = 16;
int screenwidth = 128;
int screenheight = 64;

const unsigned char background[] PROGMEM  = {
    0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,
};
const unsigned char player[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,
};
const unsigned char rock[] PROGMEM  = {
   0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00, 
};
const unsigned char flower[] PROGMEM  = {
   0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00, 
};


void setup() {
    arduboy.begin();
    arduboy.clear();
}
void loop() {
    arduboy.clear();
    if(arduboy.pressed(LEFT_BUTTON)) {
        playerx = playerx - 1;
        if(playerx<0) playerx=0;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
        playerx = playerx + 1;
        if(playerx+PLAYERWIDTH>SCREENWIDTH) playerx=SCREENWIDTH-PLAYERWIDTH;
    }
    if(arduboy.pressed(UP_BUTTON)) {
        playery = playery - 1;
        if(playery<0) playery=0;
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        playery = playery + 1;
        if(playery+PLAYERHEIGHT>SCREENHEIGHT) playery=SCREENHEIGHT-PLAYERHEIGHT;
    }
    //For each column on the screen
    for( int backgroundx = 0; backgroundx < 128; backgroundx = backgroundx + 8 ) {
        //For each row in the column
        for( int backgroundy = 0; backgroundy < 64; backgroundy = backgroundy + 8 ) {
                //Draw a background tile
            arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );
        }
    }

    arduboy.fillRect(80, 16, 16, 16, BLACK);
    arduboy.drawBitmap(80, 16, flower, 16, 16, WHITE);

    arduboy.fillRect(48, 16, 16, 16, BLACK);
    arduboy.drawBitmap(48, 16, rock, 16, 16, WHITE);
    
    arduboy.fillRect(playerx, playery, 16, 16, BLACK);
    arduboy.drawBitmap(playerx, playery, player, 16, 16, WHITE);

    
    arduboy.display();
}

Firstly, I have changed the reference from Arduboy (the old library) to the new Arduboy2 library as it is the supported one.

You will notice that I have created a little function that spawns a rock in a random location on the screen. I haven’t bothered to check to see it it is on top of other items - I will leave that to you. The X and Y coordinates are stored in a Point structure and the portion of the screen that it occupies is stored in a Rect structure for use later on when performing collision detection.

Before the player moves, I create a rectangle of the proposed location of the player and test to see if it would collide with the rock using the Arduboy2 collide method. If not, then it is valid to make the move.

This could be expanded to test for a collision with the flower. When the collision occurs, the flower can be respawned using a similar idea to the spawnRock function already in the code.

HTH

#include <Arduboy2.h>
Arduboy2 arduboy;

#define SCREENWIDTH  128
#define SCREENHEIGHT  64
#define PLAYERWIDTH   16
#define PLAYERHEIGHT  16

int playerx = 5;
int playery = 10;
int playerwidth = 16;
int playerheight = 16;
int screenwidth = 128;
int screenheight = 64;

Point rockLocation;
Rect rockRect;

const unsigned char background[] PROGMEM  = {
    0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,
};
const unsigned char player[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,
};
const unsigned char rock[] PROGMEM  = {
   0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00, 
};
const unsigned char flower[] PROGMEM  = {
   0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00, 
};

void spawnRock() {

  rockLocation.x = random(0, 128 - 16);
  rockLocation.y = random(0, 64 - 16);
  rockRect = { rockLocation.x, rockLocation.y, 16, 16 };

}

void setup() {
  
    arduboy.begin();
    arduboy.clear();
    arduboy.initRandomSeed();

    spawnRock();
}

void loop() {
    arduboy.clear();
    if(arduboy.pressed(LEFT_BUTTON)) {
        Rect playerRect = { playerx -1, playery, 16, 16 };
        if (!arduboy.collide(playerRect, rockRect) && playerx > 0) {
          playerx = playerx - 1;
        }
    }
    
    if(arduboy.pressed(RIGHT_BUTTON)) {
        Rect playerRect = { playerx + 1, playery, 16, 16 };
        if (!arduboy.collide(playerRect, rockRect) && playerx + PLAYERWIDTH < SCREENWIDTH - 1) {
          playerx++;
        }
    }

    if(arduboy.pressed(UP_BUTTON)) {
        Rect playerRect = { playerx, playery - 1, 16, 16 };
        if (!arduboy.collide(playerRect, rockRect) && playery > 0) {
          playery = playery - 1;
        }
    }

    if(arduboy.pressed(DOWN_BUTTON)) {
        Rect playerRect = { playerx, playery + 1, 16, 16 };
        if (!arduboy.collide(playerRect, rockRect) && playery+PLAYERHEIGHT < SCREENHEIGHT - 1) {
          playery = playery + 1;
        }
    }

    //For each column on the screen
    for( int backgroundx = 0; backgroundx < 128; backgroundx = backgroundx + 8 ) {
        //For each row in the column
        for( int backgroundy = 0; backgroundy < 64; backgroundy = backgroundy + 8 ) {
                //Draw a background tile
            arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );
        }
    }

    arduboy.fillRect(80, 16, 16, 16, BLACK);
    arduboy.drawBitmap(80, 16, flower, 16, 16, WHITE);

    arduboy.fillRect(rockLocation.x, rockLocation.y, 16, 16, BLACK);
    arduboy.drawBitmap(rockLocation.x, rockLocation.y, rock, 16, 16, WHITE);
    
    arduboy.fillRect(playerx, playery, 16, 16, BLACK);
    arduboy.drawBitmap(playerx, playery, player, 16, 16, WHITE);
    
    arduboy.display();
}

Other notes:

  • SCREENWIDTH and SCREENHEIGHT are already defined in the Arduboy2 library as WIDTH and HEIGHT.
    The man is defined as 16 pixels wide but is really only 8 or so. The collision function will detect a collision with the edges of the bitmap - even if the pixels are blank / black.
  • playerx and playery could be converted into a single Point structure.
Rect player;
...
player.x = 5;
player.y = 10;
2 Likes

Thanks I managed to make spawn a rock and a flower and to make them interact with the player.

I want now to make the same thing but with 3 rocks.
I tried with the code below, there are 3 rocks but the player isn’t blocked, also it goes faster, I can’t understand.

#include <Arduboy2.h>

Arduboy2 arduboy;

#define PLAYERWIDTH   16

#define PLAYERHEIGHT  16

Point player;

Rect playerRect;

Point rockLocation[3];

Rect rockRect[3];


const unsigned char background[] PROGMEM  = {

    0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,

};

const unsigned char playerbitmap[] PROGMEM  = {

    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,

};

const unsigned char rock[] PROGMEM  = {

   0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00, 

};

const unsigned char flower[] PROGMEM  = {

   0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00, 

};

void spawnPlayer() {

  player.x = 50;
  
  player.y = 20;

  playerRect = { player.x - 1, player.y, 16, 16 };
  
}


void spawnRocks() {

for ( int i = 0; i < 3; i = i + 1 ) {

  rockLocation[i].x = random(0, 128 - 16);

  rockLocation[i].y = random(0, 64 - 16);

  rockRect[i] = { rockLocation[i].x, rockLocation[i].y, 16, 16 };

}
}


void setup() {



    arduboy.begin();

    arduboy.clear();

    arduboy.initRandomSeed();

    spawnPlayer();   

    spawnRocks();
 
}



void loop() {
    
    arduboy.clear();
    
      
    if(arduboy.pressed(LEFT_BUTTON)) {
       
        Rect playerRect = { player.x - 1, player.y, 16, 16 };

        for ( int i = 0; i < 3; i = i + 1 ) { 
        
        if (!arduboy.collide(playerRect, rockRect[i]) && player.x > 0) {
        
          player.x = player.x - 1;
        }
        }

    }

    

    if(arduboy.pressed(RIGHT_BUTTON)) {

        Rect playerRect = { player.x + 1, player.y, 16, 16 };

        for ( int i = 0; i < 3; i = i + 1 ) {
        
        if (!arduboy.collide(playerRect, rockRect[i]) && player.x + PLAYERWIDTH < WIDTH ) {
        
        
          player.x = player.x + 1;
        } 
        }

    }



    if(arduboy.pressed(UP_BUTTON)) {

        Rect playerRect = { player.x, player.y - 1, 16, 16 };

        for ( int i = 0; i < 3; i = i + 1 ) {
        
        if (!arduboy.collide(playerRect, rockRect[i]) && player.y > 0) {
                
          player.y = player.y - 1;
        }
        }

    }



    if(arduboy.pressed(DOWN_BUTTON)) {

        Rect playerRect = { player.x, player.y + 1, 16, 16 };

        for ( int i = 0; i < 3; i = i + 1 ) {
        
        if (!arduboy.collide(playerRect, rockRect[i]) && player.y + PLAYERHEIGHT < HEIGHT  ) {
        
          player.y = player.y + 1;
        }
        }

    }



    //For each column on the screen

    for( int backgroundx = 0; backgroundx < 128; backgroundx = backgroundx + 8 ) {

        //For each row in the column

        for( int backgroundy = 0; backgroundy < 64; backgroundy = backgroundy + 8 ) {

                //Draw a background tile

            arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );

        }

    }


    arduboy.fillRect(player.x, player.y, 16, 16, BLACK);

    arduboy.drawBitmap(player.x, player.y, playerbitmap, 16, 16, WHITE);



    for ( int i = 0; i < 3; i = i + 1 ) {
    
    arduboy.fillRect(rockLocation[i].x, rockLocation[i].y, 16, 16, BLACK);
    
    arduboy.drawBitmap(rockLocation[i].x, rockLocation[i].y, rock, 16, 16, WHITE);

    }


    arduboy.display();

}

That’s an easy one to solve.

for ( int i = 0; i < 3; i = i + 1 ) {        
if (!arduboy.collide(playerRect, rockRect[i]) && player.x > 0) {
        
          player.x = player.x - 1;
}
}

One of the easiest way to find/fix bugs is to read through the code pretending to do what the Arduboy would do.

If the player isn’t colliding with rock 0 and the player’s x is greater than zero,
you move the player left one pixel.
If the player isn’t colliding with rock 1 and the player’s x is greater than zero,
you move the player left another pixel.
If the player isn’t colliding with rock 2 and the player’s x is greater than zero,
you move the player left yet another pixel.

So essentially if there aren’t any rocks encountered, the player is moved left 3 pixels instead of 1.

Try this instead:

if(arduboy.pressed(LEFT_BUTTON))
{   
	Rect playerRect = { player.x - 1, player.y, 16, 16 };

	// Assume the player won't hit any rocks
	bool hitARock = false;
	
	// For all rocks
	for (int i = 0; i < 3; i = i + 1)
	{
		// Check if the player would hit that rock
		if (arduboy.collide(playerRect, rockRect[i]))
		{
			// If they would hit that rock,
			// then make a note of the fact they would hit a rock
			hitARock = true;
		}
	}
	
	// If the player wouldn't hit any rocks,
	// and if the player can move left without going off-screen
	if(!hitARock && player.x > 0)
	{
		// Move the player left
		player.x = player.x - 1;
	}
	// (Implicitly) otherwise, if the player would hit a rock or can't move left
	// don't move left
}

That should hopefully fix the other two problems as well.
(Because previously the player would hit a rock and then still move left twice.)

I’ve given you the solution for how to adapt moving left,
see if you can adapt the other directions based on that.

@ArduL Any progress?

Yes it works. I’ve Added a function that prevent rocks from collide themselves but sometimes there are Strange things happening when turning on the arduboy. I think i am doing Something wrong.

Can you tell me? that is the ‘checkRockCollision()’ function.

#include <Arduboy2.h>

Arduboy2 arduboy;

#define PLAYERWIDTH   16

#define PLAYERHEIGHT  16

Point player;

Rect playerRect;

Point rockLocation[3];

Rect rockRect[3];


const unsigned char background[] PROGMEM  = {

  0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,

};

const unsigned char playerbitmap[] PROGMEM  = {

  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,

};

const unsigned char rock[] PROGMEM  = {

  0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00,

};

const unsigned char flower[] PROGMEM  = {

  0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00,

};

void spawnPlayer() {

  player.x = 50;

  player.y = 20;

  playerRect = { player.x - 1, player.y, 16, 16 };

}


void spawnRocks() {

  for ( int i = 0; i < 3; i = i + 1 ) {



    rockLocation[i].x = random(0, 128 - 16);

    rockLocation[i].y = random(0, 64 - 16);

    rockRect[i] = { rockLocation[i].x, rockLocation[i].y, 16, 16 };

    checkRockCollision();
  }
}

void checkRockCollision() {

  bool rockCollision = false;

  for ( int i = 0; i < 3; i = i + 1 ) {
    for ( int j = 0; j < 3; j = j + 1 ) {
      if (i > 0 && i != j ) {
        if (arduboy.collide(rockRect[j], rockRect[i])) rockCollision = true;
      }
    }
  }
  if (rockCollision == true) spawnRocks();
}


void setup() {



  arduboy.begin();

  arduboy.clear();

  arduboy.initRandomSeed();

  spawnPlayer();

  spawnRocks();


}



void loop() {

  arduboy.clear();


  if (arduboy.pressed(LEFT_BUTTON)) {

    Rect playerRect = { player.x - 1, player.y, 16, 16 };

    bool hitARock = false;

    for ( int i = 0; i < 3; i = i + 1 ) {

      if (arduboy.collide(playerRect, rockRect[i])) {

        hitARock = true;
      }
    }

    if (!hitARock && player.x > 0) {
      player.x = player.x - 1;
    }


  }



  if (arduboy.pressed(RIGHT_BUTTON)) {

    Rect playerRect = { player.x + 1, player.y, 16, 16 };

    bool hitARock = false;

    for ( int i = 0; i < 3; i = i + 1 ) {
      if (arduboy.collide(playerRect, rockRect[i])) {

        hitARock = true;
      }
    }

    if (!hitARock && player.x + PLAYERWIDTH < WIDTH ) {


      player.x = player.x + 1;
    }
  }





  if (arduboy.pressed(UP_BUTTON)) {

    Rect playerRect = { player.x, player.y - 1, 16, 16 };

    bool hitARock = false;

    for ( int i = 0; i < 3; i = i + 1 ) {
      if (arduboy.collide(playerRect, rockRect[i])) {
        hitARock = true;
      }
    }

    if (!hitARock && player.y > 0) {

      player.y = player.y - 1;
    }
  }





  if (arduboy.pressed(DOWN_BUTTON)) {

    Rect playerRect = { player.x, player.y + 1, 16, 16 };

    bool hitARock = false;

    for ( int i = 0; i < 3; i = i + 1 ) {
      if (arduboy.collide(playerRect, rockRect[i])) {
        hitARock = true;
      }
    }


    if (!hitARock && player.y + PLAYERHEIGHT < HEIGHT  ) {

      player.y = player.y + 1;
    }
  }





  //For each column on the screen

  for ( int backgroundx = 0; backgroundx < 128; backgroundx = backgroundx + 8 ) {

    //For each row in the column

    for ( int backgroundy = 0; backgroundy < 64; backgroundy = backgroundy + 8 ) {

      //Draw a background tile

      arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );

    }

  }


  arduboy.fillRect(player.x, player.y, 16, 16, BLACK);

  arduboy.drawBitmap(player.x, player.y, playerbitmap, 16, 16, WHITE);



  for ( int i = 0; i < 3; i = i + 1 ) {

    arduboy.fillRect(rockLocation[i].x, rockLocation[i].y, 16, 16, BLACK);

    arduboy.drawBitmap(rockLocation[i].x, rockLocation[i].y, rock, 16, 16, WHITE);

  }


  arduboy.display();

}

Yep, you’ve got two functions that are calling each other.
That can lead to the code getting ‘stuck’ because the functions don’t stop calling each other.

The reason you sometimes get an issue is that calling functions costs memory, so if the two functions call each other enough the Arduboy could run out of memory, at which point weird stuff is guaranteed to happen.

You’re probably thinking that rocks colliding shouldn’t happen often, but there’s four factors at work here:

  1. random isn’t actually random, it’s ‘pseudorandom’, which means it’s only pretending to be random.
  2. A thing called the ‘pigeon hole principle’ which basically means that the more rocks you add, the less space there is, so the chance of a collision increases. (See also: ‘birthday paradox’.)

And now the more important/more immediate problems:

  1. You’re checking for collisions against rocks you haven’t initialised yet.
  2. You’re trying to reshuffle all the rocks even if only two are colliding.

Try replacing spawnRocks and checkRockCollision with these:

// Spawns a single rock at the specified index
void spawnRock(size_t index)
{
	rockLocation[index].x = random(0, 128 - 16);
	rockLocation[index].y = random(0, 64 - 16);
	rockRect[index] = { rockLocation[index].x, rockLocation[index].y, 16, 16 };
}

// Check if the given rock collides with any of the rocks before it
bool checkRockCollisions(size_t index)
{
	// Only check collisions against existing rocks
	for(int i = 0; i < index; ++i)
	{
		if(arduboy.collide(rockRect[i], rockRect[index]))
		{
			return true;
		}
	}
	return false;
}

// Spawns multiple rocks
void spawnRocks()
{
	for(int i = 0; i < 3; ++i)
	{	
		bool colliding = true;
		while(colliding)
		{
			spawnRock(i);
			colliding = checkRockCollisions(i);
		}
	}
}

Technically, rockLocation is redundant while you have rockRect around because the location information is being duplicated.
However, you could stick to just rockLocation and make the rockRects as and when you need them since the width and height of rocks never changes (unless you’re planning to add more sizes).

Likewise for player and playerRect.
(You already are generating a local playerRect in the movement code anyway, so changing to just player shouldn’t be too hard.)


A few unsolicited stylistic tips:

  • ++i can be used instead of i = i + 1, it means the same thing but it’s shorter to type and more commonly used.
  • if(rockCollision == true) is redundant, if(rockCollision) would have the same effect. Essentially saying if(rockCollision == true) is equivalent to saying if(true == true) or if(false == true), which then evaluates to either if(true) or if(false), so the second half is redundant.
  • #define is ‘evil’, prefer const variables, e.g. const int PlayerWidth = 16

> Technically, rockLocation is redundant while you haverockRectaround because the location information is being duplicated. However, you could stick to justrockLocationand make therockRect`s as and when you need them since the width and height of rocks never changes (unless you’re planning to add more sizes).
> Likewise for player and playerRect.
> (You already are generating a local playerRect in the movement code anyway, so changing to just player shouldn’t be too hard.)

You provide really good help but i Don’t understand this phrase.
Could you be more specific?

Just realised I missed a ` on the original, but I’ve fixed that now.


The rockLocation array is an array of the rocks’ positions.
The rockRect array is an array of the rocks’ boundaries.
By definition, but boundaries include the position, which means rockRect[i].x has the same purpose as rockLocation[i].x and rockRect[i].y has the same purpose as rockLocation[i].y,
however they are stored in two separate locations, so you end up having to update both.

I.e. you end up writing things like this:

rockLocation[index].x = random(0, 128 - 16);
rockLocation[index].y = random(0, 64 - 16);
rockRect[index] = { rockLocation[index].x, rockLocation[index].y, 16, 16 };

Instead what you could do is get rid of the rockRect array and just have the rockLocation array, and then whenever you need to check for collisions, create a rectangle as and when you need it.
E.g.

Rect rockRectA = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
Rect rockRectB = { rockLocation[j].x, rockLocation[j].y, rockWidth, rockHeight };
if(arduboy.collide(rockRectA, rockRectB))
{
// Do Stuff
}

The same problem exists for player and playerRect, one represents the player’s position, the other represents the player’s ‘boundaries’ (position and size).
Instead you could just keep the player position and create the player’s boundaries as a local Rect when you need to do collision checking.

Alternatively, you could get rid of the location variables and just use the Rects.
Both approaches work, but they will have different impacts on the size of the compiled code.

You know I’m a perfect newbie, I’m starting from zero in c++.
Can you give me a concrete example by modifying my code.
I cannot grasp what you tell me.
Are there simplicity advantages of doing this apart saving memory?

#include <Arduboy2.h>

Arduboy2 arduboy;

const int playerWidth = 16;
const int playerHeight = 16;

Point player;
Rect playerRect;

Point rockLocation[3];
Rect rockRect[3];

const unsigned char background[] PROGMEM  = {

  0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,

};

const unsigned char playerbitmap[] PROGMEM  = {

  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,

};

const unsigned char rock[] PROGMEM  = {

  0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00,

};

const unsigned char flower[] PROGMEM  = {

  0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00,

};

void spawnPlayer() {

  player.x = 50;
  player.y = 20;
  playerRect = { player.x - 1, player.y, 16, 16 };

}


void spawnRock(size_t index)
{
  rockLocation[index].x = random(0, 128 - 16);
  rockLocation[index].y = random(0, 64 - 16);
  rockRect[index] = { rockLocation[index].x, rockLocation[index].y, 16, 16 };
}


void spawnRocks()
{
  for (int i = 0; i < 3; ++i)
  {
    bool colliding = true;
    while (colliding)
    {
      spawnRock(i);
      colliding = checkRockCollisions(i);
    }
  }
}


bool checkRockCollisions(size_t index)
{

  // Only check collisions against existing rocks
  for (int i = 0; i < index; ++i)
  {
    if (arduboy.collide(rockRect[i], rockRect[index]))
    {
      return true;
    }
  }
  return false;
}



void setup() {

  arduboy.begin();
  arduboy.clear();
  arduboy.initRandomSeed();
  spawnPlayer();
  spawnRocks();
}



void loop() {

  arduboy.clear();

  if (arduboy.pressed(LEFT_BUTTON)) {

    Rect playerRect = { player.x - 1, player.y, 16, 16 };

    bool hitARock = false;
    for ( int i = 0; i < 3; ++i) {
      if (arduboy.collide(playerRect, rockRect[i])) {
        hitARock = true;
      }
    }

    if (!hitARock && player.x > 0) {
      player.x = player.x - 1;
    }
  }



  if (arduboy.pressed(RIGHT_BUTTON)) {

    Rect playerRect = { player.x + 1, player.y, 16, 16 };

    bool hitARock = false;
    for ( int i = 0; i < 3; ++i) {
      if (arduboy.collide(playerRect, rockRect[i])) {
        hitARock = true;
      }
    }

    if (!hitARock && player.x + playerWidth < WIDTH ) {
      player.x = player.x + 1;
    }
  }





  if (arduboy.pressed(UP_BUTTON)) {

    Rect playerRect = { player.x, player.y - 1, 16, 16 };

    bool hitARock = false;
    for ( int i = 0; i < 3; ++i) {
      if (arduboy.collide(playerRect, rockRect[i])) {
        hitARock = true;
      }
    }
    if (!hitARock && player.y > 0) {
      player.y = player.y - 1;
    }
  }





  if (arduboy.pressed(DOWN_BUTTON)) {

    Rect playerRect = { player.x, player.y + 1, 16, 16 };

    bool hitARock = false;
    for ( int i = 0; i < 3; ++i) {
      if (arduboy.collide(playerRect, rockRect[i])) {
        hitARock = true;
      }
    }

    if (!hitARock && player.y + playerHeight < HEIGHT  ) {
      player.y = player.y + 1;
    }
  }





  //For each column on the screen

  for ( int backgroundx = 0; backgroundx < 128; backgroundx = backgroundx + 8 ) {

    //For each row in the column

    for ( int backgroundy = 0; backgroundy < 64; backgroundy = backgroundy + 8 ) {

      //Draw a background tile

      arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );

    }

  }

  arduboy.fillRect(player.x, player.y, 16, 16, BLACK);

  arduboy.drawBitmap(player.x, player.y, playerbitmap, 16, 16, WHITE);


  for ( int i = 0; i < 3; ++i) {

    arduboy.fillRect(rockLocation[i].x, rockLocation[i].y, 16, 16, BLACK);

    arduboy.drawBitmap(rockLocation[i].x, rockLocation[i].y, rock, 16, 16, WHITE);

  }

  arduboy.display();

}

Yes, it means you have less global variables to keep track of/keep in sync.

Here’s an example of just storing the locations and creating the rectangles as they’re needed.

#include <Arduboy2.h>

Arduboy2 arduboy;

const int playerWidth = 16;
const int playerHeight = 16;
const int rockWidth = 16;
const int rockHeight = 16;

Point player;
Point rockLocation[3];

const unsigned char background[] PROGMEM =
{
  0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,
};

const unsigned char playerbitmap[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,
};

const unsigned char rock[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00,
};

const unsigned char flower[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00,
};

void spawnPlayer()
{
  player.x = 50;
  player.y = 20;
}

void spawnRock(size_t index)
{
  rockLocation[index].x = random(128 - rockWidth);
  rockLocation[index].y = random(64 - rockHeight);
}

void spawnRocks()
{
  for (size_t i = 0; i < 3; ++i)
  {
    bool colliding = true;
    while (colliding)
    {
      spawnRock(i);
      colliding = checkRockCollisions(i);
    }
  }
}

bool checkRockCollisions(size_t index)
{
  // Only check collisions against existing rocks
  Rect rockRect = { rockLocation[index].x, rockLocation[index].y, rockWidth, rockHeight };
  for (size_t i = 0; i < index; ++i)
  {
    Rect otherRockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
    if (arduboy.collide(rockRect, otherRockRect))
    {
      return true;
    }
  }
  return false;
}

bool isCollidingWithAnyRock(Rect rect)
{
  for(size_t i = 0; i < 3; ++i)
  {
    Rect rockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
    if (arduboy.collide(rect, rockRect))
    {
      return true;
    }
  }
  return false;
}

void setup()
{
  arduboy.begin();
  arduboy.clear();
  arduboy.initRandomSeed();
  spawnPlayer();
  spawnRocks();
}

void loop()
{
  arduboy.clear();

  if (arduboy.pressed(LEFT_BUTTON)) {

    Rect playerRect = { player.x - 1, player.y, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);

    if (!hitARock && player.x > 0) {
      player.x = player.x - 1;
    }
  }

  if (arduboy.pressed(RIGHT_BUTTON)) {

    Rect playerRect = { player.x + 1, player.y, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);

    if (!hitARock && player.x + playerWidth < WIDTH ) {
      player.x = player.x + 1;
    }
  }

  if (arduboy.pressed(UP_BUTTON)) {

    Rect playerRect = { player.x, player.y - 1, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);
    
    if (!hitARock && player.y > 0) {
      player.y = player.y - 1;
    }
  }

  if (arduboy.pressed(DOWN_BUTTON)) {

    Rect playerRect = { player.x, player.y + 1, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);

    if (!hitARock && player.y + playerHeight < HEIGHT  ) {
      player.y = player.y + 1;
    }
  }


  //For each column on the screen
  for ( int backgroundx = 0; backgroundx < arduboy.width(); backgroundx = backgroundx + 8 ) {
    //For each row in the column
    for ( int backgroundy = 0; backgroundy < arduboy.height(); backgroundy = backgroundy + 8 ) {
      //Draw a background tile
      arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );
    }
  }

  //arduboy.fillRect(player.x, player.y, playerWidth, playerHeight, BLACK);
  arduboy.drawBitmap(player.x, player.y, playerbitmap, playerWidth, playerHeight, WHITE);

  for ( int i = 0; i < 3; ++i) {
    //arduboy.fillRect(rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight, BLACK);
    arduboy.drawBitmap(rockLocation[i].x, rockLocation[i].y, rock, rockWidth, rockHeight, WHITE);
  }

  arduboy.display();
}

I also:

  • added the constants rockWidth and rockHeight
  • rewrote some parts to use playerWidth, playerHeight, rockWidth and rockHeight
  • rewrote one part to use arduboy.width() and arduboy.height() instead of 128 and 64
  • added the function isCollidingWithAnyRock to make the button code simpler
  • changed a few ints to size_ts (technically size_t is the correct type for indexing an array, usually other numeric types work fine but size_t is the ‘official’ type)

Effectively that’s simple.

I found my code messy with all these functions, I’m trying to merge ‘spawnRocks()’ and ‘checkRockCollisions’

void spawnRocks()

{
  for (size_t i = 0; i < 3; ++i)
  {
    bool colliding = true;
    while (colliding)
    {
      spawnRock(i);
      colliding = checkRockCollisions(i);
    }
  }
}



bool checkRockCollisions(size_t index)
{
  // Only check collisions against existing rocks
  Rect rockRect = { rockLocation[index].x, rockLocation[index].y, rockWidth, rockHeight };
  for (size_t i = 0; i < index; ++i)
  {
    Rect otherRockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
    if (arduboy.collide(rockRect, otherRockRect))
    {
      return true;
    }
  }
  return false;
}

I’ve tried that:

void spawnRocks()
{
  for (size_t i = 0; i < 3; ++i)
  {
    bool colliding = true;
    while (colliding)
    {
      spawnRock(i);

      Rect rockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };

      for (size_t j = 0; j < i; ++j)
      {

        Rect otherRockRect = { rockLocation[j].x, rockLocation[j].y, rockWidth, rockHeight };
        if (arduboy.collide(rockRect, otherRockRect))
        {
          colliding = true;
        }
        
      }
      colliding = false;
    }
  }
}

but there are still collisions between rocks.

The solution to messy code is rarely ‘use less functions’.
(Quite the oposite, often it’s ‘use more functions’.)

If you’re finding the code is getting too long, you’d be better off learning how to use multiple files instead.
(Though currently this code isn’t that long. Good code is usually around 50-300 lines. Some messier code reaches 1000 lines. It’s better to have 10 100-line files than 1 1000-line file.)

For example:

Images.h:

#pragma once

const unsigned char background[] PROGMEM =
{
  0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,
};

const unsigned char playerbitmap[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,
};

const unsigned char rock[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00,
};

const unsigned char flower[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00,
};

Ardurocks.ino:

#include <Arduboy2.h>
#include "Images.h"

Arduboy2 arduboy;

const int playerWidth = 16;
const int playerHeight = 16;
const int rockWidth = 16;
const int rockHeight = 16;

Point player;
Point rockLocation[3];

void spawnPlayer()
{
  player.x = 50;
  player.y = 20;
}

void spawnRock(size_t index)
{
  rockLocation[index].x = random(128 - rockWidth);
  rockLocation[index].y = random(64 - rockHeight);
}

void spawnRocks()
{
  for (size_t i = 0; i < 3; ++i)
  {
    bool colliding = true;
    while (colliding)
    {
      spawnRock(i);
      colliding = checkRockCollisions(i);
    }
  }
}

bool checkRockCollisions(size_t index)
{
  // Only check collisions against existing rocks
  Rect rockRect = { rockLocation[index].x, rockLocation[index].y, rockWidth, rockHeight };
  for (size_t i = 0; i < index; ++i)
  {
    Rect otherRockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
    if (arduboy.collide(rockRect, otherRockRect))
    {
      return true;
    }
  }
  return false;
}

bool isCollidingWithAnyRock(Rect rect)
{
  for(size_t i = 0; i < 3; ++i)
  {
    Rect rockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
    if (arduboy.collide(rect, rockRect))
    {
      return true;
    }
  }
  return false;
}

void setup()
{
  arduboy.begin();
  arduboy.clear();
  arduboy.initRandomSeed();
  spawnPlayer();
  spawnRocks();
}

void loop()
{
  arduboy.clear();

  if (arduboy.pressed(LEFT_BUTTON)) {

    Rect playerRect = { player.x - 1, player.y, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);

    if (!hitARock && player.x > 0) {
      player.x = player.x - 1;
    }
  }

  if (arduboy.pressed(RIGHT_BUTTON)) {

    Rect playerRect = { player.x + 1, player.y, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);

    if (!hitARock && player.x + playerWidth < WIDTH ) {
      player.x = player.x + 1;
    }
  }

  if (arduboy.pressed(UP_BUTTON)) {

    Rect playerRect = { player.x, player.y - 1, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);
    
    if (!hitARock && player.y > 0) {
      player.y = player.y - 1;
    }
  }

  if (arduboy.pressed(DOWN_BUTTON)) {

    Rect playerRect = { player.x, player.y + 1, playerWidth, playerHeight };

    bool hitARock = isCollidingWithAnyRock(playerRect);

    if (!hitARock && player.y + playerHeight < HEIGHT  ) {
      player.y = player.y + 1;
    }
  }


  //For each column on the screen
  for ( int backgroundx = 0; backgroundx < arduboy.width(); backgroundx = backgroundx + 8 ) {
    //For each row in the column
    for ( int backgroundy = 0; backgroundy < arduboy.height(); backgroundy = backgroundy + 8 ) {
      //Draw a background tile
      arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );
    }
  }

  arduboy.fillRect(player.x, player.y, playerWidth, playerHeight, BLACK);
  arduboy.drawBitmap(player.x, player.y, playerbitmap, playerWidth, playerHeight, WHITE);

  for ( int i = 0; i < 3; ++i) {
    arduboy.fillRect(rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight, BLACK);
    arduboy.drawBitmap(rockLocation[i].x, rockLocation[i].y, rock, rockWidth, rockHeight, WHITE);
  }

  arduboy.display();
}

Using multiple files gets a bit more complicated with functions though.

Using Arduino-speficic .ino files removes some of the complexity, but .ino file rules aren’t standard C++.
Using standard C++ there’s some extra rules.

Hello.
I’ve just Added three flowers.
My goal, obviously is to avoid player, rocks and flowers spawns colliding with themselves.
I would be kind enouth to call for example the spawnRocks() function and then call two funtions checkPlayerCollisions() and checkRocksCollisions().
Also, do the same with spawnFlowers() but this time with three functions, checkPlayerCollisions() , checkRocksCollisions() and checkFlowersCollisions() .

spawnRocks() => checkPlayerCollisions()
checkRocksCollisions()

spawnFlowers() => checkPlayerCollisions()
checkRocksCollisions()
checkFlowersCollisions()

I know ‘while’ condition is practical but as wrote in the code it checks only one verification.
I think also Collisions functions must be rewrote.

Perhaps you could help me with that ?
In theory would that be possible ?

Here is My actual code :

#include <Arduboy2.h>

Arduboy2 arduboy;

const int playerWidth = 16;
const int playerHeight = 16;
const int rockWidth = 16;
const int rockHeight = 16;
const int flowerWidth = 16;
const int flowerHeight = 16;

Point player;
Point rockLocation[3];
Point flowerLocation[3];

const unsigned char background[] PROGMEM =
{
  0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,
};



const unsigned char playerbitmap[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,
};



const unsigned char rock[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00,
};



const unsigned char flower[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00,
};



void spawnPlayer()
{
  player.x = 50;
  player.y = 20;
}

void spawnRock(size_t index)
{
  rockLocation[index].x = random(128 - rockWidth);
  rockLocation[index].y = random(64 - rockHeight);
}

void spawnFlower(size_t index)
{
  flowerLocation[index].x = random(128 - flowerWidth);
  flowerLocation[index].y = random(64 - flowerHeight);
}

void spawnRocks()
{
  for (size_t i = 0; i < 3; ++i)
  {
    bool colliding = true;
    while (colliding)
    {
      spawnRock(i);
      colliding = checkRockCollisions(i);
    }
  }
}

void spawnFlowers()
{
  for (size_t i = 0; i < 3; ++i)
  {
    bool colliding = true;
    while (colliding)
    {
      spawnFlower(i);
      colliding = checkFlowerCollisions(i);
    }
  }
}

bool checkPlayerCollisions(size_t index)
{
  Rect rockRect = { rockLocation[index].x, rockLocation[index].y, rockWidth, rockHeight };
  Rect playerRect = { player.x, player.y, playerWidth, playerHeight };

  if (arduboy.collide(rockRect, playerRect))
  {
    return true;
  }
  return false;
}

bool checkRockCollisions(size_t index)
{

  // Only check collisions against existing rocks
  Rect rockRect = { rockLocation[index].x, rockLocation[index].y, rockWidth, rockHeight };
  for (size_t i = 0; i < index; ++i)
  {
    Rect otherRockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
    if (arduboy.collide(rockRect, otherRockRect))
    {
      return true;
    }
  }
  return false;
}

bool checkFlowerCollisions(size_t index)
{

  Rect flowerRect = { flowerLocation[index].x, flowerLocation[index].y, flowerWidth, flowerHeight };

  // Only check collisions against existing flowers
  for (size_t i = 0; i < index; ++i)
  {
    Rect otherFlowerRect = { flowerLocation[i].x, flowerLocation[i].y, flowerWidth, flowerHeight };
    if (arduboy.collide(flowerRect, otherFlowerRect))
    {
      return true;
    }


  }
  return false;
}




bool isCollidingWithAnyRock(Rect rect)
{
  for (size_t i = 0; i < 3; ++i)
  {
    Rect rockRect = { rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight };
    if (arduboy.collide(rect, rockRect))
    {
      return true;
    }
  }
  return false;
}



void setup()

{

  arduboy.begin();

  arduboy.clear();

  arduboy.initRandomSeed();

  spawnPlayer();

  spawnRocks();

  spawnFlowers();

}



void loop()

{

  arduboy.clear();



  if (arduboy.pressed(LEFT_BUTTON)) {



    Rect playerRect = { player.x - 1, player.y, playerWidth, playerHeight };



    bool hitARock = isCollidingWithAnyRock(playerRect);



    if (!hitARock && player.x > 0) {

      player.x = player.x - 1;

    }

  }



  if (arduboy.pressed(RIGHT_BUTTON)) {



    Rect playerRect = { player.x + 1, player.y, playerWidth, playerHeight };



    bool hitARock = isCollidingWithAnyRock(playerRect);



    if (!hitARock && player.x + playerWidth < WIDTH ) {

      player.x = player.x + 1;

    }

  }



  if (arduboy.pressed(UP_BUTTON)) {



    Rect playerRect = { player.x, player.y - 1, playerWidth, playerHeight };



    bool hitARock = isCollidingWithAnyRock(playerRect);



    if (!hitARock && player.y > 0) {

      player.y = player.y - 1;

    }

  }



  if (arduboy.pressed(DOWN_BUTTON)) {



    Rect playerRect = { player.x, player.y + 1, playerWidth, playerHeight };



    bool hitARock = isCollidingWithAnyRock(playerRect);



    if (!hitARock && player.y + playerHeight < HEIGHT  ) {

      player.y = player.y + 1;

    }

  }





  //For each column on the screen

  for ( int backgroundx = 0; backgroundx < arduboy.width(); backgroundx = backgroundx + 8 ) {

    //For each row in the column

    for ( int backgroundy = 0; backgroundy < arduboy.height(); backgroundy = backgroundy + 8 ) {

      //Draw a background tile

      arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );

    }

  }



  //arduboy.fillRect(player.x, player.y, playerWidth, playerHeight, BLACK);
  arduboy.drawBitmap(player.x, player.y, playerbitmap, playerWidth, playerHeight, WHITE);



  for ( int i = 0; i < 3; ++i) {
    //arduboy.fillRect(rockLocation[i].x, rockLocation[i].y, rockWidth, rockHeight, BLACK);
    arduboy.drawBitmap(rockLocation[i].x, rockLocation[i].y, rock, rockWidth, rockHeight, WHITE);
  }

  for ( int i = 0; i < 3; ++i) {
    //arduboy.fillRect(flowerLocation[i].x, flowerLocation[i].y, flowerWidth, flowerHeight, BLACK);
    arduboy.drawBitmap(flowerLocation[i].x, flowerLocation[i].y, flower, flowerWidth, flowerHeight, WHITE);
  }

  arduboy.display();

}

How many types of object are you planning to have?
Are all the objects going to be the same size?

If the answer to that is ‘lots’ and ‘yes’, then you’d probably be better off introducing an Object class and using something like this:

#include <Arduboy2.h>

const unsigned char background[] PROGMEM =
{
  0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,
};

const unsigned char playerbitmap[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,
};

const unsigned char rock[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00,
};

const unsigned char flower[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00,
};

enum class ObjectType : uint8_t
{
    None,
    Player,
    Rock,
    Flower,
};

class Object
{   
private:
    ObjectType type;
    
public:
    int16_t x;
    int16_t y;
    
public:
    Object() = default; 
    Object(ObjectType type, int16_t x, int16_t y)
        : type(type), x(x), y(y)
    {
    }
    
    ObjectType getType() const
    {
        return this->type;
    }   
};

Arduboy2 arduboy;

const int playerWidth = 16;
const int playerHeight = 16;

const int objectWidth = 16;
const int objectHeight = 16;

Object objects[7];
Object & player = objects[0];

void spawnPlayer()
{
  player = Object(ObjectType::Player, 50, 20);
}

Object spawnObject(ObjectType type)
{
  int16_t x = random(arduboy.width() - objectWidth);
  int16_t y = random(arduboy.height() - objectHeight);
  return Object(type, x, y);
}

bool checkObjectCollisions(size_t index)
{
  // Only check collisions against existing objects
  Rect objectRect = { objects[index].x, objects[index].y, objectWidth, objectHeight };
  for (size_t i = 0; i < index; ++i)
  {
    Rect otherObjectRect = { objects[i].x, objects[i].y, objectWidth, objectHeight };
    if (arduboy.collide(objectRect, otherObjectRect))
    {
      return true;
    }
  }
  return false;
}

void spawnObjects()
{
  // Spawn Rocks
  for (size_t i = 1; i < 7; ++i)
  {
    ObjectType type;
    if(i >= 1 && i <= 3)
    {
        type = ObjectType::Rock;
    }
    else if(i >= 4 && i <= 6)
    {
        type = ObjectType::Flower;
    }
    
    bool colliding = true;
    while (colliding)
    {
      objects[i] = spawnObject(type);
      colliding = checkObjectCollisions(i);
    }
  }
}

bool checkPlayerCollisions(size_t index)
{
  Rect objectRect = { objects[index].x, objects[index].y, objectWidth, objectHeight };
  Rect playerRect = { player.x, player.y, playerWidth, playerHeight };

  if (arduboy.collide(objectRect, playerRect))
  {
    return true;
  }
  return false;
}

bool isCollidingWithAnyObject(Rect rect)
{
  for (size_t i = 1; i < 7; ++i)
  {
    Rect objectRect = { objects[i].x, objects[i].y, objectWidth, objectHeight };
    if (arduboy.collide(rect, objectRect))
    {
      return true;
    }
  }
  return false;
}

void setup()
{
  arduboy.begin();
  arduboy.clear();
  arduboy.initRandomSeed();
  spawnPlayer();
  spawnObjects();
}

void loop()
{
  arduboy.clear();

  if (arduboy.pressed(LEFT_BUTTON))
  {
    Rect playerRect = { player.x - 1, player.y, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);

    if (!hitAnObject && player.x > 0) {
      player.x = player.x - 1;
    }
  }

  if (arduboy.pressed(RIGHT_BUTTON))
  {
    Rect playerRect = { player.x + 1, player.y, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);

    if (!hitAnObject && player.x + playerWidth < WIDTH ) {
      player.x = player.x + 1;
    }
  }

  if (arduboy.pressed(UP_BUTTON))
  {  
    Rect playerRect = { player.x, player.y - 1, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);
    
    if (!hitAnObject && player.y > 0) {
      player.y = player.y - 1;
    }
  }

  if (arduboy.pressed(DOWN_BUTTON))
  {
    Rect playerRect = { player.x, player.y + 1, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);

    if (!hitAnObject && player.y + playerHeight < HEIGHT  ) {
      player.y = player.y + 1;
    }
  }

  //For each column on the screen
  for ( int backgroundx = 0; backgroundx < arduboy.width(); backgroundx = backgroundx + 8 ) {
    //For each row in the column
    for ( int backgroundy = 0; backgroundy < arduboy.height(); backgroundy = backgroundy + 8 ) {
      //Draw a background tile
      arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );
    }
  }

  for (size_t i = 0; i < 7; ++i)
  {
    if(objects[i].getType() == ObjectType::Player)
    {   
      arduboy.drawBitmap(objects[i].x, objects[i].y, playerbitmap, objectWidth, objectHeight);
    }
    else if(objects[i].getType() == ObjectType::Rock)
    {
        arduboy.drawBitmap(objects[i].x, objects[i].y, rock, objectWidth, objectHeight);
    }
    else if(objects[i].getType() == ObjectType::Flower)
    {
        arduboy.drawBitmap(objects[i].x, objects[i].y, flower, objectWidth, objectHeight);
    }
  }

  arduboy.display();
}
1 Like

I have two questions:

  • Do you know object oriented programmation Tutorial or lessons specially for arduino on the web?

  • Nothing to do with programming : is arduboy English? American?

I don’t know of any that are specifically for Arduino, but I do know of some tutorials.
There’s a good C++ OOP series here:

http://www.learncpp.com/cpp-tutorial/81-welcome-to-object-oriented-programming/

Though it might require reading some of the earlier lessons:

http://www.learncpp.com/

It’s designed by an American, its headquarters are in Oregan (America), but it’s made in China.

To finish this little program, that will be my last request. Could you get that when the player hits a flower, this flower disappear. Obviously the rocks will still block the player.

#include <Arduboy2.h>

const unsigned char background[] PROGMEM =
{
  0x84, 0x20, 0x9, 0x00, 0x24, 0x00, 0x10, 0x80,
};

const unsigned char playerbitmap[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x38, 0xf, 0x7, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00,
};

const unsigned char rock[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x18, 0x00, 0x00,
};

const unsigned char flower[] PROGMEM =
{
  0x00, 0x00, 0x00, 0x10, 0xfe, 0xfe, 0xff, 0xcf, 0xcf, 0xfe, 0xfe, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc, 0x1c, 0x18, 0xff, 0x1d, 0x1e, 0xe, 0x6, 0x00, 0x00, 0x00, 0x00,
};

enum class ObjectType : uint8_t
{
    None,
    Player,
    Rock,
    Flower,
};

class Object
{   
private:
    ObjectType type;
    
public:
    int16_t x;
    int16_t y;
    
public:
    Object(void) = default; 
    Object(ObjectType type, int16_t x, int16_t y)
        : type(type), x(x), y(y)
    {
    }
    
    ObjectType getType(void) const
    {
        return this->type;
    }   
};

Arduboy2 arduboy;

const int playerWidth = 16;
const int playerHeight = 16;

const int objectWidth = 16;
const int objectHeight = 16;

Object objects[7];
Object & player = objects[0];

void spawnPlayer()
{
  player = Object(ObjectType::Player, 50, 20);
}

Object spawnObject(ObjectType type)
{
  int16_t x = random(arduboy.width() - objectWidth);
  int16_t y = random(arduboy.height() - objectHeight);
  return Object(type, x, y);
}

bool checkObjectCollisions(size_t index)
{
  // Only check collisions against existing objects
  Rect objectRect = { objects[index].x, objects[index].y, objectWidth, objectHeight };
  for (size_t i = 0; i < index; ++i)
  {
    Rect otherObjectRect = { objects[i].x, objects[i].y, objectWidth, objectHeight };
    if (arduboy.collide(objectRect, otherObjectRect))
    {
      return true;
    }
  }
  return false;
}

void spawnObjects()
{
  // Spawn Rocks
  for (size_t i = 1; i < 7; ++i)
  {
    ObjectType type;
    if(i >= 1 && i <= 3)
    {
        type = ObjectType::Rock;
    }
    else if(i >= 4 && i <= 6)
    {
        type = ObjectType::Flower;
    }
    
    bool colliding = true;
    while (colliding)
    {
      objects[i] = spawnObject(type);
      colliding = checkObjectCollisions(i);
    }
  }
}

bool checkPlayerCollisions(size_t index)
{
  Rect objectRect = { objects[index].x, objects[index].y, objectWidth, objectHeight };
  Rect playerRect = { player.x, player.y, playerWidth, playerHeight };

  if (arduboy.collide(objectRect, playerRect))
  {
    return true;
  }
  return false;
}

bool isCollidingWithAnyObject(Rect rect)
{
  for (size_t i = 1; i < 7; ++i)
  {
    Rect objectRect = { objects[i].x, objects[i].y, objectWidth, objectHeight };
    if (arduboy.collide(rect, objectRect))
    {
      return true;
    }
  }
  return false;
}

void setup()
{
  arduboy.begin();
  arduboy.clear();
  arduboy.initRandomSeed();
  spawnPlayer();
  spawnObjects();
}

void loop()
{
  arduboy.clear();

  if (arduboy.pressed(LEFT_BUTTON))
  {
    Rect playerRect = { player.x - 1, player.y, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);

    if (!hitAnObject && player.x > 0) {
      player.x = player.x - 1;
    }
  }

  if (arduboy.pressed(RIGHT_BUTTON))
  {
    Rect playerRect = { player.x + 1, player.y, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);

    if (!hitAnObject && player.x + playerWidth < WIDTH ) {
      player.x = player.x + 1;
    }
  }

  if (arduboy.pressed(UP_BUTTON))
  {  
    Rect playerRect = { player.x, player.y - 1, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);
    
    if (!hitAnObject && player.y > 0) {
      player.y = player.y - 1;
    }
  }

  if (arduboy.pressed(DOWN_BUTTON))
  {
    Rect playerRect = { player.x, player.y + 1, playerWidth, playerHeight };

    bool hitAnObject = isCollidingWithAnyObject(playerRect);

    if (!hitAnObject && player.y + playerHeight < HEIGHT  ) {
      player.y = player.y + 1;
    }
  }

  //For each column on the screen
  for ( int backgroundx = 0; backgroundx < arduboy.width(); backgroundx = backgroundx + 8 ) {
    //For each row in the column
    for ( int backgroundy = 0; backgroundy < arduboy.height(); backgroundy = backgroundy + 8 ) {
      //Draw a background tile
      arduboy.drawBitmap( backgroundx, backgroundy, background, 8, 8, WHITE );
    }
  }

  for (size_t i = 0; i < 7; ++i)
  {
    if(objects[i].getType() == ObjectType::Player)
    {   
      arduboy.drawBitmap(objects[i].x, objects[i].y, playerbitmap, objectWidth, objectHeight);
    }
    else if(objects[i].getType() == ObjectType::Rock)
    {
        arduboy.drawBitmap(objects[i].x, objects[i].y, rock, objectWidth, objectHeight);
    }
    else if(objects[i].getType() == ObjectType::Flower)
    {
        arduboy.drawBitmap(objects[i].x, objects[i].y, flower, objectWidth, objectHeight);
    }
  }

  arduboy.display();
}