Sign in to follow this  

Problem with tetris clone

This topic is 3930 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying ot make a tetris clone with SDL. I have only made very litle yet, but the first bug is a fact; sometimes draw_map() doesn't seem to write out the figure. It's about every fifth time this happening. The code look like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <SDL/SDL.h>
#include "atetris.h"

SDL_Surface *display_surface;
int map[HEIGHT][WIDTH];
Figure current_figure;
int figure_x, figure_y;

int main(int argc, char *argv[])
{
    SDL_Event event;
    
    init();
    current_figure = figures[nrand(0, 14)];
    place_figure_on_top();
    
    while (1) {
        if (SDL_PollEvent(&event) == 1) {
            if (event.type == SDL_QUIT) {
                break;
            }
        }
        draw_map();
    }
    terminate();
    debug();
    
    return 0;
}

void init(void)
{
    int i, j;
    
    if (SDL_Init(SDL_INIT_VIDEO) == -1) {
        fprintf(stderr, "Couldn't initialize SDL.\n");
    }
    display_surface = SDL_SetVideoMode(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE,
                                       0, SDL_ANYFORMAT);
    if (display_surface == NULL) {
        fprintf(stderr, "Could't set the video mode.\n");
    }
    for (i = 0; i < HEIGHT; i++) {
        for (j = 0; j < WIDTH; j++) {
            map[i][j] = NOTHING;
        }
    }
    srand((unsigned int) time((time_t *) NULL));
}

void terminate(void)
{
    SDL_Quit();
}

void draw_map(void)
{
    int i, j;
    SDL_Surface *block;
    SDL_Rect src_rect, dest_rect;
    
    for (i = 0; i < HEIGHT; i++) {
        for (j = 0; j < WIDTH; j++) {
            if (map[i][j] != NOTHING) {
                block = SDL_LoadBMP(block_images[map[i][j]]);
                src_rect.x = src_rect.y = 0;
                src_rect.w = src_rect.h = BLOCK_SIZE;
                dest_rect.x = j * BLOCK_SIZE;
                dest_rect.y = i * BLOCK_SIZE;
                dest_rect.w = dest_rect.h = BLOCK_SIZE;
                SDL_BlitSurface(block, &src_rect, display_surface, &dest_rect);
            }
        }
    }
    SDL_UpdateRect(display_surface, 0, 0, 0, 0);
}

void place_figure_on_top(void)
{
    int i, j;
    
    do {
        figure_x = nrand(0, WIDTH);
    }
    while (figure_x + current_figure.width > WIDTH - 1);
    figure_y = 0;
    
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            if (current_figure.pattern[i][j] != NOTHING) {
                map[i][j + figure_x] = current_figure.pattern[i][j];
            }
        }
    }
}

int nrand(int lower, int upper)
{
    int diff = upper - lower + 1;
    int a = rand() % diff + lower;
    
    return a;
}

void debug(void)
{
    int i, j;
    
    for (i = 0; i < HEIGHT; i++) {
        for (j = 0; j < WIDTH; j++) {
            printf("%d", map[i][j]);
        }
        putchar('\n');
    }
}

Share this post


Link to post
Share on other sites
OK... this is totally just a shot in the dark... I don't understand exactly what isn't drawing to the screen.

But you mention every 5th.


for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
if (current_figure.pattern[i][j] != NOTHING) {
map[i][j + figure_x] = current_figure.pattern[i][j];
}
}
}


This cycles through and execute 4 times. 0, 1, 2, 3. Maybe try i <= 4 and j <= 4?

Share this post


Link to post
Share on other sites
Do you realise that you are loading every image from disk multiple times every frame? Thats such a waste, try changing it so that images are loaded once. Or at least remember to SDL_FreeSurface() all those images ( that is one hell of a memory leak [smile] ).

After that I might try look harder at your drawing code. [grin]

Share this post


Link to post
Share on other sites
Quote:
Original post by Adam4444
OK, now I load every image at the beginning of the game and just blit the image I want. But still the same problem.


Try post your updated code, I will try running it. It *looks* right...

Also, by "fifth time", I assume you mean "every fifth frame" or something. But perhaps you mean every fifth map tile. Can you reword your problem, or perhaps post a screenshot of expected vs actual output?

Share this post


Link to post
Share on other sites
The code looks like this right now:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <SDL/SDL.h>
#include "atetris.h"

SDL_Surface *display_surface;
SDL_Surface *blocks[8];
SDL_TimerID timer;
int map[HEIGHT][WIDTH];
Figure current_figure;
int figure_x, figure_y;

int main(int argc, char *argv[])
{
SDL_Event event;

init();
current_figure = figures[nrand(0, 14)];
place_figure_on_top();
while (1) {
if (SDL_PollEvent(&event) == 1) {
if (event.type == SDL_QUIT) {
break;
}
if (event.type == SDL_USEREVENT && event.user.code == MOVE_FIGURE_DOWN) {
if (move_figure_down() == false) {
current_figure = figures[nrand(0, 14)];
place_figure_on_top();
}
}
}
draw_map();
}
terminate();
debug();

return 0;
}

void init(void)
{
int i, j;

if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
fprintf(stderr, "Couldn't initialize SDL.\n");
exit(1);
}
display_surface = SDL_SetVideoMode(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE,
0, SDL_ANYFORMAT);
if (display_surface == NULL) {
fprintf(stderr, "Could't set the video mode.\n");
exit(1);
}
for (i = 0; i < HEIGHT; i++) {
for (j = 0; j < WIDTH; j++) {
map[i][j] = NOTHING;
}
}
for (i = 0; i < 8; i++) {
blocks[i] = SDL_LoadBMP(block_images[i]);
}
timer = SDL_AddTimer(1000, do_move_figure_down, NULL);
srand((unsigned int) time((time_t *) NULL));
}

void terminate(void)
{
SDL_Quit();
}

void draw_map(void)
{
int i, j;
SDL_Surface *block;
SDL_Rect src_rect, dest_rect;

for (i = 0; i < HEIGHT; i++) {
for (j = 0; j < WIDTH; j++) {
src_rect.x = src_rect.y = 0;
src_rect.w = src_rect.h = BLOCK_SIZE;
dest_rect.x = j * BLOCK_SIZE;
dest_rect.y = i * BLOCK_SIZE;
dest_rect.w = dest_rect.h = BLOCK_SIZE;
SDL_BlitSurface(blocks[map[i][j]], &src_rect, display_surface, &dest_rect);
}
}
SDL_UpdateRect(display_surface, 0, 0, 0, 0);
}

void place_figure_on_top(void)
{
int i, j;

do {
figure_x = nrand(0, WIDTH);
}
while (figure_x + current_figure.width > WIDTH - 1);
figure_y = 0;

for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
if (current_figure.pattern[i][j] != NOTHING) {
map[i][j + figure_x] = current_figure.pattern[i][j];
}
}
}
}

bool move_figure_down(void)
{
int coordinats[4][2];
int coordinats_index = 0;
int i, j;

for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
if (map[i + figure_y][j + figure_x] > 0) {
coordinats[coordinats_index][0] = i + figure_y;
coordinats[coordinats_index][1] = j + figure_x;
coordinats_index++;
}
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
map[i + figure_y][j + figure_x] = 0;
}
}
for (i = 0; i < 4; i++) {
if (map[coordinats[i][0] + 1][coordinats[i][1]] == NOTHING) {
map[coordinats[i][0] + 1][coordinats[i][1]] = current_figure.color;
}
else {
map[coordinats[i][0]][coordinats[i][1]] = current_figure.color;
}
}
figure_y++;

return true;
}

Uint32 do_move_figure_down(Uint32 interval, void *param)
{
SDL_Event event;

event.type = SDL_USEREVENT;
event.user.code = MOVE_FIGURE_DOWN;
event.user.data1 = 0;
event.user.data2 = 0;
SDL_PushEvent(&event);

return interval;
}

int nrand(int lower, int upper)
{
int diff = upper - lower + 1;
int a = rand() % diff + lower;

return a;
}

void debug(void)
{
int i, j;

for (i = 0; i < HEIGHT; i++) {
for (j = 0; j < WIDTH; j++) {
printf("%d", map[i][j]);
}
putchar('\n');
}
}




And the header; atetris.h:
#ifndef GAME_H
#define GAME_H

#define WIDTH 10
#define HEIGHT 20
#define BLOCK_SIZE 20
#define COLOR_BLUE 1
#define COLOR_BROWN 2
#define COLOR_CYAN 3
#define COLOR_GREEN 4
#define COLOR_MAGENTA 5
#define COLOR_RED 6
#define COLOR_WHITE 7
#define MOVE_FIGURE_DOWN 8

typedef struct Figure_ {
int width;
int color;
int pattern[4][4];
} Figure;

void init(void);
void terminate(void);
void place_figure_on_top(void);
bool move_figure_down(void);
void draw_map(void);
Uint32 do_move_figure_down(Uint32 interval, void *param);
int nrand(int lower, int upper);
void debug(void);

const Figure figures[15] = {
{
2,
COLOR_BLUE,
{{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}}
},
{
4,
COLOR_BROWN,
{{0, 0, 0, 0},
{0, 0, 0, 0},
{2, 2, 2, 2},
{0, 0, 0, 0}}
},
{
1,
COLOR_BROWN,
{{0, 0, 2, 0},
{0, 0, 2, 0},
{0, 0, 2, 0},
{0, 0, 2, 0}}
},
{
3,
COLOR_CYAN,
{{0, 0, 0, 0},
{0, 3, 3, 0},
{3, 3, 0, 0},
{0, 0, 0, 0}}
},
{
2,
COLOR_CYAN,
{{0, 3, 0, 0},
{0, 3, 3, 0},
{0, 0, 3, 0},
{0, 0, 0, 0}}
},
{
3,
COLOR_GREEN,
{{0, 0, 0, 0},
{0, 4, 4, 0},
{0, 0, 4, 4},
{0, 0, 0, 0}}
},
{
2,
COLOR_GREEN,
{{0, 0, 4, 0},
{0, 4, 4, 0},
{0, 4, 0, 0},
{0, 0, 0, 0}}
},
{
2,
COLOR_MAGENTA,
{{0, 0, 0, 0},
{0, 0, 5, 0},
{0, 0, 5, 0},
{0, 5, 5, 0}}
},
{
3,
COLOR_MAGENTA,
{{0, 0, 0, 0},
{0, 5, 0, 0},
{0, 5, 5, 5},
{0, 0, 0, 0}}
},
{
2,
COLOR_RED,
{{0, 6, 0, 0},
{0, 6, 0, 0},
{0, 6, 6, 0},
{0, 0, 0, 0}}
},
{
3,
COLOR_RED,
{{0, 0, 0, 0},
{0, 6, 6, 6},
{0, 6, 0, 0},
{0, 0, 0, 0}}
},
{
3,
COLOR_WHITE,
{{0, 0, 0, 0},
{0, 7, 7, 7},
{0, 0, 7, 0},
{0, 0, 0, 0}}
},
{
2,
COLOR_WHITE,
{{0, 0, 7, 0},
{0, 7, 7, 0},
{0, 0, 7, 0},
{0, 0, 0, 0}}
},
{
3,
COLOR_WHITE,
{{0, 0, 0, 0},
{0, 0, 7, 0},
{0, 7, 7, 7},
{0, 0, 0, 0}}
},
{
2,
COLOR_WHITE,
{{0, 7, 0, 0},
{0, 7, 7, 0},
{0, 7, 0, 0},
{0, 0, 0, 0}}
}
};
const char *block_images[8] = {"media/block_empty.bmp",
"media/block_brown.bmp",
"media/block_cyan.bmp",
"media/block_green.bmp",
"media/block_magenta.bmp",
"media/block_red.bmp",
"media/block_white.bmp"};

#endif




Well, I'm so bad at explaining things, at least in english. But I meant about every fifth time I start the game draw_map() doesn't seems to draw anything.

Share this post


Link to post
Share on other sites
It seems to work for me (except when the piece falls off the edge of the screen your program crashed, but I can see that you have yet to implement that code).

Seeing as I don't have your image bitmaps, I made SDL_Surfaces in memory and filled them with a colour. So maybe the issue is with your images, I see no error checking where you load them ( check for NULL return values ).

If you wish to try the code I used and see if it still has the same problem on your machine, replace init() with this:

void init(void)
{
int i, j;
SDL_PixelFormat *format;
/* some random colours */
Uint32 colours[8] = {0x0,0xff,0xff00,0xff0000,0xffff,0xff00ff,0xffff00,0xffffff};

if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
fprintf(stderr, "Couldn't initialize SDL.\n");
exit(1);
}
display_surface = SDL_SetVideoMode(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE,
0, SDL_ANYFORMAT);
if (display_surface == NULL) {
fprintf(stderr, "Could't set the video mode.\n");
exit(1);
}
for (i = 0; i < HEIGHT; i++) {
for (j = 0; j < WIDTH; j++) {
map[i][j] = NOTHING;
}
}
format = display_surface->format;
for (i = 0; i < 8; i++) {
blocks[i] = SDL_CreateRGBSurface(0, BLOCK_SIZE, BLOCK_SIZE, 32,format->Rmask, format->Gmask, format->Bmask, format->Amask);
if( blocks[i] == NULL )
{
fprintf(stderr,"CreateRGBSurface() error: %s",SDL_GetError());
fflush(stderr);
exit(1);
}
SDL_FillRect(blocks[i],NULL,colours[i]);
}
timer = SDL_AddTimer(1000, do_move_figure_down, NULL);
srand((unsigned int) time((time_t *) NULL));
}


Share this post


Link to post
Share on other sites

This topic is 3930 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this