WIP, refactoring style (Rotation Borked)
This commit is contained in:
1
TODO
1
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.)
|
- Rotate (Partially Implemented/Buggy. Should try to understand Rotation Matrix better.)
|
||||||
- Empty rows that are full should "break"
|
- Empty rows that are full should "break"
|
||||||
- Shift rows down after row "breaks"
|
- Shift rows down after row "breaks"
|
||||||
|
|||||||
87
src/app.c
87
src/app.c
@@ -4,68 +4,65 @@
|
|||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "tetromino.h"
|
#include "tetromino.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
#define TARGET_FPS 60
|
#define TARGET_FPS 60
|
||||||
|
|
||||||
void EmptyGameBoard(void) {
|
void a_run(void) {
|
||||||
EmptyAllBlocks();
|
_a_initialize();
|
||||||
|
_a_loop();
|
||||||
int numberOfUpdatedBlocks = 0;
|
_a_cleanup();
|
||||||
struct TetrominoBlock** updatedBlocks = GetUpdatedBlocks(&numberOfUpdatedBlocks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitRaylib(void) {
|
void _a_initialize(void) {
|
||||||
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Tetris Clone");
|
_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);
|
SetTargetFPS(TARGET_FPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init(void) {
|
void _a_gameboard_clear(void) {
|
||||||
InitRaylib();
|
m_blocks_set_empty();
|
||||||
InitManager();
|
int number_blocks_updated = 0;
|
||||||
InitRenderer();
|
struct TetrominoBlock** blocks_updated = m_blocks_get_updated(&number_blocks_updated);
|
||||||
EmptyGameBoard();
|
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)) {
|
if (IsKeyPressed(KEY_SPACE)) {
|
||||||
RequestRotate();
|
m_request_falling_tetromino_rotate();
|
||||||
}
|
}
|
||||||
if (IsKeyDown(KEY_A)) {
|
if (IsKeyDown(KEY_A)) {
|
||||||
RequestMoveLeft();
|
m_request_falling_tetromino_move_left();
|
||||||
} else if (IsKeyDown(KEY_D)) {
|
} else if (IsKeyDown(KEY_D)) {
|
||||||
RequestMoveRight();
|
m_request_falling_tetromino_move_right();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loop(void) {
|
void _a_cleanup() {
|
||||||
int tickRate = 0; // Guaranteed a better way to do this XD
|
m_deactivate();
|
||||||
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();
|
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(void) {
|
|
||||||
Init();
|
|
||||||
Loop();
|
|
||||||
Cleanup();
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
#ifndef TETRIS_CLONE_APP_H_
|
#ifndef TETRIS_CLONE_APP_H_
|
||||||
#define 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_
|
#endif // TETRIS_CLONE_APP_H_
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
start();
|
a_run();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
515
src/manager.c
515
src/manager.c
@@ -1,8 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdlib.h> //srand,rand,
|
||||||
#include <stdlib.h>
|
#include <time.h> //time
|
||||||
#include <time.h>
|
|
||||||
#define __USE_MISC
|
#define __USE_MISC
|
||||||
#include <math.h>
|
#include <math.h> //cos,sin
|
||||||
|
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
|
||||||
@@ -26,251 +25,115 @@ struct Tetromino {
|
|||||||
struct TetrominoBlock* blocks[BLOCKS_WITHIN_A_TETROMINO];
|
struct TetrominoBlock* blocks[BLOCKS_WITHIN_A_TETROMINO];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// To find block (x,y) index = (x % FIELD_WIDTH) + (y * FIELD_WIDTH)
|
// 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.
|
// 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.
|
// 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
|
// Doesn't factor into determining X,Y
|
||||||
struct TetrominoBlock* _blocks[FIELD_HEIGHT * FIELD_WIDTH];
|
struct TetrominoBlock* _blocks[FIELD_HEIGHT * FIELD_WIDTH];
|
||||||
struct TetrominoBlock* _updatedBlocks[FIELD_HEIGHT * FIELD_WIDTH] = { NULL };
|
struct TetrominoBlock* _blocks_updated[FIELD_HEIGHT * FIELD_WIDTH] = { NULL };
|
||||||
int _updatedBlockLength = 0;
|
int _blocks_updated_length = 0;
|
||||||
bool shouldSpawnTetromino;
|
bool _should_spawn_tetromino;
|
||||||
struct Tetromino fallingTetromino;
|
struct Tetromino fallingTetromino;
|
||||||
const char kSpawnX = FIELD_WIDTH / 2 - 1;
|
const char kSpawnX = FIELD_WIDTH / 2 - 1;
|
||||||
const struct Offset kShiftDownOffset = { .xOffset = 0, .yOffset = 1 };
|
const struct Offset kShiftDownOffset = { .xOffset = 0, .yOffset = 1 };
|
||||||
const struct Offset kShiftLeftOffset = { .xOffset = -1, .yOffset = 0 };
|
const struct Offset kShiftLeftOffset = { .xOffset = -1, .yOffset = 0 };
|
||||||
const struct Offset kShiftRightOffset = { .xOffset = 1, .yOffset = 0 };
|
const struct Offset kShiftRightOffset = { .xOffset = 1, .yOffset = 0 };
|
||||||
|
|
||||||
bool moveLeft = false;
|
bool _should_tetromino_move_left = false;
|
||||||
bool moveRight = false;
|
bool _should_tetromino_move_right = false;
|
||||||
bool rotate = false;
|
bool _should_tetromino_rotate = false;
|
||||||
bool cannotSpawn = 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++) {
|
for(int i = 0; i < sizeof(_blocks) / sizeof(struct TetrominoBlock*); i++) {
|
||||||
free(_blocks[i]);
|
free(_blocks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TetrominoBlock** GetUpdatedBlocks(int* numberOfUpdatedBlocks) {
|
void _m_blocks_alloc(void) {
|
||||||
*numberOfUpdatedBlocks = _updatedBlockLength;
|
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];
|
_blocks[i] = block;
|
||||||
}
|
|
||||||
|
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateBlockType(struct TetrominoBlock* pTetrominoBlock, enum TetrominoType type) {
|
void _m_blocks_updated_erase() {
|
||||||
pTetrominoBlock->type = type;
|
_blocks_updated_length = 0;
|
||||||
RegisterUpdatedBlock(pTetrominoBlock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShiftFallingTetrominoByOffset(struct Offset offset) {
|
void _m_tetromino_spawn() {
|
||||||
for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) {
|
enum TetrominoType type = _m_tetromino_type_get_random();
|
||||||
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();
|
|
||||||
|
|
||||||
struct Offset offsets[BLOCKS_WITHIN_A_TETROMINO];
|
struct Offset offsets[BLOCKS_WITHIN_A_TETROMINO];
|
||||||
|
|
||||||
if (type == O_TYPE) {
|
if (type == TT_O) {
|
||||||
offsets[0].xOffset = 0;
|
offsets[0].xOffset = 0;
|
||||||
offsets[0].yOffset = 0;
|
offsets[0].yOffset = 0;
|
||||||
|
|
||||||
@@ -282,7 +145,7 @@ void SpawnTetromino() {
|
|||||||
|
|
||||||
offsets[3].xOffset = 1;
|
offsets[3].xOffset = 1;
|
||||||
offsets[3].yOffset = 1;
|
offsets[3].yOffset = 1;
|
||||||
} else if (type == J_TYPE) {
|
} else if (type == TT_J) {
|
||||||
offsets[0].xOffset = 0;
|
offsets[0].xOffset = 0;
|
||||||
offsets[0].yOffset = 0;
|
offsets[0].yOffset = 0;
|
||||||
|
|
||||||
@@ -294,7 +157,7 @@ void SpawnTetromino() {
|
|||||||
|
|
||||||
offsets[3].xOffset = 2;
|
offsets[3].xOffset = 2;
|
||||||
offsets[3].yOffset = 1;
|
offsets[3].yOffset = 1;
|
||||||
} else if (type == L_TYPE) {
|
} else if (type == TT_L) {
|
||||||
offsets[0].xOffset = 0;
|
offsets[0].xOffset = 0;
|
||||||
offsets[0].yOffset = 1;
|
offsets[0].yOffset = 1;
|
||||||
|
|
||||||
@@ -306,7 +169,7 @@ void SpawnTetromino() {
|
|||||||
|
|
||||||
offsets[3].xOffset = 2;
|
offsets[3].xOffset = 2;
|
||||||
offsets[3].yOffset = 0;
|
offsets[3].yOffset = 0;
|
||||||
} else if (type == I_TYPE) {
|
} else if (type == TT_I) {
|
||||||
offsets[0].xOffset = 0;
|
offsets[0].xOffset = 0;
|
||||||
offsets[0].yOffset = 0;
|
offsets[0].yOffset = 0;
|
||||||
|
|
||||||
@@ -318,7 +181,7 @@ void SpawnTetromino() {
|
|||||||
|
|
||||||
offsets[3].xOffset = 0;
|
offsets[3].xOffset = 0;
|
||||||
offsets[3].yOffset = 3;
|
offsets[3].yOffset = 3;
|
||||||
} else if (type == S_TYPE) {
|
} else if (type == TT_S) {
|
||||||
offsets[0].xOffset = 0;
|
offsets[0].xOffset = 0;
|
||||||
offsets[0].yOffset = 1;
|
offsets[0].yOffset = 1;
|
||||||
|
|
||||||
@@ -330,7 +193,7 @@ void SpawnTetromino() {
|
|||||||
|
|
||||||
offsets[3].xOffset = 2;
|
offsets[3].xOffset = 2;
|
||||||
offsets[3].yOffset = 0;
|
offsets[3].yOffset = 0;
|
||||||
} else if (type == Z_TYPE) {
|
} else if (type == TT_Z) {
|
||||||
offsets[0].xOffset = 0;
|
offsets[0].xOffset = 0;
|
||||||
offsets[0].yOffset = 0;
|
offsets[0].yOffset = 0;
|
||||||
|
|
||||||
@@ -342,7 +205,7 @@ void SpawnTetromino() {
|
|||||||
|
|
||||||
offsets[3].xOffset = 2;
|
offsets[3].xOffset = 2;
|
||||||
offsets[3].yOffset = 1;
|
offsets[3].yOffset = 1;
|
||||||
} else if (type == T_TYPE) {
|
} else if (type == TT_T) {
|
||||||
offsets[0].xOffset = 1;
|
offsets[0].xOffset = 1;
|
||||||
offsets[0].yOffset = 0;
|
offsets[0].yOffset = 0;
|
||||||
|
|
||||||
@@ -356,63 +219,169 @@ void SpawnTetromino() {
|
|||||||
offsets[3].yOffset = 1;
|
offsets[3].yOffset = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnBlocksAtPoints(type, offsets);
|
_m_blocks_spawn_at_offset_from_spawn_point(type, offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeregisterUpdatedBlocks() {
|
enum TetrominoType _m_tetromino_type_random(void) {
|
||||||
_updatedBlockLength = 0;
|
srand(time(NULL));
|
||||||
|
return (enum TetrominoType) rand() % 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update(void) {
|
void _m_blocks_spawn_at_offset_from_spawn_point(enum TetrominoType type, struct Offset *offsets) {
|
||||||
DeregisterUpdatedBlocks();
|
fallingTetromino.type = type;
|
||||||
if (shouldSpawnTetromino) {
|
int index = 0;
|
||||||
moveLeft = false;
|
while(index < BLOCKS_WITHIN_A_TETROMINO) {
|
||||||
moveRight = false;
|
struct Point spawnPoint;
|
||||||
SpawnTetromino();
|
spawnPoint.x = kSpawnX + offsets->xOffset;
|
||||||
shouldSpawnTetromino = false;
|
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 {
|
} else {
|
||||||
// TODO move left and right refactor naming
|
return true;
|
||||||
|
|
||||||
if(rotate) {
|
|
||||||
TryRotateFallingTetromino();
|
|
||||||
rotate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moveRight && FallingTetrominoCanMoveRight()) {
|
|
||||||
ShiftFallingTetrominoByOffset(kShiftRightOffset);
|
|
||||||
moveRight = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moveLeft && FallingTetrominoCanMoveLeft()) {
|
|
||||||
ShiftFallingTetrominoByOffset(kShiftLeftOffset);
|
|
||||||
moveLeft = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateFallingTetromino();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CantSpawnBlock(void) {
|
bool _m_falling_tetromino_can_fall(void) {
|
||||||
return cannotSpawn;
|
bool result = true;
|
||||||
}
|
for(int i = 0; i < BLOCKS_WITHIN_A_TETROMINO; i++) {
|
||||||
|
if (!_m_block_can_fall(*(fallingTetromino.blocks[i]))) {
|
||||||
void EmptyAllBlocks(void) {
|
result = false;
|
||||||
for (int i = 0; i < FIELD_HEIGHT * FIELD_WIDTH; i++) {
|
break;
|
||||||
UpdateBlockType(_blocks[i], EMPTY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AllocBlocks(void) {
|
return result;
|
||||||
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;
|
void _m_falling_tetromino_fall(void) {
|
||||||
|
if(_m_falling_tetromino_can_fall()) {
|
||||||
|
_m_falling_tetromino_translate(kShiftDownOffset);
|
||||||
|
} else {
|
||||||
|
_should_spawn_tetromino = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitManager(void) {
|
bool _m_block_can_move_left(struct TetrominoBlock block) {
|
||||||
AllocBlocks();
|
struct Point newBlockPoint = { .x = block.x - 1, .y = block.y };
|
||||||
shouldSpawnTetromino = true;
|
if (newBlockPoint.x < 0) {
|
||||||
|
return false;
|
||||||
|
} else if (_m_point_intersects_static_block(newBlockPoint)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,15 +4,15 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "tetromino.h"
|
#include "tetromino.h"
|
||||||
|
// TODO - I'm not sure whether the internal functions should actually be here...
|
||||||
void InitManager(void);
|
void m_initialize(void);
|
||||||
void EmptyAllBlocks(void);
|
void m_update(void);
|
||||||
bool CantSpawnBlock(void);
|
void m_blocks_set_empty(void);
|
||||||
void Update(void);
|
bool m_tetromino_can_spawn(void); // Bad name + Doesn't follow naming
|
||||||
void RequestRotate(void);
|
void m_request_falling_tetromino_rotate(void);
|
||||||
void RequestMoveLeft(void);
|
void m_request_falling_tetromino_move_left(void);
|
||||||
void RequestMoveRight(void);
|
void m_request_falling_tetromino_move_right(void);
|
||||||
struct TetrominoBlock** GetUpdatedBlocks(int* lengthOfBlocksUpdated);
|
struct TetrominoBlock* *m_blocks_get_updated(int* lengthOfBlocksUpdated);
|
||||||
void CleanupManager(void);
|
void m_deactivate(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
111
src/renderer.c
111
src/renderer.c
@@ -1,76 +1,69 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "raylib.h"
|
|
||||||
|
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
#define PNG_RES(name) "resources/" #name ".png"
|
#define RES_PNG_FILE(name) "resources/" #name ".png"
|
||||||
#define BLOCK_SIZE 32
|
#define TEXTURE_SIZE 32
|
||||||
|
|
||||||
Texture2D yellowTexture;
|
Texture2D _yellow_texture;
|
||||||
Texture2D blueTexture;
|
Texture2D _blue_texture;
|
||||||
Texture2D lightBlueTexture;
|
Texture2D _light_blue_texture;
|
||||||
Texture2D redTexture;
|
Texture2D _red_texture;
|
||||||
Texture2D purpleTexture;
|
Texture2D _purple_texture;
|
||||||
Texture2D greenTexture;
|
Texture2D _green_texture;
|
||||||
Texture2D orangeTexture;
|
Texture2D _orange_texture;
|
||||||
Texture2D emptyTexture;
|
Texture2D _empty_texture;
|
||||||
Texture2D gameOverTexture;
|
|
||||||
|
|
||||||
void InitRenderer(void) {
|
void r_initialize(void) {
|
||||||
yellowTexture = LoadTexture(PNG_RES(yellow));
|
_yellow_texture = LoadTexture(RES_PNG_FILE(yellow));
|
||||||
blueTexture = LoadTexture(PNG_RES(blue));
|
_blue_texture = LoadTexture(RES_PNG_FILE(blue));
|
||||||
lightBlueTexture = LoadTexture(PNG_RES(light-blue));
|
_light_blue_texture = LoadTexture(RES_PNG_FILE(light-blue));
|
||||||
redTexture = LoadTexture(PNG_RES(red));
|
_red_texture = LoadTexture(RES_PNG_FILE(red));
|
||||||
purpleTexture = LoadTexture(PNG_RES(purple));
|
_purple_texture = LoadTexture(RES_PNG_FILE(purple));
|
||||||
greenTexture = LoadTexture(PNG_RES(green));
|
_green_texture = LoadTexture(RES_PNG_FILE(green));
|
||||||
orangeTexture = LoadTexture(PNG_RES(orange));
|
_orange_texture = LoadTexture(RES_PNG_FILE(orange));
|
||||||
emptyTexture = LoadTexture(PNG_RES(black));
|
_empty_texture = LoadTexture(RES_PNG_FILE(black));
|
||||||
gameOverTexture = LoadTexture(PNG_RES(gameOver));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture2D* GetTextureFromTetrominoType(enum TetrominoType type) {
|
void r_render_blocks(struct TetrominoBlock* *blocks, int length) {
|
||||||
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) {
|
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
||||||
while(length--) {
|
while(length--) {
|
||||||
RenderTetrominoBlock(*(*updatedBlocks));
|
_r_render_block(*(*blocks));
|
||||||
updatedBlocks++;
|
blocks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderGameOver(void) {
|
void r_render_game_over(int score) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
||||||
ClearBackground(BLACK);
|
ClearBackground(BLACK);
|
||||||
DrawText("Game Over", SCREEN_WIDTH / 2 - MeasureText("Game Over", 24) / 2, 200, 24, RED);
|
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();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
#ifndef TETRIS_CLONE_RENDERER_H_
|
#ifndef TETRIS_CLONE_RENDERER_H_
|
||||||
#define TETRIS_CLONE_RENDERER_H_
|
#define TETRIS_CLONE_RENDERER_H_
|
||||||
|
#include "raylib.h"
|
||||||
|
|
||||||
#include "tetromino.h"
|
#include "tetromino.h"
|
||||||
|
|
||||||
#define SCREEN_HEIGHT 640
|
#define SCREEN_HEIGHT 640
|
||||||
#define SCREEN_WIDTH 320
|
#define SCREEN_WIDTH 320
|
||||||
|
|
||||||
void InitRenderer(void);
|
void r_initialize(void);
|
||||||
void RenderBlocks(struct TetrominoBlock** updatedBlocks, int length);
|
void r_render_blocks(struct TetrominoBlock* *blocks, int length);
|
||||||
void RenderGameOver(void);
|
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
|
#endif
|
||||||
|
|||||||
BIN
src/tetris-clone
BIN
src/tetris-clone
Binary file not shown.
@@ -2,19 +2,19 @@
|
|||||||
#define TETRIS_CLONE_TETROMINO_H_
|
#define TETRIS_CLONE_TETROMINO_H_
|
||||||
|
|
||||||
enum TetrominoType {
|
enum TetrominoType {
|
||||||
I_TYPE,
|
TT_I,
|
||||||
J_TYPE,
|
TT_J,
|
||||||
L_TYPE,
|
TT_L,
|
||||||
O_TYPE,
|
TT_O,
|
||||||
S_TYPE,
|
TT_S,
|
||||||
T_TYPE,
|
TT_T,
|
||||||
Z_TYPE,
|
TT_Z,
|
||||||
EMPTY
|
TT_EMPTY
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TetrominoBlock {
|
struct TetrominoBlock {
|
||||||
unsigned char x;
|
unsigned int x;
|
||||||
unsigned char y;
|
unsigned int y;
|
||||||
enum TetrominoType type;
|
enum TetrominoType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user