Compare commits
4 Commits
f3d3311baf
...
f80003520e
| Author | SHA1 | Date | |
|---|---|---|---|
| f80003520e | |||
| 138e8474c1 | |||
| cb22b6d226 | |||
| d721b68551 |
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/build/
|
||||||
|
/CMakeFiles/
|
||||||
|
/CMakeCache.txt
|
||||||
|
/cmake_install.cmake
|
||||||
|
/Makefile
|
||||||
|
/njetris
|
||||||
|
/main
|
||||||
|
/main.c
|
||||||
16
.vscode/c_cpp_properties.json
vendored
Normal file
16
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/usr/bin/clang",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"intelliSenseMode": "linux-clang-x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
51
.vscode/launch.json
vendored
Normal file
51
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "CMake Debug",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/build/njetris",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "CMake: build",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CMake Launch",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/build/njetris",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "CMake: build",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"*.embeddedhtml": "html",
|
||||||
|
"tetris.h": "c",
|
||||||
|
"cmath": "c"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10.0)
|
||||||
|
project(njetris VERSION 0.1.0 LANGUAGES C)
|
||||||
|
|
||||||
|
add_executable(njetris tetris.c)
|
||||||
|
|
||||||
|
#add raylib
|
||||||
|
find_package(raylib REQUIRED)
|
||||||
|
target_link_libraries(njetris raylib m)
|
||||||
7
buildraylib.sh
Executable file
7
buildraylib.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
git clone --depth 1 https://github.com/raysan5/raylib.git raylib
|
||||||
|
cd raylib/src/
|
||||||
|
make PLATFORM=PLATFORM_DESKTOP # To make the static version.
|
||||||
|
make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=SHARED # To make the dynamic shared version.
|
||||||
|
make PLATFORM=PLATFORM_WEB # To make web version.
|
||||||
119
gridutils.c
Normal file
119
gridutils.c
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "tetris.h"
|
||||||
|
|
||||||
|
void grid_set(bitgrid_t* grid, int x, int y, bool value){
|
||||||
|
if(x < 0 || x >= TOTAL_WIDTH || y < 0 || y >= TOTAL_HEIGHT) return;
|
||||||
|
|
||||||
|
int bitIndex = y * TOTAL_WIDTH + x;
|
||||||
|
int wordIndex = bitIndex / 32;
|
||||||
|
int bitPosition = bitIndex % 32;
|
||||||
|
|
||||||
|
if(value){
|
||||||
|
grid->bits[wordIndex] |= (1U << bitPosition);
|
||||||
|
} else {
|
||||||
|
grid->bits[wordIndex] &= ~(1U << bitPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void grid_get(bitgrid_t* grid, int x, int y, bool* value) {
|
||||||
|
if(x < 0 || x >= TOTAL_WIDTH || y < 0 || y >= TOTAL_HEIGHT) {
|
||||||
|
*value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bitIndex = y * TOTAL_WIDTH + x;
|
||||||
|
int wordIndex = bitIndex / 32;
|
||||||
|
int bitPosition = bitIndex % 32;
|
||||||
|
|
||||||
|
*value = (grid->bits[wordIndex] & (1U << bitPosition)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool grid_equals(bitgrid_t* a, bitgrid_t* b){
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
if(a->bits[i] != b->bits[i]){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitgrid_t grid_copy(bitgrid_t* src){
|
||||||
|
bitgrid_t result;
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
result.bits[i] = src->bits[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitgrid_bitwise_and(bitgrid_t* dest, bitgrid_t* a, bitgrid_t* b){
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
dest->bits[i] = a->bits[i] & b->bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitgrid_bitwise_or(bitgrid_t* dest, bitgrid_t* a, bitgrid_t* b){
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
dest->bits[i] = a->bits[i] | b->bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitgrid_bitwise_xor(bitgrid_t* dest, bitgrid_t* a, bitgrid_t* b){
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
dest->bits[i] = a->bits[i] ^ b->bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitgrid_bitwise_not(bitgrid_t* dest, bitgrid_t* src){
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
dest->bits[i] = ~(src->bits[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitgrid_bitwise_shift_left(bitgrid_t* dest, bitgrid_t* src, int shift){
|
||||||
|
if(shift < 0) return; // Invalid shift
|
||||||
|
if(shift == 0){
|
||||||
|
*dest = *src;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalBits = TOTAL_WIDTH * TOTAL_HEIGHT;
|
||||||
|
if(shift >= totalBits){
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
dest->bits[i] = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wordShift = shift / 32;
|
||||||
|
int bitShift = shift % 32;
|
||||||
|
|
||||||
|
for(int i = GRID_WORDS - 1; i >= 0; i--){
|
||||||
|
uint32_t upper = (i - wordShift - 1 >= 0 && bitShift != 0) ? (src->bits[i - wordShift - 1] >> (32 - bitShift)) : 0;
|
||||||
|
uint32_t lower = (i - wordShift >= 0) ? (src->bits[i - wordShift] << bitShift) : 0;
|
||||||
|
dest->bits[i] = upper | lower;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitgrid_bitwise_shift_right(bitgrid_t* dest, bitgrid_t* src, int shift){
|
||||||
|
if(shift < 0) return; // Invalid shift
|
||||||
|
if(shift == 0){
|
||||||
|
*dest = *src;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalBits = TOTAL_WIDTH * TOTAL_HEIGHT;
|
||||||
|
if(shift >= totalBits){
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
dest->bits[i] = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wordShift = shift / 32;
|
||||||
|
int bitShift = shift % 32;
|
||||||
|
|
||||||
|
for(int i = 0; i < GRID_WORDS; i++){
|
||||||
|
uint32_t lower = (i + wordShift + 1 < GRID_WORDS && bitShift != 0) ? (src->bits[i + wordShift + 1] << (32 - bitShift)) : 0;
|
||||||
|
uint32_t upper = (i + wordShift < GRID_WORDS) ? (src->bits[i + wordShift] >> bitShift) : 0;
|
||||||
|
dest->bits[i] = upper | lower;
|
||||||
|
}
|
||||||
|
}
|
||||||
568
tetris.c
Normal file
568
tetris.c
Normal file
@ -0,0 +1,568 @@
|
|||||||
|
// Tetris in C using raylib
|
||||||
|
#include "tetris.h"
|
||||||
|
|
||||||
|
// Game state
|
||||||
|
unsigned char board[BOARD_HEIGHT][BOARD_WIDTH] = {0};
|
||||||
|
unsigned int iBoardMask[BOARD_HEIGHT] = {0}; // bitmask for each row
|
||||||
|
unsigned int iPieceMask[BOARD_HEIGHT + PIECE_BUFFER_OFFSET] = {0}; // bitmask for piece position
|
||||||
|
bool board_mask[BOARD_HEIGHT][BOARD_WIDTH] = {0};
|
||||||
|
bool piece_mask[BOARD_HEIGHT+PIECE_BUFFER_OFFSET][BOARD_WIDTH] = {0};
|
||||||
|
char piece_rotation = 0;
|
||||||
|
// Piece shapes[] = { T_PIECE, O_PIECE, Z_PIECE, S_PIECE, I_PIECE, J_PIECE, L_PIECE};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Main function
|
||||||
|
int main(){
|
||||||
|
printf("Let's play some tetris motherfucker");
|
||||||
|
InitWindow(BOARD_WIDTH*GRID_SCREEN_PIXELS, BOARD_HEIGHT*GRID_SCREEN_PIXELS, "yaa");
|
||||||
|
SetTargetFPS(60);
|
||||||
|
zero_board();
|
||||||
|
init_game();
|
||||||
|
while(1){
|
||||||
|
BeginDrawing();
|
||||||
|
update();
|
||||||
|
draw();
|
||||||
|
EndDrawing();
|
||||||
|
if(WindowShouldClose()) break;
|
||||||
|
}
|
||||||
|
cleanup_shapes();
|
||||||
|
|
||||||
|
CloseWindow();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize shapes array properly
|
||||||
|
Piece shapes[7];
|
||||||
|
bool shapes_initialized = false;
|
||||||
|
Piece* current_piece = NULL;
|
||||||
|
|
||||||
|
void init_shapes() {
|
||||||
|
if(shapes_initialized) return;
|
||||||
|
|
||||||
|
shapes[0] = T_PIECE;
|
||||||
|
shapes[1] = O_PIECE;
|
||||||
|
shapes[2] = Z_PIECE;
|
||||||
|
shapes[3] = S_PIECE;
|
||||||
|
shapes[4] = I_PIECE;
|
||||||
|
shapes[5] = J_PIECE;
|
||||||
|
shapes[6] = L_PIECE;
|
||||||
|
|
||||||
|
shapes_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_shapes() {
|
||||||
|
for(int i = 0; i < 7; i++) {
|
||||||
|
free_shape(shapes[i].shape, shapes[i].dims.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_game(){
|
||||||
|
init_shapes();
|
||||||
|
zero_board();
|
||||||
|
zero_board_mask();
|
||||||
|
zero_piece_mask();
|
||||||
|
spawn_piece();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function implementations
|
||||||
|
|
||||||
|
void zero_board(){
|
||||||
|
for(int i = 0; i < BOARD_HEIGHT; i++){
|
||||||
|
for(int j = 0; j < BOARD_WIDTH; j++){
|
||||||
|
board[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_board_mask(){
|
||||||
|
for(int iter_height = 0; iter_height < BOARD_HEIGHT; iter_height++){
|
||||||
|
for(int iter_width = 0; iter_width < BOARD_WIDTH; iter_width++){
|
||||||
|
board_mask[iter_height][iter_width] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_piece_mask(){
|
||||||
|
for(int iter_height = 0; iter_height < BOARD_HEIGHT + PIECE_BUFFER_OFFSET; iter_height++){
|
||||||
|
for(int iter_width = 0; iter_width < BOARD_WIDTH; iter_width++){
|
||||||
|
piece_mask[iter_height][iter_width] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void populate_board_mask(){
|
||||||
|
for(int i = 0; i < BOARD_HEIGHT; i++){
|
||||||
|
for(int j = 0; j < BOARD_WIDTH; j++){
|
||||||
|
if(board[i][j] != 0){
|
||||||
|
board_mask[i][j] = true;
|
||||||
|
} else {
|
||||||
|
board_mask[i][j] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next_tick_valid(){
|
||||||
|
populate_board_mask();
|
||||||
|
for(int iter_height = 0; iter_height < BOARD_HEIGHT; iter_height++)
|
||||||
|
{
|
||||||
|
for(int iter_width = 0; iter_width < BOARD_WIDTH; iter_width++)
|
||||||
|
{
|
||||||
|
if( board_mask[iter_height][iter_width] &&
|
||||||
|
piece_mask[iter_height-1+PIECE_BUFFER_OFFSET][iter_width] )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool piece_tick(){
|
||||||
|
|
||||||
|
if(!next_tick_valid()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Check if piece can go down
|
||||||
|
// We should convert this to a simpler check where the booleans are converted to a single binary value and compared
|
||||||
|
for(int k = 0; k < BOARD_WIDTH; k++){
|
||||||
|
if(piece_mask[BOARD_HEIGHT-1 + PIECE_BUFFER_OFFSET][k]){
|
||||||
|
return 0; // piece would go out of bounds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Move piece down
|
||||||
|
for(int j = BOARD_HEIGHT - 1 + PIECE_BUFFER_OFFSET; j >= 0; j--){
|
||||||
|
for(int i = 0; i < BOARD_WIDTH; i++){
|
||||||
|
if(piece_mask[j][i]){
|
||||||
|
piece_mask[j+1][i] = piece_mask[j][i]; // This somehow doesn't crash out of bounds?
|
||||||
|
piece_mask[j][i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void place_piece(){
|
||||||
|
for(int i = 0; i < BOARD_HEIGHT+PIECE_BUFFER_OFFSET; i++){
|
||||||
|
for(int j = 0; j < BOARD_WIDTH; j++){
|
||||||
|
if(piece_mask[i][j]){
|
||||||
|
board[i-PIECE_BUFFER_OFFSET][j] = current_piece->color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
populate_board_mask();
|
||||||
|
}
|
||||||
|
void spawn_piece(){
|
||||||
|
current_piece = &shapes[GetRandomValue(0, 6)];
|
||||||
|
piece_rotation = 0;
|
||||||
|
// position piece at top of board
|
||||||
|
// calculate piece_mask based on shape and position
|
||||||
|
Vector2* bounds = get_shape_bounds();
|
||||||
|
|
||||||
|
int spawn_x = (BOARD_WIDTH / 2) - (int)bounds[0].x; // center horizontally, adjust for shape bounds
|
||||||
|
int spawn_y = 2 + (int)bounds[0].y;
|
||||||
|
|
||||||
|
|
||||||
|
for(int i = 0; i < current_piece->dims.y; i++){
|
||||||
|
for(int j = 0; j < current_piece->dims.x; j++){
|
||||||
|
if(current_piece->shape[i][j] == 1){
|
||||||
|
int board_x = spawn_x + j;
|
||||||
|
int board_y = spawn_y + i;
|
||||||
|
if(board_x >= 0 && board_x < BOARD_WIDTH && board_y >= 0 && board_y < BOARD_HEIGHT){
|
||||||
|
piece_mask[board_y][board_x] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// void Vector2Rotate(Vector2* v, float angle){
|
||||||
|
// if (v == NULL) return;
|
||||||
|
// float rad = angle * (3.14159265 / 180.0);
|
||||||
|
// float cosA = cos(rad);
|
||||||
|
// float sinA = sin(rad);
|
||||||
|
// float x_new = v->x * cosA - v->y * sinA;
|
||||||
|
// float y_new = v->x * sinA + v->y * cosA;
|
||||||
|
// v->x = x_new;
|
||||||
|
// v->y = y_new;
|
||||||
|
// }
|
||||||
|
void Vector2Rotate(Vector2* v, float angle){
|
||||||
|
if (v == NULL) return;
|
||||||
|
float rad = angle * (PI / 180.0);
|
||||||
|
float cosA = cosf(rad);
|
||||||
|
float sinA = sinf(rad);
|
||||||
|
|
||||||
|
// Store original values
|
||||||
|
float orig_x = v->x;
|
||||||
|
float orig_y = v->y;
|
||||||
|
|
||||||
|
// Calculate new values using original coordinates
|
||||||
|
v->x = orig_x * cosA - orig_y * sinA;
|
||||||
|
v->y = orig_x * sinA + orig_y * cosA;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Vector2Subtract(Vector2* v1, Vector2* v2){
|
||||||
|
Vector2 result = (Vector2) {0,0};
|
||||||
|
result.x = v1->x - v2->x;
|
||||||
|
result.y = v1->y - v2->y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_draw_blocks_on_axis(Vector2 pblock_vecs[4], Color color){
|
||||||
|
bool debugDrawing = 1;
|
||||||
|
int numVecs = sizeof(pblock_vecs) / sizeof(pblock_vecs[0]);
|
||||||
|
Vector2 block_vecs[numVecs];
|
||||||
|
#ifdef NDEBUG
|
||||||
|
int axis_zero_x = BOARD_WIDTH / 2;
|
||||||
|
int axis_zero_y = BOARD_HEIGHT / 2;
|
||||||
|
BeginDrawing();
|
||||||
|
//
|
||||||
|
// Draw axis
|
||||||
|
for(int i = -5; i <= 5; i++){
|
||||||
|
debugDraw(axis_zero_x + i, axis_zero_y, (Color){255,255,0,255});
|
||||||
|
debugDraw(axis_zero_x, axis_zero_y + i, (Color){255,255,0,255});
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < numVecs; i++){
|
||||||
|
debugDraw((int)(block_vecs[i].x)+axis_zero_x, (int)(block_vecs[i].y+axis_zero_y), (Color) color);
|
||||||
|
}
|
||||||
|
|
||||||
|
asm("nop"); // debug breakpoint
|
||||||
|
|
||||||
|
draw(); // reset
|
||||||
|
EndDrawing();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void debug_draw_blocks(Vector2 block_vecs[1], Color color){
|
||||||
|
bool debugDrawing = 1;
|
||||||
|
int numVecs = sizeof(block_vecs) / sizeof(block_vecs[0]);
|
||||||
|
#ifdef NDEBUG
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
for(int i = 0; i < numVecs; i++){
|
||||||
|
debugDraw((int)(block_vecs[i].x), (int)(block_vecs[i].y), (Color) color);
|
||||||
|
}
|
||||||
|
|
||||||
|
asm("nop"); // debug breakpoint
|
||||||
|
|
||||||
|
draw(); // reset
|
||||||
|
EndDrawing();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void turn_piece(bool clockwise){
|
||||||
|
if(!current_piece || !current_piece->has_origin){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Piece* cpiece = current_piece; // Assuming current_piece is already Piece*
|
||||||
|
Vector2 block_vecs[4] = {{0,0},{0,0},{0,0},{0,0}};
|
||||||
|
|
||||||
|
// Verified fixed
|
||||||
|
get_vecs_from_shape(cpiece, block_vecs);
|
||||||
|
|
||||||
|
|
||||||
|
asm("nop"); // debug breakpoint
|
||||||
|
|
||||||
|
// rotate blocks from shape data to match currently tracked orientation
|
||||||
|
// somehow this turns a J piece into a T piece. wtf
|
||||||
|
// Apply current rotation incrementally to avoid precision errors
|
||||||
|
for(int rotation_step = 0; rotation_step < piece_rotation; rotation_step++){
|
||||||
|
for(int i = 0; i < 4; i++){
|
||||||
|
Vector2Rotate(&block_vecs[i], 90); // Always rotate by 90°
|
||||||
|
block_vecs[i].x = roundf(block_vecs[i].x); // Round instead of truncate
|
||||||
|
block_vecs[i].y = roundf(block_vecs[i].y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_draw_blocks_on_axis(block_vecs, (Color){255,255,255,255});
|
||||||
|
|
||||||
|
// sort blocks, also broken
|
||||||
|
sort_blocks(block_vecs);
|
||||||
|
|
||||||
|
debug_draw_blocks_on_axis(block_vecs, (Color){255,255,255,255});
|
||||||
|
|
||||||
|
asm("nop"); // debug breakpoint
|
||||||
|
|
||||||
|
Vector2 topleftmost_block = find_topleftmost_block_from_buffer();
|
||||||
|
Vector2 origin_on_piece_mask = Vector2Subtract(&topleftmost_block,&block_vecs[0]);
|
||||||
|
|
||||||
|
debug_draw_blocks((Vector2[1]){(Vector2){(int)origin_on_piece_mask.x, (int)origin_on_piece_mask.y-PIECE_BUFFER_OFFSET}}, (Color){255,255,255,255});
|
||||||
|
// clear piece mask
|
||||||
|
// try to rotate to new position now
|
||||||
|
Vector2 test_vecs[4];
|
||||||
|
memcpy(test_vecs, block_vecs, sizeof(block_vecs));
|
||||||
|
for(int i = 0; i < 4; i++){
|
||||||
|
Vector2Rotate(&test_vecs[i], 90 * (clockwise ? 1 : -1));
|
||||||
|
int new_y = (float)(int)(test_vecs[i].y + origin_on_piece_mask.y);
|
||||||
|
int new_x = (float)(int)(test_vecs[i].x + origin_on_piece_mask.x);
|
||||||
|
if(new_x < 0 || new_x >= BOARD_WIDTH){
|
||||||
|
return; // out of bounds
|
||||||
|
}
|
||||||
|
if(new_y < 0 || new_y >= BOARD_HEIGHT + PIECE_BUFFER_OFFSET){
|
||||||
|
return; // out of bounds
|
||||||
|
}
|
||||||
|
if(board_mask[new_y - PIECE_BUFFER_OFFSET][new_x]){
|
||||||
|
return; // collision
|
||||||
|
}
|
||||||
|
test_vecs[i].x = roundf(test_vecs[i].x);
|
||||||
|
test_vecs[i].y = roundf(test_vecs[i].y);
|
||||||
|
}
|
||||||
|
zero_piece_mask();
|
||||||
|
for(int i = 0; i < 4; i++){
|
||||||
|
Vector2 vec = test_vecs[i];
|
||||||
|
piece_mask[(int)(vec.y + origin_on_piece_mask.y)][(int)(vec.x + origin_on_piece_mask.x)] = true;
|
||||||
|
}
|
||||||
|
// update piece rotation tracker
|
||||||
|
piece_rotation += clockwise ? 1 : -1;
|
||||||
|
if(piece_rotation > 3) piece_rotation = 0;
|
||||||
|
if(piece_rotation < 0) piece_rotation = 3;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2* get_shape_bounds(){
|
||||||
|
static Vector2 bounds[2]; // [0] = origin--> top-left, [1] = bottom-right
|
||||||
|
Piece* cpiece = current_piece;
|
||||||
|
Vector2* origin = &cpiece->origin;
|
||||||
|
Vector2* dims = &cpiece->dims;
|
||||||
|
|
||||||
|
bounds[0].x = 0 - origin->x;
|
||||||
|
bounds[0].y = 0 - origin->y;
|
||||||
|
bounds[1].x = (dims->x -1) - origin->x;
|
||||||
|
bounds[1].y = (dims->y -1) - origin->y;
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_vecs_from_shape(Piece* cpiece, Vector2* blocks){
|
||||||
|
Vector2* dims = get_shape_dimensions(current_piece);
|
||||||
|
|
||||||
|
// Allocate memory for temporary shape copy
|
||||||
|
int** shape = malloc(dims->y * sizeof(int*));
|
||||||
|
for(int i = 0; i < dims->y; i++){
|
||||||
|
shape[i] = malloc(dims->x * sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the current piece shape
|
||||||
|
for(int i = 0; i < dims->y; i++){
|
||||||
|
memcpy(shape[i], cpiece->shape[i], dims->x *sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2* origin = ¤t_piece->origin;
|
||||||
|
|
||||||
|
int block_count = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < dims->y; i++){
|
||||||
|
for(int j = 0; j < dims->x; j++){
|
||||||
|
if (shape[i][j] == 1 && block_count < 4) {
|
||||||
|
blocks[block_count].x = j - origin->x;
|
||||||
|
blocks[block_count].y = i - origin->y;
|
||||||
|
block_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort blocks by y, then by x
|
||||||
|
void sort_blocks(Vector2* blocks){
|
||||||
|
for(int i = 0; i < 4; i++){
|
||||||
|
for(int j = i + 1; j < 4; j++){
|
||||||
|
if(blocks[j].y < blocks[i].y || (blocks[j].y == blocks[i].y && blocks[j].x < blocks[i].x)){
|
||||||
|
Vector2 tmp = blocks[i];
|
||||||
|
blocks[i] = blocks[j];
|
||||||
|
blocks[j] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 find_topleftmost_block_from_buffer(){
|
||||||
|
for (int i = 0; i < BOARD_HEIGHT + PIECE_BUFFER_OFFSET; i++){
|
||||||
|
for (int j = 0; j < BOARD_WIDTH; j++){
|
||||||
|
if(piece_mask[i][j]){
|
||||||
|
return (Vector2) {(float)j,(float)i};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void game_tick(){
|
||||||
|
if(piece_tick()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
place_piece();
|
||||||
|
zero_piece_mask();
|
||||||
|
populate_board_mask();
|
||||||
|
spawn_piece();
|
||||||
|
}
|
||||||
|
|
||||||
|
Color resolve_color(unsigned char colorValue){
|
||||||
|
switch(colorValue){
|
||||||
|
case PC_CYAN: return (Color) {0x00, 0xFF, 0xFF, 0xFF};
|
||||||
|
case PC_YELLOW: return (Color) {0xFF, 0xFF, 0x00, 0xFF};
|
||||||
|
case PC_PURPLE: return (Color) {0x80, 0x00, 0x80, 0xFF};
|
||||||
|
case PC_GREEN: return (Color) {0x00, 0xFF, 0x00, 0xFF};
|
||||||
|
case PC_RED: return (Color) {0xFF, 0x00, 0x00, 0xFF};
|
||||||
|
case PC_BLUE: return (Color) {0x00, 0x00, 0xFF, 0xFF};
|
||||||
|
case PC_ORANGE: return (Color) {0xFF, 0xA5, 0x00, 0xFF};
|
||||||
|
default: return (Color) {0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugDraw(int x, int y, Color color){
|
||||||
|
#ifndef NDEBUG
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
DrawRectangle(x * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, y * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, BLOCK_SIZE, BLOCK_SIZE, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSecondWindow(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(){
|
||||||
|
ClearBackground(RAYWHITE);
|
||||||
|
for(int i = 0; i < BOARD_HEIGHT; i++){
|
||||||
|
for(int j = 0; j < BOARD_WIDTH; j++){
|
||||||
|
if(piece_mask[i+PIECE_BUFFER_OFFSET][j]){
|
||||||
|
unsigned char pieceColorValue = current_piece->color;
|
||||||
|
Color drawColor = resolve_color(pieceColorValue);
|
||||||
|
DrawRectangle(j * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, i * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, BLOCK_SIZE, BLOCK_SIZE, drawColor);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(board[i][j] != 0){
|
||||||
|
unsigned char boardColorValue = board[i][j];
|
||||||
|
Color drawColor = resolve_color(boardColorValue);
|
||||||
|
DrawRectangle(j * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, i * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, BLOCK_SIZE, BLOCK_SIZE, drawColor);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// background
|
||||||
|
DrawRectangle(j * GRID_SCREEN_PIXELS, i * GRID_SCREEN_PIXELS, GRID_SCREEN_PIXELS, GRID_SCREEN_PIXELS, COLOR_GRID_FG);
|
||||||
|
DrawRectangle(j * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, i * GRID_SCREEN_PIXELS + 1 * PIXEL_SCALE, BLOCK_SIZE, BLOCK_SIZE, COLOR_GRID_BG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int milis_elapsed = 0;
|
||||||
|
int next_tick = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void move_piece_left(){
|
||||||
|
// Perform checks
|
||||||
|
for(int iter_y = 0; iter_y < BOARD_HEIGHT + PIECE_BUFFER_OFFSET; iter_y++){
|
||||||
|
if(piece_mask[iter_y][0]){
|
||||||
|
return; // piece would go out of bounds
|
||||||
|
}
|
||||||
|
for(int iter_x = 0; iter_x < BOARD_WIDTH; iter_x++){
|
||||||
|
bool board_bit = board_mask[iter_y-PIECE_BUFFER_OFFSET][iter_x - 1];
|
||||||
|
bool piece_bit = piece_mask[iter_y][iter_x];
|
||||||
|
if(board_bit && piece_bit){
|
||||||
|
return; // collision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Move Piece
|
||||||
|
for(int iter_x = 0; iter_x < BOARD_WIDTH; iter_x++){
|
||||||
|
for(int iter_y = 0; iter_y < BOARD_HEIGHT + PIECE_BUFFER_OFFSET; iter_y++){
|
||||||
|
if(piece_mask[iter_y][iter_x]){
|
||||||
|
piece_mask[iter_y][iter_x-1] = 1;
|
||||||
|
piece_mask[iter_y][iter_x] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_piece_right(){
|
||||||
|
// Perform checks
|
||||||
|
for(int iter_x = 0; iter_x < BOARD_HEIGHT + PIECE_BUFFER_OFFSET; iter_x++){
|
||||||
|
if(piece_mask[iter_x][BOARD_WIDTH - 1]){
|
||||||
|
return; // piece would go out of bounds
|
||||||
|
}
|
||||||
|
for(int iter_y = 0; iter_y < BOARD_HEIGHT + PIECE_BUFFER_OFFSET; iter_y++){
|
||||||
|
bool board_bit = board_mask[iter_y - PIECE_BUFFER_OFFSET][iter_x+1];
|
||||||
|
bool piece_bit = piece_mask[iter_y][iter_x];
|
||||||
|
if(board_bit && piece_bit){
|
||||||
|
return; // collision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Move piece
|
||||||
|
for(int j = BOARD_WIDTH - 1; j >= 0; j--){
|
||||||
|
for(int i = 0; i < BOARD_HEIGHT + PIECE_BUFFER_OFFSET; i++){
|
||||||
|
if(piece_mask[i][j]){
|
||||||
|
int new_x = j + 1;
|
||||||
|
int new_y = i;
|
||||||
|
if(board_mask[new_y - PIECE_BUFFER_OFFSET][new_x]){
|
||||||
|
return; // collision
|
||||||
|
}
|
||||||
|
piece_mask[i][j+1] = piece_mask[i][j];
|
||||||
|
piece_mask[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(){
|
||||||
|
bool accelerate = 0;
|
||||||
|
int accel_tick_time = 75;
|
||||||
|
// Update game state
|
||||||
|
if (IsKeyPressed(KEY_W)) {
|
||||||
|
// Rotate the current piece
|
||||||
|
turn_piece(true);
|
||||||
|
}
|
||||||
|
if (IsKeyPressed(KEY_A)) {
|
||||||
|
// Move piece left
|
||||||
|
move_piece_left();
|
||||||
|
}
|
||||||
|
if (IsKeyPressed(KEY_D)) {
|
||||||
|
// Move piece right
|
||||||
|
move_piece_right();
|
||||||
|
}
|
||||||
|
if (IsKeyDown(KEY_S)) {
|
||||||
|
// Accelerate piece down
|
||||||
|
accelerate = 1;
|
||||||
|
if (next_tick > milis_elapsed + accel_tick_time)
|
||||||
|
{
|
||||||
|
game_tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(milis_elapsed > next_tick){
|
||||||
|
game_tick();
|
||||||
|
next_tick = milis_elapsed + (accelerate ? accel_tick_time : 1000);
|
||||||
|
}
|
||||||
|
milis_elapsed += GetFrameTime() * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2* get_shape_dimensions(Piece* piece){
|
||||||
|
static Vector2 dims;
|
||||||
|
dims = piece->dims;
|
||||||
|
return &dims;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function to create 2D array from 1D data
|
||||||
|
int** create_shape_from_array(int rows, int cols, int* data) {
|
||||||
|
int** shape = malloc(rows * sizeof(int*));
|
||||||
|
for(int i = 0; i < rows; i++) {
|
||||||
|
shape[i] = malloc(cols * sizeof(int));
|
||||||
|
for(int j = 0; j < cols; j++) {
|
||||||
|
shape[i][j] = data[i * cols + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_shape(int** shape, int rows) {
|
||||||
|
if(shape) {
|
||||||
|
for(int i = 0; i < rows; i++) {
|
||||||
|
free(shape[i]);
|
||||||
|
}
|
||||||
|
free(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
174
tetris.h
Normal file
174
tetris.h
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "raylib.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PC_EMPTY = 0,
|
||||||
|
PC_CYAN = 1,
|
||||||
|
PC_BLUE = 3,
|
||||||
|
PC_ORANGE = 4,
|
||||||
|
PC_YELLOW = 5,
|
||||||
|
PC_GREEN = 6,
|
||||||
|
PC_PURPLE = 7,
|
||||||
|
PC_RED = 8
|
||||||
|
} ColorCode;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int** shape;
|
||||||
|
bool has_origin;
|
||||||
|
Vector2 dims;
|
||||||
|
Vector2 origin;
|
||||||
|
char color;
|
||||||
|
} Piece;
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function to create shape from static array
|
||||||
|
int** create_shape_from_array(int rows, int cols, int* data);
|
||||||
|
void free_shape(int** shape, int rows);
|
||||||
|
|
||||||
|
#define T_PIECE (Piece) { \
|
||||||
|
.shape = create_shape_from_array(2, 3, (int[]){ \
|
||||||
|
0,1,0, \
|
||||||
|
1,1,1}), \
|
||||||
|
.has_origin = true, \
|
||||||
|
.dims = (Vector2) {3, 2}, \
|
||||||
|
.origin = (Vector2) {1, 1}, \
|
||||||
|
.color = PC_PURPLE \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define O_PIECE (Piece) { \
|
||||||
|
.shape = create_shape_from_array(2, 2, (int[]){ \
|
||||||
|
1,1, \
|
||||||
|
1,1}), \
|
||||||
|
.has_origin = false, \
|
||||||
|
.dims = (Vector2) {2, 2}, \
|
||||||
|
.origin = (Vector2) {0, 0}, \
|
||||||
|
.color = PC_YELLOW \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Z_PIECE (Piece) { \
|
||||||
|
.shape = create_shape_from_array(2, 3, (int[]){ \
|
||||||
|
1,1,0, \
|
||||||
|
0,1,1}), \
|
||||||
|
.has_origin = true, \
|
||||||
|
.dims = (Vector2) {3, 2}, \
|
||||||
|
.origin = (Vector2) {1, 1}, \
|
||||||
|
.color = PC_RED \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define S_PIECE (Piece) { \
|
||||||
|
.shape = create_shape_from_array(2, 3, (int[]){ \
|
||||||
|
0,1,1, \
|
||||||
|
1,1,0}), \
|
||||||
|
.has_origin = true, \
|
||||||
|
.dims = (Vector2) {3, 2}, \
|
||||||
|
.origin = (Vector2) {1, 1}, \
|
||||||
|
.color = PC_GREEN \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define I_PIECE (Piece) { \
|
||||||
|
.shape = create_shape_from_array(4, 1, (int[]){ \
|
||||||
|
1, \
|
||||||
|
1, \
|
||||||
|
1, \
|
||||||
|
1}), \
|
||||||
|
.has_origin = true, \
|
||||||
|
.dims = (Vector2) {1, 4}, \
|
||||||
|
.origin = (Vector2) {0, 2}, \
|
||||||
|
.color = PC_CYAN \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define J_PIECE (Piece) { \
|
||||||
|
.shape = create_shape_from_array(2, 3, (int[]){ \
|
||||||
|
1,0,0, \
|
||||||
|
1,1,1}), \
|
||||||
|
.has_origin = true, \
|
||||||
|
.dims = (Vector2) {3, 2}, \
|
||||||
|
.origin = (Vector2) {1, 1}, \
|
||||||
|
.color = PC_BLUE \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define L_PIECE (Piece) { \
|
||||||
|
.shape = create_shape_from_array(2, 3, (int[]){ \
|
||||||
|
0,0,1, \
|
||||||
|
1,1,1}), \
|
||||||
|
.has_origin = true, \
|
||||||
|
.dims = (Vector2) {3, 2}, \
|
||||||
|
.origin = (Vector2) {1, 1}, \
|
||||||
|
.color = PC_ORANGE \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COLOR_GRID_BG (Color) { 0x00, 0x00, 0x00, 0xff}
|
||||||
|
#define COLOR_GRID_FG (Color) { 0xD0, 0xD0, 0xD0, 0xff}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define BOARD_WIDTH 10
|
||||||
|
#define BOARD_HEIGHT 20
|
||||||
|
|
||||||
|
#define PIECE_BUFFER_OFFSET 4
|
||||||
|
|
||||||
|
#define BORDERBUFFER_WIDTH 1
|
||||||
|
#define BORDERBUFFER_HEIGHT 1
|
||||||
|
|
||||||
|
#define TOTAL_WIDTH (BOARD_WIDTH + 2 * BORDERBUFFER_WIDTH)
|
||||||
|
#define TOTAL_HEIGHT (BOARD_HEIGHT + 2 * BORDERBUFFER_HEIGHT + PIECE_BUFFER_OFFSET)
|
||||||
|
#define GRID_BITS (TOTAL_WIDTH * TOTAL_HEIGHT)
|
||||||
|
|
||||||
|
#define GRID_WORDS ((GRID_BITS + 31) / 32)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t bits[GRID_WORDS];
|
||||||
|
} bitgrid_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define PIXEL_SCALE 8
|
||||||
|
#define BLOCK_SIZE (4 * PIXEL_SCALE)
|
||||||
|
#define GRID_SCREEN_PIXELS (BLOCK_SIZE + 2 * PIXEL_SCALE)
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} IntVector2;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
|
||||||
|
} BoardBits;
|
||||||
|
|
||||||
|
|
||||||
|
// Function prototypes
|
||||||
|
Color resolve_color(unsigned char colorValue);
|
||||||
|
void zero_board();
|
||||||
|
void zero_board_mask();
|
||||||
|
void zero_piece_mask();
|
||||||
|
void populate_board_mask();
|
||||||
|
bool next_tick_valid();
|
||||||
|
bool piece_tick();
|
||||||
|
void place_piece();
|
||||||
|
void spawn_piece();
|
||||||
|
void turn_piece(bool clockwise);
|
||||||
|
void game_tick();
|
||||||
|
void debugDraw(int x, int y, Color color);
|
||||||
|
void debug_draw_blocks(Vector2 block_vecs[], Color color);
|
||||||
|
void debug_draw_blocks_on_axis(Vector2 block_vecs[], Color color);
|
||||||
|
void draw();
|
||||||
|
void update();
|
||||||
|
void init_game();
|
||||||
|
void init_shapes();
|
||||||
|
void cleanup_shapes();
|
||||||
|
void get_vecs_from_shape(Piece* cpiece, Vector2* blocks);
|
||||||
|
void sort_blocks(Vector2* blocks);
|
||||||
|
Vector2 find_topleftmost_block_from_buffer();
|
||||||
|
Vector2 get_origin_offset();
|
||||||
|
Vector2* get_shape_bounds();
|
||||||
|
Vector2* get_shape_dimensions(Piece* piece);
|
||||||
Loading…
x
Reference in New Issue
Block a user