Search code examples
pythoncpygamesdl-2

Difference between pygame and SDL draw rect


I am trying to figure out what's the difference between pygame and SDL2 rectangle drawing. Here is my C code:

#include <SDL2/SDL.h>

const int WIDTH = 800;
const int HEIGHT = 600;

const int BOUNDARY_H[] = { 0, WIDTH };
const int BOUNDARY_V[] = { 0, HEIGHT };

typedef enum { false, true } bool;

typedef struct {
    SDL_Rect rect;
    SDL_Color color;
    float x_velocity;
    float y_velocity;
    float speed;
} Cube;

void bounce(Cube *cube) {
    if (cube->rect.x < BOUNDARY_H[0] || cube->rect.x + cube->rect.w > BOUNDARY_H[1])
        cube->x_velocity = -cube->x_velocity;

    if (cube->rect.y < BOUNDARY_V[0] || cube->rect.y + cube->rect.h > BOUNDARY_V[1])
        cube->y_velocity = -cube->y_velocity;
}

SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;

int main(int argc, char *argv[]) {
    SDL_Init(SDL_INIT_VIDEO);

    window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);

    Cube cube = { {0, 0, 100, 100}, {255, 0, 0, 255}, 5, 5, 5 };

    SDL_Event event;
    bool running = true;

    while (running) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT)
                running = false;
        }

        cube.rect.x += cube.x_velocity;
        cube.rect.y += cube.y_velocity;

        bounce(&cube);

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
        SDL_RenderClear(renderer);

        SDL_SetRenderDrawColor(renderer, cube.color.r, cube.color.g, cube.color.b, cube.color.a);
        SDL_RenderFillRect(renderer, &cube.rect);

        SDL_RenderPresent(renderer);
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();

    return 0;
}

and python code:

import math
import pygame as pg


WIDTH = 800
HEIGHT = 600

CENTER_X = WIDTH / 2
CENTER_Y = HEIGHT / 2

RED = (255, 0, 0)

BOUNDARY_H = (0, WIDTH)
BOUNDARY_V = (0, HEIGHT)


class Cube:
    def __init__(self, **kwargs):
        self.rect = kwargs.get('rect', pg.Rect(0, 0, 0, 0))
        self.color = kwargs.get('color', (0, 0, 0, 0))
        self._speed = 0
        self._x_velocity = 0
        self._y_velocity = 0

    @property
    def speed(self):
        return self._speed

    @speed.setter
    def speed(self, x):
        if math.isnan(x):
            raise ValueError('Is not a number')

        if x < 0:
            raise ValueError('Should be positive')

        self._speed = x

    @property
    def x_velocity(self):
        return self._x_velocity

    @x_velocity.setter
    def x_velocity(self, x):
        if math.isnan(x):
            raise ValueError('Is not a number')
        self._x_velocity = x

    @property
    def y_velocity(self):
        return self._y_velocity

    @y_velocity.setter
    def y_velocity(self, y):
        if math.isnan(y):
            raise ValueError('Is not a number')

        self._y_velocity = y


def bounce(rect):
    if rect.rect.x < BOUNDARY_H[0] or rect.rect.x + rect.rect.w > BOUNDARY_H[1]:
        rect.x_velocity = -rect.x_velocity

    if rect.rect.y < BOUNDARY_V[0] or rect.rect.y + rect.rect.h > BOUNDARY_V[1]:
        rect.y_velocity = -rect.y_velocity

pg.init()

screen = pg.display.set_mode((WIDTH, HEIGHT), vsync=1, flags=pg.SCALED)

rectangle = pg.Rect((0, 0, 100, 100))
rectangle = {
    'rect': rectangle,
    'color': RED
}
cube = Cube(**rectangle)
cube.speed = 5.0
cube.x_velocity = cube.speed
cube.y_velocity = cube.speed

clock = pg.time.Clock()

running = True

while running:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False

    cube.rect.x += cube.x_velocity
    cube.rect.y += cube.y_velocity

    bounce(cube)

    screen.fill((0, 0, 0, 0))

    pg.draw.rect(screen, cube.color, cube.rect)

    pg.display.flip()
    clock.tick(30)

pg.quit()

When I run C SDL2 code, the rect (Cube) is moving smoothly without flickering, beside pygame does.

Build:

sudo apt install libsdl2-dev; gcc main.c -lSDL2; ./a.out
pip install pygame; python main.py

How to reduce flickering in python code? I have already tried to add flag pg.SCALED and others. Tried to pass vsync=1. What do I wrong?


Solution

  • It is something with my local python. I've tried to run some code to get it busy

    n = 100000
    r = n + (n - 1)
    for i in range(n):
        s = r - (n + i)
        h = r - (s * 2)
        print(' ' * s, '#' * h)
    

    Time shows 5.01s that is too long. On another machine, time is less and there is no image tearing with the same code. Question is closed.