Learn to determine the side of object for movey block game

I have an idea for a puzzle game based on the Gameboy classic Quirk. The plot of the game is pretty thin but involves a tomato dude that has to solve movey block puzzles with blocks that can move and even swivel to open a path to the level exit.

to do this I will have to draw a tilemap and then super impose the game piece on to the screen much like the way you would add the player. Then I need to write a simple collision function that will allow the player to collide with the super imposed gamepiece bitmap. I do that like this…

struct Rect{
	int16_t x;
	int16_t y;
	uint8_t width;
	uint8_t height;
};
void moveblockleft(){

Rect rectA {x,y,16,16};
Rect rectB {player_x, player_y,16,16};

if(tft.collideRectRect( rectA.x, rectA.y, rectA.width, rectA.height, rectB.x, rectB.y, rectB.width, rectB.height))
{

rectangle structure works with the first two coordinates being where the you placed the block and its size. Then the collision part looks for when rect a which is the game piece and rectb which is the player to collide. From here I could simply tell the block to move in the appropriate direction to open the path but what fun and kind of challenge would that be?

I’m gonna start simple. we have one block on the screen in the tilemap room. And I just want it to move left if I touch the right side of the block.

how do I tell the game that my block game piece has a right side? Or should I give it all four sides?

1 Like

How about you determine the direction it moves based on the direction the player is moving? If this is tile based, then it can simply be that if you are trying to move left and hit a block, you must have hit the right side of the block. This should be enough for more complex block behavior as well.

Yes, i think that wuuff method is the easiest way to do it.
If collosion then dir_bloc = dir_player

If you don’t mind I need a lil bit more explanation for the dir_bloc part… but I was able to do this much with what you gave me.

int block_x = 122;     //block position on screen x
int block_y = 188;     //block position on screen y

void moveblockleft(){

Rect rectA {block_x,block_y,16,16};
Rect rectB {player_x, player_y,16,16};

gb.display.drawBitmap(block_x, block_y,16,16,4,stonewall2, anycolor);

if(tft.collideRectRect( rectA.x, rectA.y, rectA.width, rectA.height, rectB.x, rectB.y, rectB.width, rectB.height))
{
        )&& player_direction = 7){ block_x -= 16;} 

}
};

ive added 4 more player directions, D5 playerrearwalka which is the bitmap that’s programmed to cycle when the up button is pushed and player moving up and did the same with left, right and down. So it only collides with that particular bitmap. Then ends with moving the block 16pix left.

I just don’t understand the missing part.

If player go left and collide block, you move the block to left of “one step” (block_x -= 16)
if it’s right block_x += 16, top block_y -= 16 and bottom block_y += 16
It should be enough to manage the block move (but you should not move diectly as you should first verify that the next position dont collide with something else wich block the move of the block and the player). So it’s could be better to stock old position first to restore it if the block can’t move

If I do the puzzles right, when the block moves it should move to a position where it cant move again.

simply removing the )&& and then adding an if ( in front of player seems to have done the trick though I haven’t tested on screen yet but it compiles.

I would still like to be able to give my block a structure with top left bootom right and be able to use those to determine wether the player collides.

Say the user is searching for the move trigger on the block and its only gonna move when the the players leftwalk bitmaps touches it moves and the player is on the right side. if the player checks the same block from the bottom and accidentally hits left and up at the same time. that will cause the player sprite to move diagonal which also brings up the sprite bitmap for walking left.

it would give a false positive and move the block even though the character is not right of the block. so I would like to have some kind of variable that definitely tells the player sprite its hitting the right side of the block.

something like

struct Point
{
  int16_t x; /**< The X coordinate of the point */
  int16_t y; /**< The Y coordinate of the point */
};

if(point(x,y,) && (player_direction = 7) { block_x -= 16;} 

To be clear, are you planning for this game to be grid based, where each tile fits in a grid space and the player moves one tile at a time, or instead have the player move by smaller amounts and not be constrained to a grid?

ok the player moves in increments of 5 pixels and is not constrained by the grid.

the puzzlepiece bitmap and the tilemap are constrained by the grid.

I was thinking I could place recta one pixel right and one pixel up. That moves the actual collision square up one line of pixels so the move can only be triggered from the right but just to insure that there isn’t a false positive I want to add a button trigger so two conditions have to be met.

i could also set the recta to one pixel right to avoid double firing if player is in exactly the place the block moved. so it will only move once period.

problem is ive tried this once before and never could get it compile much less work. i cant figure out how to do the and button press correctly.

void moveblockleft(){

Rect rectA {block_x,block_y,16,16};
Rect rectB {player_x, player_y,16,16};

tft.writeRectNBPP(block_x, block_y,16,16,4,blockp,palette);

if(tft.collideRectRect( rectA.x, rectA.y, rectA.width, rectA.height, rectB.x, rectB.y, rectB.width, rectB.height))
{
 if((player_direction = 7) && (ButtonRight.fallingEdge())) {block_x -= 16;} 

     }
 }

i cant seem to get the bracketing right. does that look right? Buttons work like this…

if (ButtonRight.fallingEdge()){
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulrightw,palette);
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulright,palette);
    player_direction = 4;
    player_x += 4;
  if(checkcolision())
  {
    player_x -= 4;}
  }
            if(player_x <= 16){
              player_x = 16;}

To be clear: I don’t know that much about game programming as I’m still learning. I only programmed microcontrollers and PC software so far. I’m new to the Arduino platform too, so i don’t know how much computing power it offers. I mean i know the specs but it all comes down to how good the compiler is etc.

But heres my idea:
You know the position of the block on the tilemap and you know the size of the block. You could check the collision not for only 1 but for 4 rectangles. These 4 rectangles are determined by the position and the size of the block. I made you an example “picture” :sweat_smile:
Rect collision

That’s why I said that I’m not sure about the computing power. I don’t know if this kind of collision testing slows down the system. If it does you could check for the block rectangle in general, so you know that this particular block was hit by the player. Then you could check again which side was hit by using 4 different rectangles.

This code is just an example to show what i mean, it’s not tested :sweat_smile:

if(tft.collideRectRect(block_x, block_y,16,16, player_x, player_y. 16, 16))
{
    if(tft.collideRectRect(block_x + 1, block_y, 14, 2, player_x, player_y, 16,16)  MoveBlockDown();

    if(tft.collideRectRect(block_x + 1, block_y+14, 14, 2, player_x, player_y, 16,16)  MoveBlockUp();

    if(tft.collideRectRect(block_x, block_y + 1, 2, 14, player_x, player_y, 16,16)  MoveBlockLeft();

    if(tft.collideRectRect(block_x + 14, block_y + 1, 2, 14, player_x, player_y, 16,16)  MoveBlockRight();
}

*€dit: I almost forgot it: I LOVE KWIRK :smiley: I still own the GameBoy cartridge :slight_smile: It was one of my first gameboy games and I played all the time when i was a child.

1 Like

As the step of movment of the player a the step of the block, you have manage when 2 lines of detection are hited too because the collision can be in a corner and or you want do the 2 conditions as it should do with your program as it is (and it’s can be logical) or to adopt specific action but you have to be sure of wich action you want.

I thought about that too. But does a player really want to move a block by hitting it’s corner? I think the player will try to move the block by hitting the middle of a side most of the time.

Otherwise you could use a bool variable moved = false and set it to true after one condition is met. This way you could prevent the block from moving again in a second direction.

You’re overcomplicating things. You can have a simple collision rectangle for the tiles and player if you just check the x and y coordinates separately for the player and check where the player will be before moving.

So, for example, if the player is holding up and left, you check if the player moving up would cause them to collide with a tile (only changing their y coordinate). Them you would check if moving left would cause them to hit a tile (only changing their x coordinate). If they hit a tile when moving up, they hit the bottom of the tile. If they hit a tile while moving left, they hit the right side. If they hit a tile while moving both up and left, they hit the corner. This can be implemented relatively simply without resorting to extra variables or collision rectangles.

You’re right wuuff, it’s the first answer gaven but Duhjoker want manage top left right and bottom side of the block too probably for a good reason even i don’t understand the use atm.
For me the more easy is to manage a matrix of possible emplacements in a grid.
If the player go left and that the emplacement is a case tagged as “free to move” (empty), you make the move else you don’t but then you tag the old position of the block as “free to move” (empty) in the grid and the new position as “occuped”.

Awesome guys!!! I’m learning and I think I might have it handled.

lol there is a reason for wanting to manage all four points to the block at once but… I really cant remember right now. but as I do remember I will explain.

//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
On my main game project, ive been having trouble with space. the problem was that I was I’m using tilemap to print out all my world maps which is supposed to save precious space but I was having to list a new bitmap for each exit and entrance. with a game that has 17 villages and a cave structure for each one plus the exits and entrances for the elements in the caves to change rooms.

that’s over 110 tiles just to take care of my over world stuff on top of my 100 some off regular world tiles. as you can imagine this doubles the amount of space needed.

I have been racking my brain for a couple weeks to solve the problem and it was in my face the whole time.

so lets solve it.

I call rooms like this…

      if(room == 1){
  tft.drawTilemap(cameraX, cameraY, worldtl, spritesheet, palette);}
 else if(room == 2){
  tft.drawTilemap(cameraX, cameraY, worldtc, spritesheet, palette);}
 else if(room == 3){
  tft.drawTilemap(cameraX, cameraY, worldtl, spritesheet, palette);}
 else if(room == 4){
  tft.drawTilemap(cameraX, cameraY, worldcl, spritesheet, palette);}

each room gets an integer that I can call to change for switching out the map like so…

////////// top center rock formation
 else if((tft.solid[i].spritecol == area1exit1s) && room == 1){room = 4; player_x = 122; player_y = 188; cameraX = -1056; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}     /////101
 else if((tft.solid[i].spritecol == area1exit2e) && room == 1){room = 2; player_x = 122; player_y = 188; cameraX = -0; cameraY = -1056; cameraXMin = -2080; cameraYMin = -2144;}     /////102
//////////////////////////////////////////////////////////////////////////////////////////// 
 else if((tft.solid[i].spritecol == area2exit1w) && room == 2){room = 1; player_x = 122; player_y = 188; cameraX = -2080; cameraY = -1056; cameraXMin = -2080; cameraYMin = -2144;}  /////103
 else if((tft.solid[i].spritecol == area2exit2s) && room == 2){room = 5; player_x = 122; player_y = 188; cameraX = -1056; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}     /////104
 

so I’m saying if player collides with this bit and has the conditional of also being in a room int do something. so what I wasn’t seeing was that I could make as many exit and entrance tiles that I could ever need for a room then use the conditional && room = 1;{} to use the same however may tiles as many times as needed with out going severely off budget.

110 now becomes around 35 taking up 2/3 less than it was.

I ran into a snag. The examples above only work if the puzzle piece is placed in a room that has no camera movement. I cant figure out how to add the piece in a larger room. So now if I place it in a room like so…

tft.drawTilemap(cameraX, cameraY, dungeon4, spritesheet, palette); tft.writeRectNBPP(block_x, block_y,32,32,4,blockp2,palette); detectside();}

with this

void detectside(){

int block_x = 288;
int block_y = 96;

if(tft.collideRectRect(block_x, block_y,16,16, player_x, player_y, 16, 16))
{
    if(tft.collideRectRect(block_x + 1, block_y, 14, 2, player_x, player_y, 16,16)){block_y -= 16;} 

    if(tft.collideRectRect(block_x + 1, block_y+14, 14, 2, player_x, player_y, 16,16)){block_y += 16;}  

    if(tft.collideRectRect(block_x, block_y + 1, 2, 14, player_x, player_y, 16,16)) {block_x -= 16;} 

    if(tft.collideRectRect(block_x + 14, block_y + 1, 2, 14, player_x, player_y, 16,16)) {block_x += 16;} 
}
}

it just puts the block on the screen at the given coordinates and not on screen where it needs to be. Any ideas?