From 58bef85206c7cce153400e51b247e2476e9e65a4 Mon Sep 17 00:00:00 2001 From: David Phillips Date: Tue, 12 Jan 2016 20:41:56 +1300 Subject: Initial commit of rough-arse Tetris --- .gitignore | 2 + Makefile | 15 ++++ README.md | 3 + colour.h | 5 ++ config.mk | 2 + plot.c | 103 +++++++++++++++++++++++ plot.h | 14 ++++ tetris.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tetromino.h | 207 +++++++++++++++++++++++++++++++++++++++++++++++ window.c | 44 ++++++++++ window.h | 20 +++++ 11 files changed, 680 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 colour.h create mode 100644 config.mk create mode 100644 plot.c create mode 100644 plot.h create mode 100644 tetris.c create mode 100644 tetromino.h create mode 100644 window.c create mode 100644 window.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..213c075 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tetris +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..545347b --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +include config.mk + +all: tetris + +tetris: tetris.o plot.o + $(CC) -o $@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) -c -o $@ $< $(CFLAGS) + +clean: + rm -f tetris + find -name "*.o" -delete + +.PHONY: all clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..2ec5c1f --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +What? +===== +Tetris. diff --git a/colour.h b/colour.h new file mode 100644 index 0000000..fc25ac9 --- /dev/null +++ b/colour.h @@ -0,0 +1,5 @@ +struct colour { + uint8_t r; + uint8_t g; + uint8_t b; +}; diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..d3875ba --- /dev/null +++ b/config.mk @@ -0,0 +1,2 @@ +CFLAGS += -I/usr/include/SDL2 -Wall -Wextra -Werror +LDFLAGS += -lm -lsqlite3 -lSDL2 diff --git a/plot.c b/plot.c new file mode 100644 index 0000000..6a579d6 --- /dev/null +++ b/plot.c @@ -0,0 +1,103 @@ +#include + +#include "colour.h" +#include "plot.h" + +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; + +void plot_update() +{ + SDL_RenderPresent(renderer); +} + +void plot_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height, struct colour *c) +{ + SDL_Rect rect; + + SDL_SetRenderDrawColor(renderer, c->r, c->g, c->b, 255); + + rect.x = x; + rect.y = y; + rect.w = width; + rect.h = height; + + SDL_RenderFillRect(renderer, &rect); +} + +void plot_cell(unsigned int x, unsigned int y, struct colour *c) +{ + plot_rect( + x*CELL_SIZE+(x-1)*BORDER_THICKNESS, + y*CELL_SIZE+(y-1)*BORDER_THICKNESS, + CELL_SIZE, + CELL_SIZE, + c + ); +} + +void plot_cell_borders() +{ + int i, j; + + struct colour col = {.r = 0, .g = 0, .b = 0}; + + for (i = 1; i < WIDTH_CELLS; i++) + { + j = i*CELL_SIZE + (i-1)*BORDER_THICKNESS; + plot_rect( + j, 0, + BORDER_THICKNESS, HEIGHT_PIXELS, + &col); + } + + for (i = 1; i < HEIGHT_CELLS; i++) + { + j = i*CELL_SIZE + (i-1)*BORDER_THICKNESS; + plot_rect( + 0, j, + WIDTH_PIXELS, BORDER_THICKNESS, + &col); + } + +} + + +int plot_init() +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + fprintf(stderr, "Failed to init SDL video: %s\n", SDL_GetError()); + return 1; + } + + window = SDL_CreateWindow( + "Some title", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + WIDTH_PIXELS, + HEIGHT_PIXELS, + SDL_WINDOW_SHOWN + ); + + if (window == NULL) + { + fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); + return 1; + } + + renderer = SDL_CreateRenderer(window, 0, 0); + if (renderer == NULL) + { + fprintf(stderr, "Failed to get window renderer: %s\n", SDL_GetError()); + return 1; + } + + /* blank out the background with gray */ + SDL_SetRenderDrawColor(renderer, 0x33, 0x33, 0x33, 0xFF); + SDL_RenderFillRect(renderer, NULL); + + plot_cell_borders(); + + return 0; +} diff --git a/plot.h b/plot.h new file mode 100644 index 0000000..836c377 --- /dev/null +++ b/plot.h @@ -0,0 +1,14 @@ +void plot_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height, struct colour *c); +void plot_cell(unsigned int x, unsigned int y, struct colour *c); +void plot_cell_borders(); +int plot_init(); +void plot_update(); + +#define CELL_SIZE 25 +#define BORDER_THICKNESS 2 +#define WIDTH_CELLS 10 +#define HEIGHT_CELLS 20 + +#define WIDTH_PIXELS (WIDTH_CELLS * CELL_SIZE + BORDER_THICKNESS * (WIDTH_CELLS-1)) +#define HEIGHT_PIXELS (HEIGHT_CELLS * CELL_SIZE + BORDER_THICKNESS * (HEIGHT_CELLS-1)) + diff --git a/tetris.c b/tetris.c new file mode 100644 index 0000000..3b6364a --- /dev/null +++ b/tetris.c @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include + +#include "colour.h" +#include "tetromino.h" +#include "plot.h" + +#define TETROMINO_WIDTH 4 +#define TETROMINO_HEIGHT 4 +#define TETROMINO_AREA (TETROMINO_HEIGHT*TETROMINO_WIDTH) + + +#define MIN(a,b) (abitmap)[px][py]) + (*board)[wx][wy] = piece->colour; +} + +Uint32 gravity_callback(Uint32 interval, void *param) +{ + (void)param; /* solves unused parameter warn+error */ + SDL_Event e; + SDL_UserEvent ue; + ue.type = SDL_USEREVENT; + ue.code = 0; + ue.data1 = 0; + ue.data2 = 0; + + e.type = SDL_USEREVENT; + e.user = ue; + + SDL_PushEvent(&e); + return interval; +} + +int main() +{ + srand(time(NULL)); + plot_init(); + main_loop(); +} + + +int hit_floor(int x, int y, struct piece *held, struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS]) +{ + int px,py; + for (px = 0; px < 4; px++) + { + /* seek to first cell of column */ + py = 0; + while (py < 4 && (*held->bitmap)[px][py] == 0) + py++; + + /* column has no cells? no collision possible. NEXT! */ + if (py == 4) + continue; + + while (py < 4 && (*held->bitmap)[px][py]) + py++; + + if ( y + py >= HEIGHT_CELLS + || (*board)[x + px][y + py] != &(palette[0])) + return 1; + } + return 0; +} + +int hit_side(int x, int y, struct piece *held, struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS]) +{ + int px,py; + for (py = 0; py < 4; py++) + { + for (px = 0; px < 4; px++) + { + if ((*held->bitmap)[px][py] + && + ( x + px >= WIDTH_CELLS + || x + px < 0 + || (*board)[x + px][y + py] != &(palette[0]) + )) + return 1; + } + } + return 0; +} + +void update_bitmap(struct piece *held) +{ + held->bitmap = &(tetrominoes[0][held->type][held->rotation]); +} + +void new_piece(struct piece *held) +{ + held->colour = &palette[rand() % 7 + 1]; + held->type = rand()%7; + held->rotation= rand()%4; + update_bitmap(held); +} + +void rotate(struct piece *held) +{ + held->rotation++; + if (held->rotation >= 4) + held->rotation -= 4; + + update_bitmap(held); +} + + +void clear_rows(struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS]) +{ + char row; + int x, y, x1, y1; + for (y = 0; y < HEIGHT_CELLS; y++) + { + row = 1; + for (x = 0; x < WIDTH_CELLS; x++) + { + if ((*board)[x][y] == &(palette[0])) + { + row = 0; + break; + } + } + if (!row) + continue; + + for (y1 = y; y1 > 0; y1--) + for (x1 = 0; x1 < WIDTH_CELLS; x1++) + (*board)[x1][y1] = (*board)[x1][y1-1]; + + for (x1 = 0; x1 < WIDTH_CELLS; x1++) + (*board)[x1][y1] = &(palette[0]); + } +} + +void main_loop() +{ + struct colour *board[WIDTH_CELLS][HEIGHT_CELLS]; + SDL_Event e = {0}; + bool running = false; + int x = 0; + int y = 0; + int last_x = 0; + int last_y = 1; + struct piece held; + new_piece(&held); + + for (y = 0; y < HEIGHT_CELLS; y++) + for (x = 0; x < WIDTH_CELLS; x++) + board[x][y] = &(palette[0]); + + running = true; + last_x = last_y = x = y = 0; + SDL_AddTimer(500, &gravity_callback, NULL); + char lockout; + while (running) + { + lockout = 0; + clear_rows(&board); + if (hit_side(x, y, &held, &board)) + { + x = last_x; + } + if (hit_floor(x, y, &held, &board)) + { + lockout = 1; + } + draw_board(&board); + draw_piece(x, y, held.colour, held.bitmap); + plot_update(); + while(SDL_PollEvent(&e)) + { + switch (e.type) + { + case SDL_USEREVENT: + if (lockout) { + drop_piece(x, y, &held, &board); + last_x = last_y = x = y = 0; + new_piece(&held); + lockout = 0; + } else { + last_y = y++; /* gravity */ + last_x = x; + } + break; + case SDL_QUIT: + fprintf(stderr, "quit\n"); + running = false; + break; + + case SDL_KEYDOWN: + switch (e.key.keysym.sym) + { + case SDLK_a: last_x = x--; break; + case SDLK_d: last_x = x++; break; + case SDLK_w: rotate(&held); break; + case SDLK_q: + running = false; + break; + } + break; + default: + break; + } + } + } +} diff --git a/tetromino.h b/tetromino.h new file mode 100644 index 0000000..c0a33f0 --- /dev/null +++ b/tetromino.h @@ -0,0 +1,207 @@ +#define TETROMINO_WIDTH 4 +#define TETROMINO_HEIGHT 4 +#define TETROMINO_AREA (TETROMINO_HEIGHT*TETROMINO_WIDTH) +/* +struct tetromino { + char name; + uint8_t r; + uint8_t g; + uint8_t b; + unsigned int width; + unsigned int height; + char data[4][16]; +};*/ + +struct piece +{ + struct colour *colour; + char (*bitmap)[4][4]; + int type; + int rotation; +}; + +char tetromino_I[4][4][4] = { + { + {0,0,0,0}, + {1,1,1,1}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,0,1,0}, + {0,0,1,0}, + {0,0,1,0}, + {0,0,1,0} + },{ + {0,0,0,0}, + {0,0,0,0}, + {1,1,1,1}, + {0,0,0,0} + },{ + {0,1,0,0}, + {0,1,0,0}, + {0,1,0,0}, + {0,1,0,0} + } +}; + + +char tetromino_J[4][4][4] = { + { + {1,0,0,0}, + {1,1,1,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,1,1,0}, + {0,1,0,0}, + {0,1,0,0}, + {0,0,0,0} + },{ + {0,0,0,0}, + {1,1,1,0}, + {0,0,1,0}, + {0,0,0,0} + },{ + {0,1,0,0}, + {0,1,0,0}, + {1,1,0,0}, + {0,0,0,0} + } +}; + + +char tetromino_L[4][4][4] = { + { + {0,0,1,0}, + {1,1,1,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,1,0,0}, + {0,1,0,0}, + {0,1,1,0}, + {0,0,0,0} + },{ + {0,0,0,0}, + {1,1,1,0}, + {1,0,0,0}, + {0,0,0,0} + },{ + {1,1,0,0}, + {0,1,0,0}, + {0,1,0,0}, + {0,0,0,0} + } +}; + + +char tetromino_O[4][4][4]= { + { + {0,1,1,0}, + {0,1,1,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,1,1,0}, + {0,1,1,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,1,1,0}, + {0,1,1,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,1,1,0}, + {0,1,1,0}, + {0,0,0,0}, + {0,0,0,0} + } +}; + + +char tetromino_S[4][4][4] = { + { + {0,1,1,0}, + {1,1,0,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,1,0,0}, + {0,1,1,0}, + {0,0,1,0}, + {0,0,0,0} + },{ + {0,0,0,0}, + {0,1,1,0}, + {1,1,0,0}, + {0,0,0,0} + },{ + {1,0,0,0}, + {1,1,0,0}, + {0,1,0,0}, + {0,0,0,0} + } +}; + + +char tetromino_T[4][4][4] = { + { + {1,1,1,0}, + {0,1,0,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,0,1,0}, + {0,1,1,0}, + {0,0,1,0}, + {0,0,0,0} + },{ + {0,0,0,0}, + {0,1,0,0}, + {1,1,1,0}, + {0,0,0,0} + },{ + {1,0,0,0}, + {1,1,0,0}, + {1,0,0,0}, + {0,0,0,0} + } +}; + +char tetromino_Z[4][4][4] = { + { + {1,1,0,0}, + {0,1,1,0}, + {0,0,0,0}, + {0,0,0,0} + },{ + {0,0,1,0}, + {0,1,1,0}, + {0,1,0,0}, + {0,0,0,0} + },{ + {0,0,0,0}, + {1,1,0,0}, + {0,1,1,0}, + {0,0,0,0} + },{ + {0,1,0,0}, + {1,1,0,0}, + {1,0,0,0}, + {0,0,0,0} + } +}; + + + + +char (*tetrominoes[])[4][4][4] = { + &tetromino_I, + &tetromino_J, + &tetromino_L, + &tetromino_O, + &tetromino_S, + &tetromino_T, + &tetromino_Z +}; diff --git a/window.c b/window.c new file mode 100644 index 0000000..2128f1c --- /dev/null +++ b/window.c @@ -0,0 +1,44 @@ +#include "window.h" + +#include + +int display_init(struct window *wobj) +{ + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) + { + fprintf(stderr,"Couldn't init SDL: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + + /* Create run-of-the-mill window at specified size */ + wobj->window = SDL_CreateWindow( + wobj->title, + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + wobj->width, wobj->height, + SDL_WINDOW_SHOWN + ); + if (wobj->window == NULL) + { + fprintf(stderr, "Couldn't create window: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + + /* Grab window surface */ + wobj->surface = SDL_GetWindowSurface(wobj->window); + if (wobj->surface == NULL) + { + fprintf(stderr, "Couldn't grab window surface: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + + /* Clear/blank surface with grey, and update it */ + SDL_FillRect(wobj->surface, NULL, SDL_MapRGB(wobj->surface->format, 0x33, 0x33, 0x33)); + SDL_UpdateWindowSurface(wobj->window); + return EXIT_SUCCESS; +} + +void display_stop(struct window *wobj) +{ + SDL_DestroyWindow(wobj->window); + SDL_Quit(); +} diff --git a/window.h b/window.h new file mode 100644 index 0000000..0c97b86 --- /dev/null +++ b/window.h @@ -0,0 +1,20 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include + +struct window { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Surface *surface; + unsigned int height; + unsigned int width; + char* title; +}; + +int display_init(struct window *wobj); +void display_stop(struct window *wobj); + + +#endif -- cgit v1.1