Skip to content

Instantly share code, notes, and snippets.

@spaceexperiment
Created November 2, 2016 19:31
Show Gist options
  • Save spaceexperiment/4d6b116ef577a29712593c41747bd092 to your computer and use it in GitHub Desktop.
Save spaceexperiment/4d6b116ef577a29712593c41747bd092 to your computer and use it in GitHub Desktop.
#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