diff --git a/TODO b/TODO index 037ca3f..110a117 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +- Re-organize manager.c to match manager.h, add internals to .h and fix code style to match rest of code - Rotate (Partially Implemented/Buggy. Should try to understand Rotation Matrix better.) - Empty rows that are full should "break" - Shift rows down after row "breaks" diff --git a/src/app.c b/src/app.c index b994642..5a2e176 100644 --- a/src/app.c +++ b/src/app.c @@ -4,68 +4,65 @@ #include "manager.h" #include "renderer.h" #include "tetromino.h" +#include "app.h" #define TARGET_FPS 60 -void EmptyGameBoard(void) { - EmptyAllBlocks(); - - int numberOfUpdatedBlocks = 0; - struct TetrominoBlock** updatedBlocks = GetUpdatedBlocks(&numberOfUpdatedBlocks); +void a_run(void) { + _a_initialize(); + _a_loop(); + _a_cleanup(); } -void InitRaylib(void) { - InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Tetris Clone"); +void _a_initialize(void) { + _a_initialize_raylib(); + m_initialize(); + r_initialize(); + _a_gameboard_clear(); +} +void _a_initialize_raylib(void) { + InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Tetris Clone"); SetTargetFPS(TARGET_FPS); } -void Init(void) { - InitRaylib(); - InitManager(); - InitRenderer(); - EmptyGameBoard(); +void _a_gameboard_clear(void) { + m_blocks_set_empty(); + int number_blocks_updated = 0; + struct TetrominoBlock** blocks_updated = m_blocks_get_updated(&number_blocks_updated); + r_render_blocks(blocks_updated, number_blocks_updated); } -void ProcessInput(void) { +void _a_loop(void) { + int tick_rate = 0; // Guaranteed a better way to do this XD + while(!WindowShouldClose()) { + while(m_tetromino_can_spawn()) { + _a_input_process(); + if (tick_rate == 0) { + m_update(); + tick_rate = 50; + } + int number_blocks_updated = 0; + struct TetrominoBlock** blocks_updated = GetUpdatedBlocks(&number_blocks_updated); + r_render_blocks(blocks_updated, number_blocks_updated); + tick_rate--; + } + r_render_game_over(0); + } +} + +void _a_input_process(void) { if (IsKeyPressed(KEY_SPACE)) { - RequestRotate(); + m_request_falling_tetromino_rotate(); } if (IsKeyDown(KEY_A)) { - RequestMoveLeft(); + m_request_falling_tetromino_move_left(); } else if (IsKeyDown(KEY_D)) { - RequestMoveRight(); + m_request_falling_tetromino_move_right(); } } -void Loop(void) { - int tickRate = 0; // Guaranteed a better way to do this XD - while(!WindowShouldClose()) { - while(!CantSpawnBlock()) { - ProcessInput(); - if (tickRate == 0) { - Update(); - tickRate = 5; - } - - int numberOfUpdatedBlocks = 0; - struct TetrominoBlock** updatedBlocks = GetUpdatedBlocks(&numberOfUpdatedBlocks); - - RenderBlocks(updatedBlocks, numberOfUpdatedBlocks); - tickRate--; - } - // TODO present Game over message and score - RenderGameOver(); - } -} - -void Cleanup() { - CleanupManager(); +void _a_cleanup() { + m_deactivate(); CloseWindow(); } - -void start(void) { - Init(); - Loop(); - Cleanup(); -} \ No newline at end of file diff --git a/src/app.h b/src/app.h index c23d9a1..2376cc1 100644 --- a/src/app.h +++ b/src/app.h @@ -1,6 +1,13 @@ #ifndef TETRIS_CLONE_APP_H_ #define TETRIS_CLONE_APP_H_ -void start(void); +void a_run(void); + +void _a_initialize(void); +void _a_initialize_raylib(void); +void _a_gameboard_clear(void); +void _a_loop(void); +void _a_input_process(void); +void _a_cleanup(void); #endif // TETRIS_CLONE_APP_H_ diff --git a/src/main.c b/src/main.c index 977982c..22038ff 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ #include "app.h" int main(void) { - start(); + a_run(); return 0; } diff --git a/src/manager.c b/src/manager.c index 29d50d1..0344d1f 100644 --- a/src/manager.c +++ b/src/manager.c @@ -1,8 +1,7 @@ -#include -#include -#include +#include //srand,rand, +#include //time #define __USE_MISC -#include +#include //cos,sin #include "manager.h" @@ -26,251 +25,115 @@ struct Tetromino { struct TetrominoBlock* blocks[BLOCKS_WITHIN_A_TETROMINO]; }; - // To find block (x,y) index = (x % FIELD_WIDTH) + (y * FIELD_WIDTH) // Height doesn't matter but height is just the factor of how tall the board is. // And in the end each row is just the next representation of width * units, height just determines row count. // Doesn't factor into determining X,Y struct TetrominoBlock* _blocks[FIELD_HEIGHT * FIELD_WIDTH]; -struct TetrominoBlock* _updatedBlocks[FIELD_HEIGHT * FIELD_WIDTH] = { NULL }; -int _updatedBlockLength = 0; -bool shouldSpawnTetromino; +struct TetrominoBlock* _blocks_updated[FIELD_HEIGHT * FIELD_WIDTH] = { NULL }; +int _blocks_updated_length = 0; +bool _should_spawn_tetromino; struct Tetromino fallingTetromino; const char kSpawnX = FIELD_WIDTH / 2 - 1; const struct Offset kShiftDownOffset = { .xOffset = 0, .yOffset = 1 }; const struct Offset kShiftLeftOffset = { .xOffset = -1, .yOffset = 0 }; const struct Offset kShiftRightOffset = { .xOffset = 1, .yOffset = 0 }; -bool moveLeft = false; -bool moveRight = false; -bool rotate = false; -bool cannotSpawn = false; +bool _should_tetromino_move_left = false; +bool _should_tetromino_move_right = false; +bool _should_tetromino_rotate = false; +bool _tetromino_can_spawn = true; -void CleanupManager(void) { +void m_initialize(void) { + _m_blocks_alloc(); + _should_spawn_tetromino = true; +} + +void m_update(void) { + _m_blocks_updated_erase(); + if (_should_spawn_tetromino) { + _should_tetromino_move_left = false; + _should_tetromino_move_right = false; + _m_tetromino_spawn(); + _should_spawn_tetromino = false; + } else { + // TODO move left and right refactor naming + + if(_should_tetromino_rotate) { + _m_falling_tetromino_rotate(); + _should_tetromino_rotate = false; + } + + if (_should_tetromino_move_right && _m_falling_tetromino_can_move_right()) { + _m_falling_tetromino_translate(kShiftRightOffset); + _should_tetromino_move_right = false; + } + + if (_should_tetromino_move_left && _m_falling_tetromino_can_move_left()) { + _m_falling_tetromino_translate(kShiftLeftOffset); + _should_tetromino_move_left = false; + } + + _m_falling_tetromino_fall(); + } +} + +void m_blocks_set_empty(void) { + for (int i = 0; i < FIELD_HEIGHT * FIELD_WIDTH; i++) { + _m_block_set_type(_blocks[i], TT_EMPTY); + } +} + +bool m_tetromino_can_spawn(void) { + return _tetromino_can_spawn; +} + +void m_request_falling_tetromino_rotate(void) { + _should_tetromino_rotate = true; +} + +void m_request_falling_tetromino_move_left(void) { + _should_tetromino_move_left = true; + _should_tetromino_move_right = false; +} + +void m_request_falling_tetromino_move_right(void) { + _should_tetromino_move_right = true; + _should_tetromino_move_left = false; +} + +struct TetrominoBlock** m_blocks_get_updated(int* numberOfUpdatedBlocks) { + *numberOfUpdatedBlocks = _blocks_updated_length; + + return &_blocks_updated[0]; +} + +void m_deactivate(void) { for(int i = 0; i < sizeof(_blocks) / sizeof(struct TetrominoBlock*); i++) { free(_blocks[i]); } } -struct TetrominoBlock** GetUpdatedBlocks(int* numberOfUpdatedBlocks) { - *numberOfUpdatedBlocks = _updatedBlockLength; +void _m_blocks_alloc(void) { + for (int i = 0; i < FIELD_HEIGHT * FIELD_WIDTH; i++) { + struct TetrominoBlock* block = calloc(1, sizeof(struct TetrominoBlock)); + block->x = i % FIELD_WIDTH; + block->y = i / FIELD_WIDTH; - return &_updatedBlocks[0]; -} - -void RequestRotate(void) { - rotate = true; -} - -void RequestMoveLeft(void) { - moveLeft = true; - moveRight = false; -} - -void RequestMoveRight(void) { - moveRight = true; - moveLeft = false; -} - -struct TetrominoBlock* GetBlockAtPoint(struct Point point) { - return _blocks[(point.x % FIELD_WIDTH) + (point.y * FIELD_WIDTH)]; -} - -void RegisterUpdatedBlock(struct TetrominoBlock* pTetrominoBlock) { - if (_updatedBlockLength < FIELD_HEIGHT * FIELD_WIDTH) { - _updatedBlocks[_updatedBlockLength] = pTetrominoBlock; - _updatedBlockLength++; + _blocks[i] = block; } } -void UpdateBlockType(struct TetrominoBlock* pTetrominoBlock, enum TetrominoType type) { - pTetrominoBlock->type = type; - RegisterUpdatedBlock(pTetrominoBlock); +void _m_blocks_updated_erase() { + _blocks_updated_length = 0; } -void ShiftFallingTetrominoByOffset(struct Offset offset) { - for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { - UpdateBlockType(fallingTetromino.blocks[i], EMPTY); - RegisterUpdatedBlock(fallingTetromino.blocks[i]); - } - - for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { - struct Point updatedPoint = { .x = fallingTetromino.blocks[i]->x + offset.xOffset, .y = fallingTetromino.blocks[i]->y + offset.yOffset}; - fallingTetromino.blocks[i] = GetBlockAtPoint(updatedPoint); - - UpdateBlockType(fallingTetromino.blocks[i], fallingTetromino.type); - RegisterUpdatedBlock(fallingTetromino.blocks[i]); - } -} - -// I HATE THIS NAME... but it's verbose for now TODO - RENAME -bool DoesPointIntersectNonFallingBlock(struct Point point) { - bool result = false; - - struct TetrominoBlock* blockAtPoint = GetBlockAtPoint(point); - - if (blockAtPoint->type != EMPTY) { - result = true; - - for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { - if (fallingTetromino.blocks[i] == blockAtPoint) { - result = false; - break; - } - } - } - - return result; -} - -bool CanBlockFall(struct TetrominoBlock block) { - struct Point newBlockPoint = { .x = block.x, .y = block.y + 1}; - if (newBlockPoint.y >= FIELD_HEIGHT) { - return false; - } else if (DoesPointIntersectNonFallingBlock(newBlockPoint)) { - return false; - } else { - return true; - } -} - -bool FallingTetrominoCanFall(void) { - bool result = true; - for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { - if (!CanBlockFall(*(fallingTetromino.blocks[i]))) { - result = false; - break; - } - } - - return result; -} - -void UpdateFallingTetromino(void) { - if(FallingTetrominoCanFall()) { - ShiftFallingTetrominoByOffset(kShiftDownOffset); - } else { - shouldSpawnTetromino = true; - } -} - -bool CanBlockMoveLeft(struct TetrominoBlock block) { - struct Point newBlockPoint = { .x = block.x - 1, .y = block.y }; - if (newBlockPoint.x < 0) { - return false; - } else if (DoesPointIntersectNonFallingBlock(newBlockPoint)) { - return false; - } else { - return true; - } -} - -bool FallingTetrominoCanMoveLeft(void) { - bool result = true; - for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { - if (!CanBlockMoveLeft(*(fallingTetromino.blocks[i]))) { - result = false; - break; - } - } - - return result; -} - -bool CanBlockMoveRight(struct TetrominoBlock block) { - struct Point newBlockPoint = { .x = block.x + 1, .y = block.y }; - if (newBlockPoint.x >= FIELD_WIDTH) { - return false; - } else if (DoesPointIntersectNonFallingBlock(newBlockPoint)) { - return false; - } else { - return true; - } -} - -bool FallingTetrominoCanMoveRight(void) { - bool result = true; - for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { - if (!CanBlockMoveRight(*(fallingTetromino.blocks[i]))) { - result = false; - break; - } - } - - return result; -} - -struct Point GetRotatedPointForBlock(struct Point origin, struct TetrominoBlock block) { - // Only doing counter clockwise for now - struct Point newPoint; - newPoint.x = (block.x - origin.x) * cos(M_PI_2) - (block.y - origin.y) * sin(M_PI_2); - newPoint.y = (block.x - origin.x) * sin(M_PI_2) + (block.y - origin.y) * cos(M_PI_2); - - return newPoint; -} - -void RotateFallingTetromino(void) { - // Will be a bit buggy because i'm not checking for intersections - struct Point origin = { .x = fallingTetromino.blocks[0]->x, .y = fallingTetromino.blocks[0]->y }; - - for (int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { - // Empty the old - UpdateBlockType(fallingTetromino.blocks[i], EMPTY); - RegisterUpdatedBlock(fallingTetromino.blocks[i]); - - // Update the new - struct Point rotatedPointAdjustedForOrigin = GetRotatedPointForBlock(origin, *fallingTetromino.blocks[i]); - struct Point newRotatedPoint = { .x = rotatedPointAdjustedForOrigin.x + origin.x, .y = rotatedPointAdjustedForOrigin.y + origin.y }; - fallingTetromino.blocks[i] = GetBlockAtPoint(newRotatedPoint); - - UpdateBlockType(fallingTetromino.blocks[i], fallingTetromino.type); - RegisterUpdatedBlock(fallingTetromino.blocks[i]); - } -} - -void TryRotateFallingTetromino(void) { - // TODO IMPLEMENT - if (fallingTetromino.type == O_TYPE) { - return; - } else { - RotateFallingTetromino(); - } -} - -void SpawnBlocksAtPoints(enum TetrominoType type, struct Offset* offsets) { - fallingTetromino.type = type; - int index = 0; - while(index < BLOCKS_WITHIN_A_TETROMINO) { - struct Point spawnPoint; - spawnPoint.x = kSpawnX + offsets->xOffset; - spawnPoint.y = offsets->yOffset; - - struct TetrominoBlock* spawnBlock = GetBlockAtPoint(spawnPoint); - if (spawnBlock->type != EMPTY) { - cannotSpawn = true; - return; - } - UpdateBlockType(spawnBlock, type); - - // I'm not sure if this makes more sense to be here or return a list of spawnedBlocks to be handled in Parent function - fallingTetromino.blocks[index] = spawnBlock; - - index++; - offsets++; - } -} - -enum TetrominoType GenerateRandomTetrominoType() { - srand(time(NULL)); - return (enum TetrominoType) rand() % 6; -} - -void SpawnTetromino() { - enum TetrominoType type = GenerateRandomTetrominoType(); +void _m_tetromino_spawn() { + enum TetrominoType type = _m_tetromino_type_get_random(); struct Offset offsets[BLOCKS_WITHIN_A_TETROMINO]; - if (type == O_TYPE) { + if (type == TT_O) { offsets[0].xOffset = 0; offsets[0].yOffset = 0; @@ -282,7 +145,7 @@ void SpawnTetromino() { offsets[3].xOffset = 1; offsets[3].yOffset = 1; - } else if (type == J_TYPE) { + } else if (type == TT_J) { offsets[0].xOffset = 0; offsets[0].yOffset = 0; @@ -294,7 +157,7 @@ void SpawnTetromino() { offsets[3].xOffset = 2; offsets[3].yOffset = 1; - } else if (type == L_TYPE) { + } else if (type == TT_L) { offsets[0].xOffset = 0; offsets[0].yOffset = 1; @@ -306,7 +169,7 @@ void SpawnTetromino() { offsets[3].xOffset = 2; offsets[3].yOffset = 0; - } else if (type == I_TYPE) { + } else if (type == TT_I) { offsets[0].xOffset = 0; offsets[0].yOffset = 0; @@ -318,7 +181,7 @@ void SpawnTetromino() { offsets[3].xOffset = 0; offsets[3].yOffset = 3; - } else if (type == S_TYPE) { + } else if (type == TT_S) { offsets[0].xOffset = 0; offsets[0].yOffset = 1; @@ -330,7 +193,7 @@ void SpawnTetromino() { offsets[3].xOffset = 2; offsets[3].yOffset = 0; - } else if (type == Z_TYPE) { + } else if (type == TT_Z) { offsets[0].xOffset = 0; offsets[0].yOffset = 0; @@ -342,7 +205,7 @@ void SpawnTetromino() { offsets[3].xOffset = 2; offsets[3].yOffset = 1; - } else if (type == T_TYPE) { + } else if (type == TT_T) { offsets[0].xOffset = 1; offsets[0].yOffset = 0; @@ -356,63 +219,169 @@ void SpawnTetromino() { offsets[3].yOffset = 1; } - SpawnBlocksAtPoints(type, offsets); + _m_blocks_spawn_at_offset_from_spawn_point(type, offsets); } -void DeregisterUpdatedBlocks() { - _updatedBlockLength = 0; +enum TetrominoType _m_tetromino_type_random(void) { + srand(time(NULL)); + return (enum TetrominoType) rand() % 6; } -void Update(void) { - DeregisterUpdatedBlocks(); - if (shouldSpawnTetromino) { - moveLeft = false; - moveRight = false; - SpawnTetromino(); - shouldSpawnTetromino = false; +void _m_blocks_spawn_at_offset_from_spawn_point(enum TetrominoType type, struct Offset *offsets) { + fallingTetromino.type = type; + int index = 0; + while(index < BLOCKS_WITHIN_A_TETROMINO) { + struct Point spawnPoint; + spawnPoint.x = kSpawnX + offsets->xOffset; + spawnPoint.y = offsets->yOffset; + + struct TetrominoBlock* spawnBlock = _m_block_at_point(spawnPoint); + if (spawnBlock->type != TT_EMPTY) { + _tetromino_can_spawn = false; + return; + } + _m_block_set_type(spawnBlock, type); + + // I'm not sure if this makes more sense to be here or return a list of spawnedBlocks to be handled in Parent function + fallingTetromino.blocks[index] = spawnBlock; + + index++; + offsets++; + } +} + +struct TetrominoBlock *_m_block_at_point(struct Point point) { + return _blocks[(point.x % FIELD_WIDTH) + (point.y * FIELD_WIDTH)]; +} + +void _m_block_set_type(struct TetrominoBlock *pTetrominoBlock, enum TetrominoType type) { + pTetrominoBlock->type = type; + _m_blocks_updated_register_block(pTetrominoBlock); +} + +void _m_blocks_updated_register_block(struct TetrominoBlock *pTetrominoBlock) { + if (_blocks_updated_length < FIELD_HEIGHT * FIELD_WIDTH) { + _blocks_updated[_blocks_updated_length] = pTetrominoBlock; + _blocks_updated_length++; + } +} + +void _m_falling_tetromino_rotate(void) { + if (fallingTetromino.type != TT_O) { + // i'm not a fan of this implementation + // check this out instead and re-write + // https://stackoverflow.com/questions/42519/how-do-you-rotate-a-two-dimensional-array?page=1&tab=scoredesc#tab-top + + } +} + +bool _m_falling_tetromino_can_move_right(void) { + bool result = true; + for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { + if (!_m_block_can_move_right(*(fallingTetromino.blocks[i]))) { + result = false; + break; + } + } + + return result; +} + +void _m_falling_tetromino_translate(struct Offset offset) { + for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { + _m_block_set_type(fallingTetromino.blocks[i], TT_EMPTY); + _m_blocks_updated_register_block(fallingTetromino.blocks[i]); + } + + for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { + struct Point updatedPoint = { .x = fallingTetromino.blocks[i]->x + offset.xOffset, .y = fallingTetromino.blocks[i]->y + offset.yOffset}; + fallingTetromino.blocks[i] = _m_block_at_point(updatedPoint); + + _m_block_set_type(fallingTetromino.blocks[i], fallingTetromino.type); + _m_blocks_updated_register_block(fallingTetromino.blocks[i]); + } +} + +bool _m_point_intersects_static_block(struct Point point) { + bool result = false; + + struct TetrominoBlock* blockAtPoint = _m_block_at_point(point); + + if (blockAtPoint->type != TT_EMPTY) { + result = true; + + for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { + if (fallingTetromino.blocks[i] == blockAtPoint) { + result = false; + break; + } + } + } + + return result; +} + +bool _m_block_can_fall(struct TetrominoBlock block) { + struct Point newBlockPoint = { .x = block.x, .y = block.y + 1}; + if (newBlockPoint.y >= FIELD_HEIGHT) { + return false; + } else if (_m_point_intersects_static_block(newBlockPoint)) { + return false; } else { - // TODO move left and right refactor naming - - if(rotate) { - TryRotateFallingTetromino(); - rotate = false; - } - - if (moveRight && FallingTetrominoCanMoveRight()) { - ShiftFallingTetrominoByOffset(kShiftRightOffset); - moveRight = false; - } - - if (moveLeft && FallingTetrominoCanMoveLeft()) { - ShiftFallingTetrominoByOffset(kShiftLeftOffset); - moveLeft = false; - } - - UpdateFallingTetromino(); + return true; } } -bool CantSpawnBlock(void) { - return cannotSpawn; +bool _m_falling_tetromino_can_fall(void) { + bool result = true; + for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { + if (!_m_block_can_fall(*(fallingTetromino.blocks[i]))) { + result = false; + break; + } + } + + return result; } -void EmptyAllBlocks(void) { - for (int i = 0; i < FIELD_HEIGHT * FIELD_WIDTH; i++) { - UpdateBlockType(_blocks[i], EMPTY); +void _m_falling_tetromino_fall(void) { + if(_m_falling_tetromino_can_fall()) { + _m_falling_tetromino_translate(kShiftDownOffset); + } else { + _should_spawn_tetromino = true; } } -void AllocBlocks(void) { - for (int i = 0; i < FIELD_HEIGHT * FIELD_WIDTH; i++) { - struct TetrominoBlock* block = calloc(1, sizeof(struct TetrominoBlock)); - block->x = i % FIELD_WIDTH; - block->y = i / FIELD_WIDTH; - - _blocks[i] = block; +bool _m_block_can_move_left(struct TetrominoBlock block) { + struct Point newBlockPoint = { .x = block.x - 1, .y = block.y }; + if (newBlockPoint.x < 0) { + return false; + } else if (_m_point_intersects_static_block(newBlockPoint)) { + return false; + } else { + return true; } } -void InitManager(void) { - AllocBlocks(); - shouldSpawnTetromino = true; -} \ No newline at end of file +bool _m_falling_tetromino_can_move_left(void) { + bool result = true; + for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) { + if (!_m_block_can_move_left(*(fallingTetromino.blocks[i]))) { + result = false; + break; + } + } + + return result; +} + +bool _m_block_can_move_right(struct TetrominoBlock block) { + struct Point newBlockPoint = { .x = block.x + 1, .y = block.y }; + if (newBlockPoint.x >= FIELD_WIDTH) { + return false; + } else if (_m_point_intersects_static_block(newBlockPoint)) { + return false; + } else { + return true; + } +} diff --git a/src/manager.h b/src/manager.h index db6086a..bc4ecea 100644 --- a/src/manager.h +++ b/src/manager.h @@ -4,15 +4,15 @@ #include #include "tetromino.h" - -void InitManager(void); -void EmptyAllBlocks(void); -bool CantSpawnBlock(void); -void Update(void); -void RequestRotate(void); -void RequestMoveLeft(void); -void RequestMoveRight(void); -struct TetrominoBlock** GetUpdatedBlocks(int* lengthOfBlocksUpdated); -void CleanupManager(void); +// TODO - I'm not sure whether the internal functions should actually be here... +void m_initialize(void); +void m_update(void); +void m_blocks_set_empty(void); +bool m_tetromino_can_spawn(void); // Bad name + Doesn't follow naming +void m_request_falling_tetromino_rotate(void); +void m_request_falling_tetromino_move_left(void); +void m_request_falling_tetromino_move_right(void); +struct TetrominoBlock* *m_blocks_get_updated(int* lengthOfBlocksUpdated); +void m_deactivate(void); #endif diff --git a/src/renderer.c b/src/renderer.c index 0de371a..d23fda9 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -1,76 +1,69 @@ -#include -#include "raylib.h" - #include "renderer.h" -#define PNG_RES(name) "resources/" #name ".png" -#define BLOCK_SIZE 32 +#define RES_PNG_FILE(name) "resources/" #name ".png" +#define TEXTURE_SIZE 32 -Texture2D yellowTexture; -Texture2D blueTexture; -Texture2D lightBlueTexture; -Texture2D redTexture; -Texture2D purpleTexture; -Texture2D greenTexture; -Texture2D orangeTexture; -Texture2D emptyTexture; -Texture2D gameOverTexture; +Texture2D _yellow_texture; +Texture2D _blue_texture; +Texture2D _light_blue_texture; +Texture2D _red_texture; +Texture2D _purple_texture; +Texture2D _green_texture; +Texture2D _orange_texture; +Texture2D _empty_texture; -void InitRenderer(void) { - yellowTexture = LoadTexture(PNG_RES(yellow)); - blueTexture = LoadTexture(PNG_RES(blue)); - lightBlueTexture = LoadTexture(PNG_RES(light-blue)); - redTexture = LoadTexture(PNG_RES(red)); - purpleTexture = LoadTexture(PNG_RES(purple)); - greenTexture = LoadTexture(PNG_RES(green)); - orangeTexture = LoadTexture(PNG_RES(orange)); - emptyTexture = LoadTexture(PNG_RES(black)); - gameOverTexture = LoadTexture(PNG_RES(gameOver)); +void r_initialize(void) { + _yellow_texture = LoadTexture(RES_PNG_FILE(yellow)); + _blue_texture = LoadTexture(RES_PNG_FILE(blue)); + _light_blue_texture = LoadTexture(RES_PNG_FILE(light-blue)); + _red_texture = LoadTexture(RES_PNG_FILE(red)); + _purple_texture = LoadTexture(RES_PNG_FILE(purple)); + _green_texture = LoadTexture(RES_PNG_FILE(green)); + _orange_texture = LoadTexture(RES_PNG_FILE(orange)); + _empty_texture = LoadTexture(RES_PNG_FILE(black)); } -Texture2D* GetTextureFromTetrominoType(enum TetrominoType type) { - switch (type) { - case O_TYPE: - return &yellowTexture; - case I_TYPE: - return &lightBlueTexture; - case T_TYPE: - return &purpleTexture; - case J_TYPE: - return &blueTexture; - case L_TYPE: - return &orangeTexture; - case S_TYPE: - return &greenTexture; - case Z_TYPE: - return &redTexture; - default: - return &emptyTexture; - } -} - -void RenderTetrominoBlock(struct TetrominoBlock blockToRender) { - Texture2D* textureToRender = GetTextureFromTetrominoType(blockToRender.type); - DrawTexture(*textureToRender, blockToRender.x * BLOCK_SIZE, blockToRender.y * BLOCK_SIZE, WHITE); -} - -void RenderBlocks(struct TetrominoBlock** updatedBlocks, int length) { +void r_render_blocks(struct TetrominoBlock* *blocks, int length) { BeginDrawing(); - while(length--) { - RenderTetrominoBlock(*(*updatedBlocks)); - updatedBlocks++; + _r_render_block(*(*blocks)); + blocks++; } - EndDrawing(); } -void RenderGameOver(void) { +void r_render_game_over(int score) { BeginDrawing(); - ClearBackground(BLACK); DrawText("Game Over", SCREEN_WIDTH / 2 - MeasureText("Game Over", 24) / 2, 200, 24, RED); - DrawText("Score: N/A", SCREEN_WIDTH / 2 - MeasureText("Score: N/A", 18) / 2, 232, 18, RED); - + char* score_message = TextFormat("Score: %d", score); + DrawText(score_message, SCREEN_WIDTH / 2 - MeasureText(score_message, 18) / 2, 232, 18, RED); + // Draw a play again button EndDrawing(); +} + +void _r_render_block(struct TetrominoBlock blockToRender) { + Texture2D* textureToRender = _r_get_texture_by_tetromino_type(blockToRender.type); + DrawTexture(*textureToRender, blockToRender.x * TEXTURE_SIZE, blockToRender.y * TEXTURE_SIZE, WHITE); +} + +Texture2D* _r_get_texture_by_tetromino_type(enum TetrominoType type) { + switch (type) { + case TT_O: + return &_yellow_texture; + case TT_I: + return &_light_blue_texture; + case TT_T: + return &_purple_texture; + case TT_J: + return &_blue_texture; + case TT_L: + return &_orange_texture; + case TT_S: + return &_green_texture; + case TT_Z: + return &_red_texture; + default: + return &_empty_texture; + } } \ No newline at end of file diff --git a/src/renderer.h b/src/renderer.h index 3a9db69..63c9f69 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -1,13 +1,17 @@ #ifndef TETRIS_CLONE_RENDERER_H_ #define TETRIS_CLONE_RENDERER_H_ +#include "raylib.h" #include "tetromino.h" #define SCREEN_HEIGHT 640 #define SCREEN_WIDTH 320 -void InitRenderer(void); -void RenderBlocks(struct TetrominoBlock** updatedBlocks, int length); -void RenderGameOver(void); +void r_initialize(void); +void r_render_blocks(struct TetrominoBlock* *blocks, int length); +void r_render_game_over(int score); + +void _r_render_block(struct TetrominoBlock blockToRender); +Texture2D *_r_get_texture_by_tetromino_type(enum TetrominoType type); #endif diff --git a/src/tetris-clone b/src/tetris-clone index 22b581d..bdebff7 100755 Binary files a/src/tetris-clone and b/src/tetris-clone differ diff --git a/src/tetromino.h b/src/tetromino.h index 9fa4019..2904f26 100644 --- a/src/tetromino.h +++ b/src/tetromino.h @@ -2,19 +2,19 @@ #define TETRIS_CLONE_TETROMINO_H_ enum TetrominoType { - I_TYPE, - J_TYPE, - L_TYPE, - O_TYPE, - S_TYPE, - T_TYPE, - Z_TYPE, - EMPTY + TT_I, + TT_J, + TT_L, + TT_O, + TT_S, + TT_T, + TT_Z, + TT_EMPTY }; struct TetrominoBlock { - unsigned char x; - unsigned char y; + unsigned int x; + unsigned int y; enum TetrominoType type; };