Программа C/SDL, рендеринг не работает с моим рендерером

Я следил за этим руководством от Pikuma о том, как настроить базовый игровой цикл C/SDL2, и все работало очень хорошо. Мне удалось завершить обучение, и моя программа работала нормально.

Проблема возникла, когда я попытался разбить код на несколько файлов (в уроке он делал все в основной функции, кроме объявления некоторых констант)

Я все еще могу создать окно и удалить его, и я все еще могу вызвать функцию рендеринга. НО функция рендеринга не распознает мой рендерер. Предполагалось, что он будет рисовать простую красную линию на сером фоне, но он больше не работает с тех пор, как я разбил свои функции на разные файлы.

вот как устроены мои файлы и код:

main.c

#include <stdio.h>
#include <SDL2/SDL.h>

#include "./constants.h"
#include "./init_and_destroy.h"
#include "./render.h"

//globals
int game_is_running = FALSE;
SDL_Window* my_window = NULL;
SDL_Renderer* my_renderer = NULL;

int last_frame_time = 0;

void setup() {

}

void process_input() {

    SDL_Event event;
    SDL_PollEvent(&event); //reference to event

    switch (event.type) {
        case SDL_QUIT:
            game_is_running = FALSE;
            break;
        case SDL_KEYDOWN:
            if (event.key.keysym.sym == SDLK_ESCAPE)
                game_is_running = FALSE;
            break;
    }
}

void update() {
    
    //---------------------------------FPS AND DELTA_TIME LOGIC---------------------------------------

    //caping frame rate
    int time_to_wait = FRAME_TARGET_TIME - (SDL_GetTicks() - last_frame_time);
    if (time_to_wait > 0 && time_to_wait <= FRAME_TARGET_TIME) {
        SDL_Delay(time_to_wait);
    }

    //delta time in seconds
    float delta_time = (SDL_GetTicks() - last_frame_time) / 1000.0f;

    last_frame_time = SDL_GetTicks();

    //------------------------------------------------------------------------------------------------

    //UPDATE LOGIC GOES HERE

}

int main() {
    
    game_is_running  = initialize_window(my_window, my_renderer);
    
    setup();

    while(game_is_running) {
        process_input();
        update();
        render(my_renderer);
    }

    destroy_window(my_window, my_renderer);

    return 0;
}

init_and_destroy.c

#include <stdio.h>
#include <SDL2/SDL.h>

#include "./constants.h"
#include "./init_and_destroy.h"


int initialize_window(SDL_Window* window, SDL_Renderer* renderer) {

    if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
        fprintf(stderr, "Error initializing SDL.\n");
        return FALSE;
    }

    window = SDL_CreateWindow(
        "My Window",
        SDL_WINDOWPOS_CENTERED, //x position
        SDL_WINDOWPOS_CENTERED, //y position
        WINDOW_WIDTH,
        WINDOW_HEIGHT,
        0
    );
    if (!window) {
        fprintf(stderr, "Error creating SDL Window.\n");
        return FALSE;
    }

    renderer = SDL_CreateRenderer(window, -1, 0);
    if (!renderer) {
        fprintf(stderr, "Error creating SDL Renderer.\n");
        return FALSE;
    }

    return TRUE;
}

void destroy_window(SDL_Window* window, SDL_Renderer* renderer) {
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
}

рендер.с

#include <stdio.h>
#include <SDL2/SDL.h>

#include "./constants.h"
#include "./render.h"

void render(SDL_Renderer* renderer) {
       
    SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
    SDL_RenderClear(renderer);
   
   //draw a red line
    SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
    for(int i = 0; i < WINDOW_WIDTH; i++) {
        SDL_RenderDrawPoint(renderer, i, i);
    }

    SDL_RenderPresent(renderer); //swap buffer

}

и мои файлы заголовков:

рендер.h

#ifndef RENDER
#define RENDER

void render(SDL_Renderer* renderer);

#endif

init_and_destroy.h

#ifndef INIT_AND_DESTROY
#define INIT_AND_DESTROY

int initialize_window(SDL_Window* window, SDL_Renderer* renderer);
void destroy_window(SDL_Window* window, SDL_Renderer* renderer);

#endif

отпечаток моего экрана

Я попробовал просто объявить функцию рендеринга без передачи каких-либо параметров, а теперь пытаюсь передать свой SDL_Renderer в качестве параметра, но все равно ничего не получается, все, что я вижу, это черное окно.

Функция initialize_window присваивает значения локальным копиям переданных указателей. Она не изменяет исходные указатели, объявленные в main. Для этого вам понадобится двойной указатель. int initialize_window(SDL_Window** window, SDL_Renderer** renderer) { *window = ...; *renderer = ...; }

Retired Ninja 14.03.2024 22:20
Назначение указателя C в функции может оказаться полезным.
Retired Ninja 14.03.2024 22:24

Спасибо @RetiredNinja, что решил проблему! Я посмотрю на двойные указатели! Спасибо!

Eujota 14.03.2024 23:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
65
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Проблема в том, что вы отправляете SDL_Window* и SDL_Renderer* на initialize_window. Чтобы переменным, которые вы определили в main, были присвоены значения в initialize_window, вам необходимо отправить указатели на эти указатели, чтобы то, что вы назначаете, было доступно на месте вызова.

Пример:

init_and_destroy.h:

int initialize_window(SDL_Window** window, SDL_Renderer** renderer);
//                              ^^                     ^^
void destroy_window(SDL_Window* window, SDL_Renderer* renderer);

init_and_destroy.c:

int initialize_window(SDL_Window** window, SDL_Renderer** renderer) {
//                              ^^                     ^^
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
        fprintf(stderr, "Error initializing SDL.\n");
        return FALSE;
    }

    *window = SDL_CreateWindow(
//  ^
        "My Window",
        SDL_WINDOWPOS_CENTERED, //x position
        SDL_WINDOWPOS_CENTERED, //y position
        WINDOW_WIDTH,
        WINDOW_HEIGHT,
        0
    );
    if (!*window) {
//      ^
        fprintf(stderr, "Error creating SDL Window.\n");
        return FALSE;
    }

    *renderer = SDL_CreateRenderer(*window, -1, 0);
//  ^
    if (!*renderer) {
//      ^
        fprintf(stderr, "Error creating SDL Renderer.\n");
        return FALSE;
    }

    return TRUE;
}

main.c:

int main() {
    SDL_Window* my_window = NULL;      // no reason to have these global
    SDL_Renderer* my_renderer = NULL;

    game_is_running  = initialize_window(&my_window, &my_renderer);
//                                       ^           ^
    //...
}

Спасибо! Это решило проблему. Я рассмотрю эту концепцию двойного указателя. Я никогда об этом не слышал, я новичок в C. Спасибо за ответ.

Eujota 14.03.2024 23:48

@Eujota Добро пожаловать! По сути, в исходном коде вы отправляете копию указателя, который у вас есть в main, и присвоение этой копии нового значения не отображается в main. Имея указатель на указатель, вы можете разыменовать этот указатель-указатель, чтобы присвоить значение, которое затем будет присвоено указателю в main.

Ted Lyngmo 14.03.2024 23:51
Ответ принят как подходящий

Я вижу, что кто-то уже опубликовал ответ.

Всего один совет: помните, что нам нужно зациклить возврат SDL_PollEvent.

void process_input() {
  SDL_Event event;
  while (SDL_PollEvent(&event)) {
    switch (event.type) {
      case SDL_QUIT:
        game_is_running = FALSE;
        break;
      case SDL_KEYDOWN:
        if (event.key.keysym.sym == SDLK_ESCAPE)
          game_is_running = FALSE;
        break;
    }
  }
}

Мы добавим этот цикл в одну из последующих лекций курса.

Спасибо, Густаво, я большой фанат! Я не помню, чтобы видел такое на каких-либо видео на YouTube... Это часть платного курса?

Eujota 24.05.2024 16:33

Я уверен, что у нас это есть в реальном курсе.

Gustavo Pezzi 24.05.2024 23:21

Другие вопросы по теме