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