Я следил за этим руководством от 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 в качестве параметра, но все равно ничего не получается, все, что я вижу, это черное окно.
Спасибо @RetiredNinja, что решил проблему! Я посмотрю на двойные указатели! Спасибо!





Проблема в том, что вы отправляете 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 Добро пожаловать! По сути, в исходном коде вы отправляете копию указателя, который у вас есть в main, и присвоение этой копии нового значения не отображается в main. Имея указатель на указатель, вы можете разыменовать этот указатель-указатель, чтобы присвоить значение, которое затем будет присвоено указателю в main.
Я вижу, что кто-то уже опубликовал ответ.
Всего один совет: помните, что нам нужно зациклить возврат 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... Это часть платного курса?
Я уверен, что у нас это есть в реальном курсе.
Функция
initialize_windowприсваивает значения локальным копиям переданных указателей. Она не изменяет исходные указатели, объявленные вmain. Для этого вам понадобится двойной указатель.int initialize_window(SDL_Window** window, SDL_Renderer** renderer) { *window = ...; *renderer = ...; }