diff --git a/handmade.c b/handmade.c index f0faca4..dcf1c73 100644 --- a/handmade.c +++ b/handmade.c @@ -57,6 +57,12 @@ static S32 RoundF32toS32(F32 Real32) return Result; } +static S32 FloorF32toS32(F32 Real32) +{ + S32 Result = (S32)floorf(Real32); + return Result; +} + static void DrawRectangle(game_offscreen_buffer *Buffer, F32 RealMinX, F32 RealMinY, F32 RealMaxX, F32 RealMaxY, @@ -100,28 +106,6 @@ static void DrawRectangle(game_offscreen_buffer *Buffer, } } -static void RenderRectangle(game_offscreen_buffer *Buffer, S32 MouseX, - S32 MouseY) -{ - U8 *Row; - U32 *Pixel; - S32 X, Y; - - for(Y = MouseY; Y < MouseY+10; Y++) { - if(Y >= Buffer->Height) - break; - - Row = (U8 *)Buffer->Memory + (Buffer->Pitch * Y); - for(X = MouseX; X < MouseX+10; X++) { - if(X >= Buffer->Width) - break; - - Pixel = (U32 *)Row + X; - *Pixel = 0xFFFFFF; - } - } -} - static tile_map *GetTileMap(world *World, S32 TileMapX, S32 TileMapY) { tile_map *TileMap = NULL; @@ -136,57 +120,87 @@ static tile_map *GetTileMap(world *World, S32 TileMapX, S32 TileMapY) return TileMap; } -static U32 GetTileValueUnchecked(tile_map *TileMap, S32 TileX, S32 TileY) +static U32 GetTileValueUnchecked(world *World, tile_map *TileMap, S32 TileX, S32 TileY) { - U32 TileMapValue = TileMap->Tiles[TileY*TileMap->CountX + TileX]; + U32 TileMapValue; + + ASSERT(TileMap); + ASSERT((TileX >= 0) && (TileX < World->CountX) && + (TileY >= 0) && (TileY < World->CountY)); + + TileMapValue = TileMap->Tiles[TileY*World->CountX + TileX]; return TileMapValue; } -static B32 IsTileMapPointEmpty(tile_map *TileMap, F32 TestX, F32 TestY) +static B32 IsTileMapPointEmpty(world *World, tile_map *TileMap, + S32 TestTileX, S32 TestTileY) { B32 Empty = FALSE; - S32 PlayerTileX = - (S32)((TestX - TileMap->UpperLeftX) / TileMap->TileWidth); - S32 PlayerTileY = - (S32)((TestY - TileMap->UpperLeftY) / TileMap->TileHeight); - - if((PlayerTileX >= 0) && (PlayerTileX < TileMap->CountX) && - (PlayerTileY >= 0) && (PlayerTileY < TileMap->CountY)) - { - U32 TileMapValue = - GetTileValueUnchecked(TileMap, PlayerTileX, PlayerTileY); - Empty = (TileMapValue == 0); + if(TileMap) { + if((TestTileX >= 0) && (TestTileX < World->CountX) && + (TestTileY >= 0) && (TestTileY < World->CountY)) + { + U32 TileMapValue = + GetTileValueUnchecked(World, TileMap, TestTileX, TestTileY); + Empty = (TileMapValue == 0); + } } return Empty; } -static B32 IsWorldPointEmpty(world *World, - S32 TileMapX, S32 TileMapY, - F32 TestX, F32 TestY) +static cannonical_position GetCannonicalPosition(world *World, + raw_position Pos) +{ + cannonical_position Result; + F32 X, Y; + + Result.TileMapX = Pos.TileMapX; + Result.TileMapY = Pos.TileMapY; + + X = Pos.X - World->UpperLeftX; + Y = Pos.Y - World->UpperLeftY; + Result.TileX = FloorF32toS32(X / World->TileWidth); + Result.TileY = FloorF32toS32(Y / World->TileHeight); + + Result.X = X - Result.TileX*World->TileWidth; + Result.Y = Y - Result.TileY*World->TileHeight; + + ASSERT(Result.X >= 0); + ASSERT(Result.Y >= 0); + ASSERT(Result.X < World->TileWidth); + ASSERT(Result.Y < World->TileHeight); + + if(Result.TileX < 0) { + Result.TileX = World->CountX + Result.TileX; + Result.TileMapX--; + } + if(Result.TileY < 0) { + Result.TileY = World->CountY + Result.TileY; + Result.TileMapY--; + } + if(Result.TileX >= World->CountX) { + Result.TileX = Result.TileX - World->CountX; + Result.TileMapX++; + } + if(Result.TileY >= World->CountY) { + Result.TileY = Result.TileY - World->CountY; + Result.TileMapY++; + } + + return Result; +} + +static B32 IsWorldPointEmpty(world *World, raw_position TestPos) { B32 Empty = FALSE; - tile_map *TileMap = GetTileMap(World, TileMapX, TileMapY); + tile_map *TileMap; - S32 PlayerTileX, PlayerTileY; - - TileMap = GetTileMap(World, TileMapX, TileMapY); - if(TileMap) { - S32 PlayerTileX = - (S32)((TestX - TileMap->UpperLeftX) / TileMap->TileWidth); - S32 PlayerTileY = - (S32)((TestY - TileMap->UpperLeftY) / TileMap->TileHeight); - - if((PlayerTileX >= 0) && (PlayerTileX < TileMap->CountX) && - (PlayerTileY >= 0) && (PlayerTileY < TileMap->CountY)) - { - U32 TileMapValue = - GetTileValueUnchecked(TileMap, PlayerTileX, PlayerTileY); - Empty = (TileMapValue == 0); - } - } + cannonical_position CanPos = GetCannonicalPosition(World, TestPos); + TileMap = GetTileMap(World, CanPos.TileMapX, CanPos.TileMapY); + Empty = IsTileMapPointEmpty(World, TileMap, CanPos.TileX, CanPos.TileY); return Empty; } @@ -225,7 +239,7 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, }; U32 Tiles10[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { - {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, @@ -259,33 +273,24 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, ARRAY_SIZE(Input->Controllers[0].u.Buttons)); ASSERT(sizeof(game_state) <= Memory->PermanentStorageSize); - memset(&World, 0, sizeof(World)); - - TileMaps[0][0].CountX = TILEMAP_COUNT_X; - TileMaps[0][0].CountY = TILEMAP_COUNT_Y; - - TileMaps[0][0].UpperLeftX = 0.0f; - TileMaps[0][0].UpperLeftY = 0.0f; - TileMaps[0][0].TileWidth = 57.0f; - TileMaps[0][0].TileHeight = 57.0f; - TileMaps[0][0].Tiles = (U32 *)Tiles00; - - TileMaps[0][1] = TileMaps[0][0]; - TileMaps[0][1].Tiles = (U32 *)Tiles01; - - TileMaps[1][0] = TileMaps[0][0]; - TileMaps[1][0].Tiles = (U32 *)Tiles10; - - TileMaps[1][1] = TileMaps[0][0]; + TileMaps[0][1].Tiles = (U32 *)Tiles10; + TileMaps[1][0].Tiles = (U32 *)Tiles01; TileMaps[1][1].Tiles = (U32 *)Tiles11; - TileMap = &TileMaps[0][0]; + memset(&World, 0, sizeof(World)); + World.TileMapCountX = 2; + World.TileMapCountY = 2; + World.CountX = TILEMAP_COUNT_X; + World.CountY = TILEMAP_COUNT_Y; + World.UpperLeftX = 0.0f; + World.UpperLeftY = 0.0f; + World.TileWidth = 57.0f; + World.TileHeight = 57.0f; + World.TileMaps = (tile_map *)TileMaps; - World.TileMaps = (tile_map *)TileMaps; - - PlayerWidth = 0.75f * TileMap->TileWidth; - PlayerHeight = TileMap->TileHeight; + PlayerWidth = 0.75f * World.TileWidth; + PlayerHeight = World.TileHeight; GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { @@ -295,6 +300,10 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, Memory->IsInitialized = TRUE; } + TileMap = GetTileMap(&World, GameState->PlayerTileMapX, + GameState->PlayerTileMapY); + ASSERT(TileMap); + for(ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) @@ -308,6 +317,8 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, F32 NewPlayerX, NewPlayerY; + raw_position PlayerPos, PlayerLeft, PlayerRight; + if(Controller->u.buttons.MoveUp.EndedDown) { dPlayerY = -1.0f; } @@ -321,22 +332,38 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, dPlayerX = 1.0f; } - dPlayerX *= 100.0f; - dPlayerY *= 100.0f; + dPlayerX *= 200.0f; + dPlayerY *= 200.0f; NewPlayerX = RoundF32toS32(GameState->PlayerX + Input->dtForFrame*dPlayerX); NewPlayerY = RoundF32toS32(GameState->PlayerY + Input->dtForFrame*dPlayerY); - if(IsTileMapPointEmpty(TileMap, NewPlayerX - 0.5f*PlayerWidth, - NewPlayerY) && - IsTileMapPointEmpty(TileMap, NewPlayerX + 0.5f*PlayerWidth, - NewPlayerY) && - IsTileMapPointEmpty(TileMap, NewPlayerX, NewPlayerY)) + PlayerPos.TileMapX = GameState->PlayerTileMapX; + PlayerPos.TileMapY = GameState->PlayerTileMapY; + PlayerPos.X = NewPlayerX; + PlayerPos.Y = NewPlayerY; + + PlayerLeft = PlayerPos; + PlayerLeft.X -= 0.5f*PlayerWidth; + + PlayerRight = PlayerPos; + PlayerRight.X += 0.5f*PlayerWidth; + + if(IsWorldPointEmpty(&World, PlayerPos) && + IsWorldPointEmpty(&World, PlayerLeft) && + IsWorldPointEmpty(&World, PlayerRight)) { - GameState->PlayerX = NewPlayerX; - GameState->PlayerY = NewPlayerY; + cannonical_position CanPos = + GetCannonicalPosition(&World, PlayerPos); + + GameState->PlayerTileMapX = CanPos.TileMapX; + GameState->PlayerTileMapY = CanPos.TileMapY; + GameState->PlayerX = World.UpperLeftX + + World.TileWidth*CanPos.TileX + CanPos.X; + GameState->PlayerY = World.UpperLeftY + + World.TileHeight*CanPos.TileY + CanPos.Y; } } } @@ -348,15 +375,15 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, for(Row = 0; Row < TILEMAP_COUNT_Y; Row++) { for(Column = 0; Column < TILEMAP_COUNT_X; Column++) { F32 MinX, MinY, MaxX, MaxY; - U32 TileID = GetTileValueUnchecked(TileMap, Column, Row); + U32 TileID = GetTileValueUnchecked(&World, TileMap, Column, Row); F32 Gray = 0.5f; if(TileID) { Gray = 1.0f; } - MinX = TileMap->UpperLeftX + (F32)(Column) * TileMap->TileWidth; - MinY = TileMap->UpperLeftY + (F32)(Row) * TileMap->TileHeight; - MaxX = MinX + TileMap->TileWidth; - MaxY = MinY + TileMap->TileHeight; + MinX = World.UpperLeftX + (F32)(Column) * World.TileWidth; + MinY = World.UpperLeftY + (F32)(Row) * World.TileHeight; + MaxX = MinX + World.TileWidth; + MaxY = MinY + World.TileHeight; DrawRectangle(Buffer, MinX, MinY, MaxX, MaxY, Gray, Gray, Gray); } } @@ -372,8 +399,8 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, PlayerR, PlayerG, PlayerB); DrawRectangle(Buffer, - (F32)(Input->MouseX), (F32)(Input->MouseY), - (F32)(Input->MouseX) + 10.0f, (F32)(Input->MouseY) + 10.0f, + (F32)(Input->MouseX) - 15.0f, (F32)(Input->MouseY) - 15.0f, + (F32)(Input->MouseX) + 5.0f, (F32)(Input->MouseY) + 5.0f, 1.0f, 0.5f, 0.0f); GameOutputSound(GameState, SoundBuffer, 400); diff --git a/handmade.h b/handmade.h index 8e0175f..93fe387 100644 --- a/handmade.h +++ b/handmade.h @@ -136,7 +136,32 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, * */ +typedef struct cannonical_position { + S32 TileMapX; + S32 TileMapY; + + S32 TileX; + S32 TileY; + + /* NOTE: Tile-relative X and Y. */ + F32 X; + F32 Y; +} cannonical_position; + +typedef struct raw_position { + S32 TileMapX; + S32 TileMapY; + + /* NOTE: Tile-map relative X and Y. */ + F32 X; + F32 Y; +} raw_position; + typedef struct tile_map { + U32 *Tiles; +} tile_map; + +typedef struct world { S32 CountX; S32 CountY; @@ -145,10 +170,6 @@ typedef struct tile_map { F32 TileWidth; F32 TileHeight; - U32 *Tiles; -} tile_map; - -typedef struct world { S32 TileMapCountX; S32 TileMapCountY; @@ -156,6 +177,9 @@ typedef struct world { } world; typedef struct game_state { + S32 PlayerTileMapX; + S32 PlayerTileMapY; + F32 PlayerX; F32 PlayerY; } game_state;