Created
November 2, 2016 19:31
-
-
Save spaceexperiment/4d6b116ef577a29712593c41747bd092 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "SDL.h" | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
SDL_Window *window; | |
SDL_Renderer *renderer; | |
int WINDOW_WIDTH = 510; | |
int WINDOW_HEIGHT = 510; | |
int BLOCK_WIDTH = 30; | |
int BLOCKS_X = 17; | |
int BLOCKS_Y = 17; | |
int LEVEL[17][17]; | |
int SHAPES[5][8] = { | |
{ | |
0, 0, | |
1, 0, | |
2, 0, | |
3, 0 | |
}, | |
{ | |
0, 0, | |
1, 0, | |
1, 1, | |
2, 1 | |
}, | |
{ | |
0, 0, | |
1, 0, | |
2, 0, | |
2, 1 | |
}, | |
{ | |
0, 0, | |
1, 0, | |
0, 1, | |
1, 1 | |
}, | |
{ | |
0, 0, | |
1, 0, | |
2, 0, | |
1, 1 | |
} | |
}; | |
int max(int a, int b){ | |
if (a >= b){ | |
return a; | |
} | |
return b; | |
} | |
int min(int a, int b){ | |
if (a <= b){ | |
return a; | |
} | |
return b; | |
} | |
SDL_Window* create_window(){ | |
int posX = SDL_WINDOWPOS_CENTERED; | |
int posY = SDL_WINDOWPOS_CENTERED; | |
return SDL_CreateWindow( | |
"SDL Window", | |
posX, | |
posY, | |
WINDOW_WIDTH, | |
WINDOW_HEIGHT, | |
SDL_WINDOW_OPENGL | |
); | |
} | |
SDL_Renderer* create_renderer(SDL_Window *window){ | |
return SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); | |
// SDL_RENDERER_ACCELERATED | |
// SDL_RENDERER_SOFTWARE | |
} | |
void destroy_and_quit(SDL_Window *window, SDL_Renderer *renderer){ | |
SDL_DestroyRenderer(renderer); | |
SDL_DestroyWindow(window); | |
SDL_Quit(); | |
} | |
int input_quit(SDL_Event *event){ | |
SDL_PollEvent(event); | |
if (event->type == SDL_QUIT){ | |
printf("Quiting.\n"); | |
return 1; | |
} | |
return 0; | |
} | |
///////////////////////// LEVEL BLOCKS /////////////////// | |
void draw_level_blocks(SDL_Texture **level_texture){ | |
SDL_Surface *surface; | |
SDL_Rect r; | |
r.w = 1; | |
r.h = 1; | |
r.x = 0; | |
r.y = 0; | |
surface = SDL_CreateRGBSurface(0, 17, 17, 32, 0, 0, 0, 250); | |
for (int y = 0; y < 17; y++) { | |
for (int x = 0; x < 17; x++){ | |
if (LEVEL[y][x] == 1){ | |
r.x = x; | |
r.y = y; | |
SDL_FillRect(surface, &r, SDL_MapRGB(surface->format, 250, 0, 0)); | |
} | |
} | |
} | |
*level_texture = SDL_CreateTextureFromSurface(renderer, surface); | |
} | |
void clear_line(int y){ | |
for (int i = y; i >= 0; i--){ | |
for (int x = 0; x < 17; x++) { | |
if (i == 0){ | |
LEVEL[i][x] = 0; | |
} else { | |
LEVEL[i][x] = LEVEL[i-1][x]; | |
} | |
} | |
} | |
} | |
int get_completed_line_pos(){ | |
for (int y = 0; y < 17; y++) { | |
for (int x = 0; x < 17; x++){ | |
if (x == 16 && LEVEL[y][x] == 1){ | |
return y; | |
} else { | |
if (LEVEL[y][x] != 1){ | |
break; | |
} | |
} | |
} | |
} | |
return -1; | |
} | |
void clear_lines(){ | |
int y = get_completed_line_pos(); | |
while(y >= 0){ | |
clear_line(y); | |
y = get_completed_line_pos(); | |
} | |
} | |
///////////////////////// END LEVEL BLOCKS /////////////////// | |
///////////////////////// SHAPES /////////////////// | |
struct Shape { | |
SDL_Texture *texture; | |
SDL_Rect *rect; | |
int blocks_x; | |
int blocks_y; | |
double pos_x; | |
double pos_y; | |
// a pair of x and y for every block in shape relative to shape | |
// each shape has 4 blocks | |
int blocks_position[8]; | |
}; | |
void create_shape(struct Shape *shape, int pos_x, int pos_y){ | |
SDL_Surface *surface; | |
SDL_Rect r, *rect; | |
rect = malloc(sizeof(struct SDL_Rect)); | |
r.w = 1; | |
r.h = 1; | |
r.x = 0; | |
r.y = 0; | |
int y, x; | |
surface = SDL_CreateRGBSurface(0, shape->blocks_x, shape->blocks_y, 32, 0, 0, 0, 0); | |
for (int i = 0; i < 8; i += 2) { | |
r.x = shape->blocks_position[i]; | |
r.y = shape->blocks_position[i+1]; | |
SDL_FillRect(surface, &r, SDL_MapRGB(surface->format, 250, 0, 0)); | |
} | |
shape->pos_x = pos_x; | |
shape->pos_y = pos_y; | |
rect->x = shape->pos_x; | |
rect->y = shape->pos_y; | |
rect->w = BLOCK_WIDTH * shape->blocks_x; | |
rect->h = BLOCK_WIDTH * shape->blocks_y; | |
shape->texture = SDL_CreateTextureFromSurface(renderer, surface); | |
shape->rect = rect; | |
SDL_FreeSurface(surface); | |
} | |
void set_blocks_x_y(struct Shape *shape, int blocks_position[]){ | |
shape->blocks_x = 0; | |
shape->blocks_y = 0; | |
for (int x = 0; x < 8; x += 2) { | |
shape->blocks_x = max(blocks_position[x] + 1, shape->blocks_x); | |
shape->blocks_y = max(blocks_position[x+1] + 1, shape->blocks_y); | |
} | |
} | |
void free_shape(struct Shape *shape){ | |
SDL_DestroyTexture(shape->texture); | |
free(shape->rect); | |
} | |
void get_new_shape(struct Shape *shape){ | |
int r = rand() % 5; | |
set_blocks_x_y(shape, SHAPES[r]); | |
memcpy(shape->blocks_position, SHAPES[r], sizeof(int) * 8); | |
int pos_x = rand() % (WINDOW_WIDTH / BLOCK_WIDTH - shape->blocks_x + 1) * BLOCK_WIDTH; | |
int pos_y = 0; | |
create_shape(shape, pos_x, pos_y); | |
} | |
void make_non_negative(int *new_blocks){ | |
int i; | |
int min_x = 0; | |
int min_y = 0; | |
for (i = 0; i < 8; i += 2){ | |
min_x = min(new_blocks[i], min_x); | |
min_y = min(new_blocks[i+1], min_y); | |
} | |
for (int i = 0; i < 8; i += 2){ | |
if (min_x < 0){ | |
new_blocks[i] += -1 * min_x; | |
} | |
if (min_y < 0){ | |
new_blocks[i+1] += -1 * min_y; | |
} | |
} | |
} | |
int *rotate(int blocks_position[]){ | |
int *new_blocks; | |
new_blocks = malloc(8 * sizeof(int)); | |
// *(&new_blocks + 5) == new_blocks[5] | |
new_blocks[0] = blocks_position[0]; | |
new_blocks[1] = blocks_position[1]; | |
int x, y; | |
for (int i = 2; i < 8; i += 2){ | |
x = blocks_position[0]; | |
y = blocks_position[1]; | |
int new_x = x + (y - blocks_position[i+1]); | |
int new_y = y + -1 * (x - blocks_position[i]); | |
new_blocks[i] = new_x; | |
new_blocks[i+1] = new_y; | |
printf("x: %i, y: %i\n", blocks_position[i], blocks_position[i+1]); | |
printf("x: %i, y: %i\n\n", new_blocks[i], new_blocks[i+1]); | |
} | |
make_non_negative(new_blocks); | |
return new_blocks; | |
} | |
void rotate_shape(struct Shape *shape){ | |
int *new_blocks; | |
new_blocks = rotate(shape->blocks_position); | |
free_shape(shape); | |
set_blocks_x_y(shape, new_blocks); | |
memcpy(shape->blocks_position, new_blocks, sizeof(int) * 8); | |
create_shape(shape, shape->pos_x, shape->pos_y); | |
free(new_blocks); | |
} | |
///////////////////////// END SHAPES /////////////////// | |
double get_time_elapsed(clock_t t_start, clock_t t_now){ | |
double time_diff = (double)(t_now - t_start) / CLOCKS_PER_SEC; | |
return time_diff; | |
} | |
void freeze_shape(struct Shape *shape){ | |
int x; | |
int y; | |
for (int i = 0; i < 8; i += 2){ | |
x = shape->rect->x / BLOCK_WIDTH + shape->blocks_position[i]; | |
y = shape->rect->y / BLOCK_WIDTH + shape->blocks_position[i+1]; | |
LEVEL[y][x] = 1; | |
} | |
} | |
int check_y_collision(struct Shape *shape){ | |
int x; | |
int y; | |
for (int i = 0; i < 8; i += 2){ | |
x = shape->rect->x / BLOCK_WIDTH + shape->blocks_position[i]; | |
y = shape->rect->y / BLOCK_WIDTH + shape->blocks_position[i+1]; | |
if (LEVEL[y+1][x] == 1 || y == 16){ | |
return 1; | |
} | |
} | |
return 0; | |
} | |
int check_x_collision(struct Shape *shape, int x_offset){ | |
int x; | |
int y; | |
for (int i = 0; i < 8; i += 2){ | |
x = shape->rect->x / BLOCK_WIDTH + shape->blocks_position[i]; | |
y = shape->rect->y / BLOCK_WIDTH + shape->blocks_position[i+1]; | |
if (LEVEL[y][x + x_offset] == 1){ | |
return 1; | |
} | |
} | |
return 0; | |
} | |
int is_game_lost(){ | |
for (int i = 0; i < 17; i++){ | |
if (LEVEL[0][i] == 1){ | |
return 1; | |
} | |
} | |
return 0; | |
} | |
void clear_level(){ | |
for (int y = 0; y < 17; y++){ | |
for (int x = 0; x < 17; x++) { | |
LEVEL[y][x] = 0; | |
} | |
} | |
} | |
///////////////////////// SHAPE MOVES /////////////////// | |
void move_down(double seconds_elapsed, struct Shape *shape){ | |
// shape->pos_y = shape->pos_y + (100 * seconds_elapsed); | |
// shape->rect->y = shape->pos_y; | |
static clock_t last_move = 0; | |
if (get_time_elapsed(last_move, clock()) >= 0.2){ | |
shape->pos_y = shape->pos_y + BLOCK_WIDTH; | |
shape->rect->y = shape->pos_y; | |
last_move = clock(); | |
} | |
} | |
void move_right(struct Shape *shape){ | |
static clock_t last_keypress = 0; | |
if (get_time_elapsed(last_keypress, clock()) > 0.1){ | |
if (shape->pos_x < WINDOW_WIDTH - (BLOCK_WIDTH * shape->blocks_x)){ | |
if (check_x_collision(shape, 1)){return;} | |
shape->pos_x = shape->pos_x + BLOCK_WIDTH; | |
shape->rect->x = shape->pos_x; | |
last_keypress = clock(); | |
} | |
} | |
} | |
void move_left(struct Shape *shape){ | |
static clock_t last_keypress = 0; | |
if (get_time_elapsed(last_keypress, clock()) > 0.1){ | |
if (shape->pos_x > 0 && !check_x_collision(shape, -1)){ | |
shape->pos_x = shape->pos_x - BLOCK_WIDTH; | |
shape->rect->x = shape->pos_x; | |
last_keypress = clock(); | |
} | |
} | |
} | |
///////////////////////// END SHAPE MOVES //////////////// | |
void draw(struct Shape *shape, SDL_Texture *level_texture){ | |
SDL_Rect r; | |
r.w = BLOCK_WIDTH * 17; | |
r.h = BLOCK_WIDTH * 17; | |
r.x = 0; | |
r.y = 0; | |
// SDL_SetRenderDrawColor(renderer, 0x22, 0x22, 0x22, 0x00); | |
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00); | |
SDL_RenderClear(renderer); | |
SDL_RenderCopy(renderer, level_texture, NULL, &r); | |
SDL_RenderCopy(renderer, shape->texture, NULL, shape->rect); | |
SDL_RenderPresent(renderer); | |
} | |
void body(){ | |
SDL_Event event; | |
struct Shape *shape; | |
SDL_Texture *level_texture; | |
draw_level_blocks(&level_texture); | |
shape = malloc(sizeof(struct Shape)); | |
get_new_shape(shape); | |
clock_t time, time_now, last_keypress; | |
double seconds_elapsed; | |
time = clock(); | |
while (1) { | |
time_now = clock(); | |
seconds_elapsed = get_time_elapsed(time, time_now); | |
time = time_now; | |
// if (input_quit(&event)){break;} | |
SDL_PollEvent(&event); | |
if (event.type == SDL_QUIT){ | |
printf("Quiting.\n"); | |
break; | |
} | |
if (check_y_collision(shape)){ | |
// printf("collision at x %i y %i\n", shape->rect->x, shape->rect->y); | |
freeze_shape(shape); | |
clear_lines(); | |
if (is_game_lost()){ | |
clear_level(); | |
} | |
draw_level_blocks(&level_texture); | |
free_shape(shape); | |
get_new_shape(shape); | |
} | |
if (event.type == SDL_KEYDOWN){ | |
if (event.key.keysym.scancode == SDL_SCANCODE_LEFT){ | |
move_left(shape); | |
} else if (event.key.keysym.scancode == SDL_SCANCODE_RIGHT){ | |
move_right(shape); | |
} else if (event.key.keysym.scancode == SDL_SCANCODE_SPACE){ | |
rotate_shape(shape); | |
} | |
} | |
move_down(seconds_elapsed, shape); | |
draw(shape, level_texture); | |
} | |
} | |
int main(int argc, char const *argv[]) { | |
// random seed | |
srand(time(NULL) + clock()); | |
// initialize SDL | |
if (SDL_Init(SDL_INIT_VIDEO) == 0){ | |
window = create_window(); | |
renderer = create_renderer(window); | |
body(); | |
destroy_and_quit(window, renderer); | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment