Day53: Isn't bounding box of the apron centered at the bottom of the screen instead of the center?

Hello,

In this episode we make a function to check which entities are going to be in high/dormant and some functions to move them around these tables when they enter a region around the screen where the player is.

This is how the bounding box where the entities are supposed to be in high is calculated

rectangle2 CameraBounds = RectCenterDim(
      v2{0, 0},
      TileMap->TileSideInMeters * v2{(real32)TileSpanX, (real32)TileSpanY});

But should it not be like this instead where we actually center the bounding box to the place where the camera is getting moved to?

rectangle2 CameraBounds = RectCenterDim(
      TileMap->TileSideInMeters * v2{(real32)NewCameraP.AbsTileX, (real32)NewCameraP.AbsTileY},
      TileMap->TileSideInMeters * v2{(real32)TileSpanX, (real32)TileSpanY});

I don't know if this is explained in later episodes. Am I wrong?

It's been a while since those episodes and I didn't watch the whole episode again, but at this timestamp https://hero.handmade.network/episode/code/day053/#1598 Casey says that the coordinates are relative to the camera position, so (0,0) is the center of the screen (where the camera is).

Hmm maybe I'm not understanding this correctly.

Or maybe I have just written this wrong (as these snippets are not from the handmade_hero source. I wrote it by following the tutorials).

But the setCamera function takes in the new camera position in the tilemap coordiantes:

internal void
SetCamera(game_state *GameState, tile_map_position NewCameraP) {
  
  tile_map *TileMap = GameState->World->TileMap;
  tile_map_difference dCameraP = Subtract(TileMap, &NewCameraP, &GameState->CameraP);
  GameState->CameraP = NewCameraP;

  uint32 TileSpanX = 17 * 3;
  uint32 TileSpanY = 9 * 3;
  rectangle2 CameraBounds = RectCenterDim(
      // TileMap->TileSideInMeters * v2{(real32)NewCameraP.AbsTileX, (real32)NewCameraP.AbsTileY},
      v2{0, 0},
      TileMap->TileSideInMeters * v2{(real32)TileSpanX, (real32)TileSpanY});

  v2 EntityOffsetForFrame = -dCameraP.dXY;
  OffsetAndCheckFrequencyByArea(GameState, EntityOffsetForFrame, CameraBounds);

And we set the camera position when the game starts like this

    tile_map_position NewCameraP = {};
    NewCameraP.AbsTileX = 17/2;
    NewCameraP.AbsTileY = 9/2;
    NewCameraP.AbsTileZ = 0;
    SetCamera(GameState, NewCameraP);

    Memory->IsInitialized = true;

So, it seems to me that definitely the coordinate axes are centered at the bottom of the screen and there are 17/9 tiles in all. Then we are placing the camera at the center of this.

This is also clear if you change the initialization call of the hero which puts the hero at bottom left for 0, 0.

And hence, I think this is an error. Now the tilespan is so big that making this change doesn't really make any difference. So, even if you do calculate the bounds with the center of the rectangle2 at the bottomleft, it works fine.

I will go through the video again though and see if I can make sense of this.


Edited by Gaurav Gautam on
Replying to mrmixer (#26300)

The high entity positions are relative to the camera. To change an entity to high entity residence, we call ChangeEntityResidence and that subtracts the camera position from the dormant entity position to get the relative position. There is a comment "Map the entity into camera space". Note that the code I checked is the code of day 53, so it's the code at the end of the episode.

In handmade.cpp on line 271.

internal void
ChangeEntityResidence(game_state *GameState, uint32 EntityIndex, entity_residence Residence)
{
    // TODO(casey): Implement this!
    if(Residence == EntityResidence_High)
    {
        if(GameState->EntityResidence[EntityIndex] != EntityResidence_High)
        {
            high_entity *EntityHigh = &GameState->HighEntities[EntityIndex];
            dormant_entity *EntityDormant = &GameState->DormantEntities[EntityIndex];

            // NOTE(casey): Map the entity into camera space
            tile_map_difference Diff = Subtract(GameState->World->TileMap,
                                                &EntityDormant->P, &GameState->CameraP);
            EntityHigh->P = Diff.dXY;
            EntityHigh->dP = V2(0, 0);
            EntityHigh->AbsTileZ = EntityDormant->P.AbsTileZ;
            EntityHigh->FacingDirection = 0;
        }
    }

    GameState->EntityResidence[EntityIndex] = Residence;
}

The SetCamera function (handmade.cpp line 546), after removing entities from the high set, checks for dormant entities using absolute coordinates (not the relatives coordinates) to make dormant entities high if they are in bounds:

// [...]
    uint32 MinTileX = NewCameraP.AbsTileX - TileSpanX/2;
    uint32 MaxTileX = NewCameraP.AbsTileX + TileSpanX/2;
    uint32 MinTileY = NewCameraP.AbsTileY - TileSpanY/2;
    uint32 MaxTileY = NewCameraP.AbsTileY + TileSpanY/2;
    for(uint32 EntityIndex = 1;
        EntityIndex < ArrayCount(GameState->DormantEntities);
        ++EntityIndex)
    {
        if(GameState->EntityResidence[EntityIndex] == EntityResidence_Dormant)
        {
            dormant_entity *Dormant = GameState->DormantEntities + EntityIndex;

            if((Dormant->P.AbsTileZ == NewCameraP.AbsTileZ) &&
               (Dormant->P.AbsTileX >= MinTileX) &&
               (Dormant->P.AbsTileX <= MaxTileX) &&
               (Dormant->P.AbsTileY <= MinTileY) &&
               (Dormant->P.AbsTileY >= MaxTileY))
           
            {
                ChangeEntityResidence(GameState, EntityIndex, EntityResidence_High);
            }
        }
    }

Ah I see, I see. Thankyou for explaining!


Replying to mrmixer (#26308)