|
|
@@ -2,14 +2,23 @@ |
|
|
|
|
|
|
|
#define PI32 3.141592653589f |
|
|
|
|
|
|
|
internal int32 roundReal32ToUInt32(real32 realNum) { |
|
|
|
inline int32 roundReal32ToUInt32(real32 realNum) { |
|
|
|
return (uint32)(realNum + 0.5f); |
|
|
|
} |
|
|
|
|
|
|
|
internal int32 roundReal32ToInt32(real32 realNum) { |
|
|
|
inline int32 roundReal32ToInt32(real32 realNum) { |
|
|
|
return (int32)(realNum + 0.5f); |
|
|
|
} |
|
|
|
|
|
|
|
#include "math.h" |
|
|
|
inline int32 floorReal32ToInt32(real32 realNum) { |
|
|
|
return (int32)floorf(realNum); |
|
|
|
} |
|
|
|
|
|
|
|
inline int32 truncateReal32ToInt32(real32 realNum) { |
|
|
|
return (int32)realNum; |
|
|
|
} |
|
|
|
|
|
|
|
internal void drawRectangle(GameOffscreenBuffer *buffer, real32 realMinX, real32 realMinY, real32 realMaxX, real32 realMaxY, real32 R, real32 G, real32 B) { |
|
|
|
int32 minX = roundReal32ToInt32(realMinX); |
|
|
|
int32 minY = roundReal32ToInt32(realMinY); |
|
|
@@ -57,6 +66,76 @@ internal void outputSound(GameSoundOutputBuffer *soundBuffer, GameState *state) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
inline uint32 getTileValueUnchecked(World *world, TileMap *tileMap, int32 testTileX, int32 testTileY) { |
|
|
|
Assert(tileMap); |
|
|
|
Assert( |
|
|
|
(testTileX >= 0) && (testTileX < world->tileCountX) && |
|
|
|
(testTileY >= 0) && (testTileY < world->tileCountY) |
|
|
|
); |
|
|
|
return tileMap->tiles[testTileY * world->tileCountX + testTileX]; |
|
|
|
} |
|
|
|
|
|
|
|
inline TileMap *getTileMap(World *world, int32 tileMapX, int32 tileMapY) { |
|
|
|
TileMap *tileMap = NULL; |
|
|
|
|
|
|
|
if ((tileMapX >= 0) && (tileMapX < world->tileMapCountX) && |
|
|
|
(tileMapY >= 0) && (tileMapY < world->tileMapCountY) |
|
|
|
) { |
|
|
|
tileMap = &world->tileMaps[tileMapY * world->tileMapCountX + tileMapX]; |
|
|
|
} |
|
|
|
|
|
|
|
return tileMap; |
|
|
|
} |
|
|
|
|
|
|
|
inline CanonicalPosition getCanonicalPosition(World* world, RawPosition pos) { |
|
|
|
CanonicalPosition result = {}; |
|
|
|
|
|
|
|
result.tileMapX = pos.tileMapX; |
|
|
|
result.tileMapY = pos.tileMapY; |
|
|
|
|
|
|
|
real32 x = pos.x - world->upperLeftX; |
|
|
|
real32 y = pos.y - world->upperLeftY; |
|
|
|
|
|
|
|
result.tileX = floorReal32ToInt32(x / world->tileWidth); |
|
|
|
result.tileY = floorReal32ToInt32(y / world->tileHeight); |
|
|
|
|
|
|
|
result.x = pos.x - result.tileX*world->tileWidth; |
|
|
|
result.y = pos.y - result.tileY*world->tileHeight; |
|
|
|
|
|
|
|
if (result.tileX < 0) { |
|
|
|
result.tileX += world->tileCountX; |
|
|
|
result.tileMapX -= 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (result.tileY < 0) { |
|
|
|
result.tileY += world->tileCountY; |
|
|
|
result.tileMapY -= 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (result.tileX >= world->tileCountX) { |
|
|
|
result.tileX -= world->tileCountX; |
|
|
|
result.tileMapX += 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (result.tileY >= world->tileCountY) { |
|
|
|
result.tileY -= world->tileCountY; |
|
|
|
result.tileMapY += 1; |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
internal bool32 isWorldPointEmpty(World *world, RawPosition testPos) { |
|
|
|
bool32 isEmpty = false; |
|
|
|
|
|
|
|
CanonicalPosition canPos = getCanonicalPosition(world, testPos); |
|
|
|
TileMap *tileMap = getTileMap(world, canPos.tileMapX, canPos.tileMapY); |
|
|
|
|
|
|
|
isEmpty = (getTileValueUnchecked(world, tileMap, canPos.tileX, canPos.tileY) == 0); |
|
|
|
|
|
|
|
return isEmpty; |
|
|
|
} |
|
|
|
|
|
|
|
extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { |
|
|
|
Assert(sizeof(GameState) <= memory->permanentStorageSize); |
|
|
|
|
|
|
@@ -64,10 +143,97 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { |
|
|
|
|
|
|
|
if (!memory->isInitialised) { |
|
|
|
memory->isInitialised = true; |
|
|
|
state->playerX = 20.0f; |
|
|
|
state->playerY = 20.0f; |
|
|
|
state->playerX = 150.0f; |
|
|
|
state->playerY = 150.0f; |
|
|
|
state->tileMapX = 0; |
|
|
|
state->tileMapY = 0; |
|
|
|
} |
|
|
|
|
|
|
|
const int TILEMAP_WIDTH = 16; |
|
|
|
const int TILEMAP_HEIGHT = 9; |
|
|
|
|
|
|
|
const int WORLD_WIDTH = 2; |
|
|
|
const int WORLD_HEIGHT = 2; |
|
|
|
|
|
|
|
uint32 tiles00[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { |
|
|
|
{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, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 1, 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, 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, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
}; |
|
|
|
|
|
|
|
uint32 tiles01[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
{1, 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, 1}, |
|
|
|
{1, 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, 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, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
}; |
|
|
|
|
|
|
|
uint32 tiles10[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
|
|
|
{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
}; |
|
|
|
|
|
|
|
uint32 tiles11[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
|
|
|
{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
}; |
|
|
|
|
|
|
|
World world = {}; |
|
|
|
world.tileCountX = TILEMAP_WIDTH; |
|
|
|
world.tileCountY = TILEMAP_HEIGHT; |
|
|
|
world.tileMapCountX = WORLD_WIDTH; |
|
|
|
world.tileMapCountY = WORLD_HEIGHT; |
|
|
|
world.upperLeftX = 0; |
|
|
|
world.upperLeftY = 0; |
|
|
|
world.tileWidth = 60; |
|
|
|
world.tileHeight = 60; |
|
|
|
|
|
|
|
TileMap maps[WORLD_HEIGHT][WORLD_WIDTH]; |
|
|
|
maps[0][0].tiles = (uint32*)tiles00; |
|
|
|
|
|
|
|
maps[1][0] = maps[0][0]; |
|
|
|
maps[1][0].tiles = (uint32*)tiles01; |
|
|
|
|
|
|
|
maps[0][1] = maps[0][0]; |
|
|
|
maps[0][1].tiles = (uint32*)tiles10; |
|
|
|
|
|
|
|
maps[1][1] = maps[0][0]; |
|
|
|
maps[1][1].tiles = (uint32*)tiles11; |
|
|
|
|
|
|
|
world.tileMaps = (TileMap*)maps; |
|
|
|
|
|
|
|
// player |
|
|
|
real32 playerR = 1.0f; |
|
|
|
real32 playerG = 1.0f; |
|
|
|
real32 playerB = 0.5f; |
|
|
|
real32 playerWidth = 50.0f; |
|
|
|
real32 playerHeight = 70.0f; |
|
|
|
|
|
|
|
for (int controllerIndex = 0; controllerIndex < ArrayCount(input->controllers); controllerIndex++) { |
|
|
|
GameControllerInput *controller = &input->controllers[controllerIndex]; |
|
|
|
|
|
|
@@ -75,67 +241,79 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { |
|
|
|
real32 dPlayerY = 0.0f; |
|
|
|
|
|
|
|
if (controller->stickUp.endedDown) { |
|
|
|
dPlayerY = -128.0f; |
|
|
|
dPlayerY = -1.0f; |
|
|
|
} |
|
|
|
if (controller->stickDown.endedDown) { |
|
|
|
dPlayerY = 128.0f; |
|
|
|
dPlayerY = 1.0f; |
|
|
|
} |
|
|
|
if (controller->stickLeft.endedDown) { |
|
|
|
dPlayerX = -128.0f; |
|
|
|
dPlayerX = -1.0f; |
|
|
|
} |
|
|
|
if (controller->stickRight.endedDown) { |
|
|
|
dPlayerX = 128.0f; |
|
|
|
dPlayerX = 1.0f; |
|
|
|
} |
|
|
|
|
|
|
|
state->playerX += dPlayerX * input->dtForFrame; |
|
|
|
state->playerY += dPlayerY * input->dtForFrame; |
|
|
|
} |
|
|
|
dPlayerX *= 96.0f; |
|
|
|
dPlayerY *= 96.0f; |
|
|
|
|
|
|
|
const int TILEMAP_WIDTH = 16; |
|
|
|
const int TILEMAP_HEIGHT = 9; |
|
|
|
real32 upperLeftX = 0; |
|
|
|
real32 upperLeftY = 0; |
|
|
|
real32 tileWidth = 60; |
|
|
|
real32 tileHeight = 60; |
|
|
|
real32 newPlayerX = state->playerX + dPlayerX * input->dtForFrame; |
|
|
|
real32 newPlayerY = state->playerY + dPlayerY * input->dtForFrame; |
|
|
|
|
|
|
|
uint32 tileMap[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, |
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, |
|
|
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, |
|
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
|
|
|
}; |
|
|
|
RawPosition playerPos = { |
|
|
|
state->tileMapX, |
|
|
|
state->tileMapY, |
|
|
|
newPlayerX, |
|
|
|
newPlayerY, |
|
|
|
}; |
|
|
|
|
|
|
|
RawPosition playerBottomLeft = playerPos; |
|
|
|
playerBottomLeft.x -= 0.5f * playerWidth; |
|
|
|
|
|
|
|
RawPosition playerTopLeft = playerPos; |
|
|
|
playerTopLeft.x -= 0.5f * playerWidth; |
|
|
|
playerTopLeft.y -= playerWidth; |
|
|
|
|
|
|
|
RawPosition playerBottomRight = playerPos; |
|
|
|
playerBottomRight.x += 0.5f * playerWidth; |
|
|
|
|
|
|
|
RawPosition playerTopRight = playerPos; |
|
|
|
playerTopRight.x += 0.5f * playerWidth; |
|
|
|
playerTopRight.y -= playerWidth; |
|
|
|
|
|
|
|
if ( |
|
|
|
isWorldPointEmpty(&world, playerTopLeft) && |
|
|
|
isWorldPointEmpty(&world, playerTopRight) && |
|
|
|
isWorldPointEmpty(&world, playerBottomLeft) && |
|
|
|
isWorldPointEmpty(&world, playerBottomRight) |
|
|
|
) { |
|
|
|
CanonicalPosition canPos = getCanonicalPosition(&world, playerPos); |
|
|
|
|
|
|
|
state->tileMapX = canPos.tileMapX; |
|
|
|
state->tileMapY = canPos.tileMapY; |
|
|
|
|
|
|
|
state->playerX = world.upperLeftX + world.tileWidth*canPos.tileX + canPos.x; |
|
|
|
state->playerY = world.upperLeftY + world.tileHeight*canPos.tileY + canPos.y; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// clearscreen |
|
|
|
drawRectangle(videoBuf, 0.0f, 0.0f, (real32)videoBuf->width, (real32)videoBuf->height, 1.0f, 0.0f, 1.0f); |
|
|
|
|
|
|
|
// tilemap |
|
|
|
for (int row = 0; row < TILEMAP_HEIGHT; row++) { |
|
|
|
for (int col = 0; col < TILEMAP_WIDTH; col++) { |
|
|
|
uint32 tileID = tileMap[row][col]; |
|
|
|
real32 fill = tileID == 1 ? 1.0f : 0.5f; |
|
|
|
real32 minX = upperLeftX + ((real32)col)*tileWidth; |
|
|
|
real32 minY = upperLeftY + ((real32)row)*tileHeight; |
|
|
|
real32 maxX = minX + tileWidth; |
|
|
|
real32 maxY = minY + tileHeight; |
|
|
|
TileMap *currMap = getTileMap(&world, state->tileMapX, state->tileMapY); |
|
|
|
for (int row = 0; row < world.tileCountY; row++) { |
|
|
|
for (int col = 0; col < world.tileCountX; col++) { |
|
|
|
real32 fill = getTileValueUnchecked(&world, currMap, col, row) == 1 ? 1.0f : 0.5f; |
|
|
|
real32 minX = world.upperLeftX + ((real32)col)*world.tileWidth; |
|
|
|
real32 minY = world.upperLeftY + ((real32)row)*world.tileHeight; |
|
|
|
real32 maxX = minX + world.tileWidth; |
|
|
|
real32 maxY = minY + world.tileHeight; |
|
|
|
drawRectangle(videoBuf, minX, minY, maxX, maxY, fill, fill, fill); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// player |
|
|
|
real32 playerR = 1.0f; |
|
|
|
real32 playerG = 0.5f; |
|
|
|
real32 playerB = 0.0f; |
|
|
|
real32 playerWidth = 25.0f; |
|
|
|
real32 playerHeight = 40.0f; |
|
|
|
real32 playerLeft = state->playerX - 0.5f * playerWidth; |
|
|
|
real32 playerTop = state->playerY - 0.5f * playerHeight; |
|
|
|
|
|
|
|
drawRectangle(videoBuf, playerLeft, playerTop, state->playerX + playerWidth, state->playerY + playerHeight, playerR, playerG, playerB); |
|
|
|
real32 playerTop = state->playerY - playerHeight; |
|
|
|
drawRectangle(videoBuf, playerLeft, playerTop, state->playerX + playerWidth*0.5f, state->playerY, playerR, playerG, playerB); |
|
|
|
} |
|
|
|
|
|
|
|
extern "C" GAME_GET_SOUND_SAMPLES(gameGetSoundSamples) { |
|
|
|