Форум программистов, компьютерный форум, киберфорум
Visual C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141

SDL3_image - не отрисовывается текстура

23.02.2025, 17:23. Показов 28677. Ответов 166
Метки sdl (Все метки)

Студворк — интернет-сервис помощи студентам
Не отрисовывается текстура! Путь, формат img, установки и подключения dll - проверил трижды. При наложении текстуры, просто белое поле.
Участок кода (ошибок нет):
C++
1
2
3
4
5
6
7
8
SDL_Texture* player = IMG_LoadTexture(renderer, "2.png");
if (!player) {
    SDL_Log("IMG_LoadTexture: %s\n", SDL_GetError());
}
SDL_RenderTexture(renderer, player, NULL, &rect);
SDL_DestroyTexture(player);
 
SDL_RenderPresent(renderer);
Полный код. Может кто то взглянет опытным глазом где я накосячил?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include<SDL3_image/SDL_image.h>
#include<iostream>
 
static SDL_Window* window = NULL;
static SDL_Renderer* renderer = NULL;
SDL_FRect rect = { 0, 0, 100, 100 }; // создаем квадрат
int speed = 10;
 
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_Init(SDL_INIT_VIDEO);
    SDL_CreateWindowAndRenderer("SDL3 Game", 800, 640, 0, &window, &renderer);
    return(SDL_APP_CONTINUE);
}
 
 
SDL_AppResult SDL_AppIterate(void* appstate)
{
    SDL_SetRenderDrawColor(renderer, 30, 30, 30, 255);
    SDL_RenderClear(renderer);
 
    // Получаем массив нажатых клавиш
    const bool* keys = SDL_GetKeyboardState(NULL);
    if (keys[SDL_SCANCODE_W]) {
        rect.y -= speed;
    }
    if (keys[SDL_SCANCODE_S]) {
        rect.y += speed;
    }
    if (keys[SDL_SCANCODE_A]) {
        rect.x -= speed;
    }
    if (keys[SDL_SCANCODE_D]) {
        rect.x += speed;
    }
 
    // Отрисовка квадрата и движение вправо
    SDL_SetRenderDrawColor(renderer, 30, 200, 30, 255);
    SDL_RenderFillRect(renderer, &rect);
 
    SDL_Texture* player = IMG_LoadTexture(renderer, "2.png");
    if (!player) {
        SDL_Log("IMG_LoadTexture: %s\n", SDL_GetError());
    }
    SDL_RenderTexture(renderer, player, NULL, &rect);
    SDL_DestroyTexture(player);
 
    SDL_RenderPresent(renderer);
    SDL_Delay(16);
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    switch (event->type)
    {
    case SDL_EVENT_QUIT:
        return SDL_APP_SUCCESS;
        break;
 
    default:
        break;
    }
    return SDL_APP_CONTINUE;
}
 
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    /* SDL will clean up the window/renderer for us. */
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
23.02.2025, 17:23
Ответы с готовыми решениями:

Использование opengl. Не отрисовывается квадрат
Начал изучать opengl и столкнулся с трудностью уже на 1 примере, согласно которому должен просто отрисовываться белый квадрат, а у меня как...

Удаление текстур OpenGL
Ребята подскажите как удалить текстуру? Через метод glDeleteTextures, если да то какие параметры она принимает? И есть ли другой способ...

SDL : Неадекватная загрузка текстур
Есть следующее приложение: Programm.h #include &lt;windows.h&gt; #include &lt;SDL.h&gt; #include &lt;iostream&gt; #include &lt;string&gt; #pragma...

166
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141
03.04.2025, 21:16  [ТС]
Студворк — интернет-сервис помощи студентам
Пока решил сам.
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
03.04.2025, 21:42
Цитата Сообщение от cosmos44 Посмотреть сообщение
Подскажите, а как регулировать скорость анимации?
На шаге 5:

Цитата Сообщение от 8Observer8 Посмотреть сообщение
5) Создание таймера для переключения кадров спрайтовой анимации. Дельта тайм найден и может быть использован для расчёта моментов переключения кадров спрайтовой анимации. С помощью дельта тайм можно создать таймер. Создаём константу, которая хранит интервал между кадрами спрайтовой анимации:

C++
1
const float animationInterval = 0.1f;
Чем меньше интервал между сменой кадров спрайтовой анимации, тем быстрее проигрывается анимация и наоборот.
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141
04.04.2025, 16:58  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Чем меньше интервал между сменой кадров спрайтовой анимации, тем быстрее проигрывается анимация и наоборот.
Искал решение сделать короче код Таймера - скорость - ни чего не получилось.
Но все же сделал короче код - убрал массив спрайтов. У нас есть данные по изображению x, y, шаг 192px. Так что бегать по спрайтам можно по координатам с шагом 192 не используя массивы. Изображение воина в ZIP (ниже)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
 
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_image/SDL_image.h>
#include <iostream>
 
 
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Texture* spriteTexture = NULL;
 
int frameIndex = 0;
int lastTime = 0;
float animationTime = 0.f;
const float animationInterval = 0.1f;  // Кадр меняется каждые 0.1 секунды
 
int a = 0;
int shag = 192;
 
// This function runs once at startup
SDL_AppResult SDL_AppInit(void** appState, int argc, char* argv[])
{
    if (!SDL_Init(SDL_INIT_VIDEO))
    {
        SDL_Log("Couldn't initialize SDL: %s\n", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    if (!SDL_CreateWindowAndRenderer("Blue Warrior, SDL3, C++", 350, 350,
        0, &window, &renderer))
    {
        SDL_Log("Couldn't create window/renderer: %s\n", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    SDL_SetRenderVSync(renderer, 1);
 
    const char* texturePath = "./assets/Warrior_Blue.png";
    spriteTexture = IMG_LoadTexture(renderer, texturePath);
    if (!spriteTexture)
    {
        SDL_Log("Couldn't load %s: %s\n", texturePath, SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs when a new event (mouse input, keypresses, etc) occurs
SDL_AppResult SDL_AppEvent(void* appState, SDL_Event* event)
{
    if (event->type == SDL_EVENT_QUIT)
    {
        // End the program, reporting 
        return SDL_APP_SUCCESS;
    }
 
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs once per frame, and it is the heart of the program
SDL_AppResult SDL_AppIterate(void* appState)
{
    SDL_SetRenderDrawColor(renderer, 71, 171, 170, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(renderer);
 
    // Update animation
    SDL_FRect srcRect = { a, 0, 192, 192 };
    SDL_FRect destRect = { 100, 100, 192, 192 };
 
    // Render the current frame
    SDL_RenderTexture(renderer, spriteTexture, &srcRect, &destRect);
 
    // Update the screen
    SDL_RenderPresent(renderer);
 
    // Calculate delta time
    int currentTime = SDL_GetTicks();
    float deltaTime = (currentTime - lastTime) / 1000.f;
    lastTime = currentTime;
 
    animationTime += deltaTime;
 
    // Increment frame index and loop back to 0 when necessary
    if (animationTime > animationInterval)
    {
        animationTime = 0.f;
        a = a + shag;
        if (a == 960) { a = 0; }
    }
    
    //std::cout << "currentTime: " << currentTime << std::endl;
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs once at shutdown
void SDL_AppQuit(void* appState, SDL_AppResult result)
{
    // SDL will clean up the window/renderer for us
 
    SDL_DestroyTexture(spriteTexture);
}
assets.zip
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141
04.04.2025, 17:02  [ТС]
Еще вопрос!? У вас в коде // Заметки на английском. Это вы генерируете в GPT? и в каком.
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
04.04.2025, 20:21
Цитата Сообщение от cosmos44 Посмотреть сообщение
Еще вопрос!? У вас в коде // Заметки на английском. Это вы генерируете в GPT? и в каком.
Следующие комментарии я взял из официального учебного примера c GitHub-репозитория SDL: examples/renderer/01-clear/clear.c

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
 
/* ... */
 
// This function runs once at startup
SDL_AppResult SDL_AppInit(void** appState, int argc, char* argv[])
{
    /* ... */
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs when a new event (mouse input, keypresses, etc) occurs
SDL_AppResult SDL_AppEvent(void* appState, SDL_Event* event)
{
    /* ... */
}
 
// This function runs once per frame, and it is the heart of the program
SDL_AppResult SDL_AppIterate(void* appState)
{
    /* ... */
}
 
// This function runs once at shutdown
void SDL_AppQuit(void* appState, SDL_AppResult result)
{
    /* ... */
}
Пишите названия переменных и комментарии на английском - это полезно. Когда есть сомнения в правильности слов и предложений используйте https://translate.google.com/ Зря вы назвали переменную словом "shag" - лучше назвать "step". Я использую Gemini на английском, но не для перевода, а для вопросов. Можно писать комментарии на русском в Google Translate, а потом копировать текст в проект и наоборот - английские комментарии копировать в Google Translate для перевода на русский. Я иногда так делаю. Если часто так делать, то волей неволей учишься. Но лучше сразу писать на английском, а Google Translate использовать для самопроверки.

Цитата Сообщение от cosmos44 Посмотреть сообщение
Но все же сделал короче код - убрал массив спрайтов. У нас есть данные по изображению x, y, шаг 192px. Так что бегать по спрайтам можно по координатам с шагом 192 не используя массивы.
Согласен, это удобнее. Я не хотел делать большие спрайты, поэтому нарезал их на маленькие в два ряда. Теперь понял, что разницы нет, потому что остальная часть всё равно прозрачная. Только время уйдёт на нарезку спрайтов в GIMP. А самое главное, что в оригинальном sprite sheet спрайты уже выровнены.

У меня компилятор MinGW GCC 11.2 выдаёт предупреждение: narrowing conversion of 'a' from 'int' to 'float', потому что у "a" тип "int", а SDL_FRect требует "float":

Bash
1
2
3
warning: narrowing conversion of 'a' from 'int' to 'float' [-Wnarrowing]
   68 |     SDL_FRect srcRect = { a, 0, 192, 192 };
      |
Можно добавить явное приведение типа из "int" в "float" и тогда предупреждение исчезает:

C++
1
SDL_FRect srcRect = { (float)a, 0, 192, 192 };
Спрайт выводится относительно его верхнего левого угла. Например, я хочу вывести спрайт в начале координат, то есть в точке (0, 0) - в левом верхнем углу, а так не выходит сделать:

C++
1
2
3
4
// Player position
float playerX = 0.f;
float playerY = 0.f;
SDL_FRect destRect = { playerX, playerY, 192.f, 192.f };


Надо выводить его относительно центра, отняв половину высоты и ширины перед рисованием. Немного откорректировал ваш пример для вывода спрайта относительно его центра:

C++
1
2
3
4
// Player position
float playerX = 0.f;
float playerY = 0.f;
SDL_FRect destRect = { playerX - 96.f, playerY - 96.f, 192.f, 192.f };


Миниатюры
Вложения
Тип файла: zip warrior-sdl3.zip (1.56 Мб, 0 просмотров)
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
04.04.2025, 20:31
Подумайте, как сделать, чтобы по клику левой кнопки мыши воин махал мечом.
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
05.04.2025, 19:36
В вашем крайнем примере проигрывается idle-анимация, то есть анимация покоя. Хорошо бы сделать, чтобы при клике левой кнопкой мыши в области окна проигрывалась анимация атаки мечом, а после однократного проигранной анимации атаки снова выводилась анимация покоя. Я сделаю свою версию, а вы свою. Чтобы определить клик левой кнопкой (а не правой или средней), нужно добавить следующий код в функцию SDL_AppEvent:

C++
1
2
3
4
5
6
7
8
9
10
11
12
    if (event->type == SDL_EVENT_QUIT)
    {
        // End the program, reporting 
        return SDL_APP_SUCCESS;
    }
    else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
    {
        if (event->button.button == SDL_BUTTON_LEFT)
        {
            std::cout << "Left button click" << std::endl;
        }
    }
В архиве assets.zip в вашем сообщении выше в третьем и четвёртом рядах спрайтовой страницы находятся два вида атаки мечом:



Миниатюры
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
06.04.2025, 13:11
Объясню своими словами, что означают эти строки кода:

C++
1
2
3
    SDL_FRect srcRect = { 0, 0, 192, 192 };
    SDL_FRect destRect = { 100, 100, 192, 192 };
    SDL_RenderTexture(renderer, spriteTexture, &srcRect, &destRect);
Функция SDL_RenderTexture() рисует текстуру spriteTexture, принимая два прямоугольника типа SDL_FRect. Приставка "SDL_" означает, что функция SDL_RenderTexture() и SDL_FRect принадлежат к библиотеке SDL. Буква "F" в названии типа SDL_FRect означает Float - то есть параметры (x, y, w, h) имеют тип float. "Rect" в названии типа SDL_FRect означает Rectangle, то есть переводится, как "прямоугольник". SDL_RenderTexture() - "render texture" переводится, как "нарисовать текстуру".

Прямоугольник srcRect (сокращение от "source rectangle" - переводится, как "прямоугольник источника") относится к загруженному изображению. Первые два параметра это (x, y) - координата левого верхнего угла начала области на текстуре, а вторые два параметра (w, h) - это ширина и высота области, которая будет взята из текстуры источника.

Прямоугольник destRect (сокращение от "destination rectangle" - переводится, как "прямоугольник назначения") относится к отображаемому изображению. Первые два параметра это (x, y) - координата левого верхнего угла начала области рисования, а вторые два параметра (w, h) - это ширина и высота области, куда будет нарисована текстура. То есть с помощью двух первых параметров (x, y) можно менять координату картинки, где её нарисовать на экране, а вторые два параментра определяют какого размера будет отображаемая картинка.
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141
06.04.2025, 13:22  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Объясню своими словами, что означают эти строки кода:
В общем я понял, что и как. Сейчас посмотрел видео-уроки - переношу в class.
Как будут результаты - выложу для обсуждения, где, чего подправить или изменить.
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
06.04.2025, 18:11
Для переключения между анимациями по клику мыши я завёл переменную "b":

C++
1
2
3
int a = 0;
int b = 0;
const int step = 192;
Эта переменная используется при взятии кадра из текстуры:

C++
1
SDL_FRect srcRect = { (float)a, (float)b, 192, 192 };
По событию клика левой кнопкой мыши значение переменной "b" увеличивается на step = 192:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// This function runs when a new event (mouse input, keypresses, etc) occurs
SDL_AppResult SDL_AppEvent(void *appState, SDL_Event *event)
{
    if (event->type == SDL_EVENT_QUIT)
    {
        // End the program, reporting
        return SDL_APP_SUCCESS;
    }
    else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
    {
        if (event->button.button == SDL_BUTTON_LEFT)
        {
            b = b + step;
            if (b == 1344)
            {
                b = 0;
            }
        }
    }
 
    return SDL_APP_CONTINUE; // Carry on with the program
}
main.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
 
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_image/SDL_image.h>
#include <iostream>
 
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *spriteTexture = NULL;
 
int frameIndex = 0;
int lastTime = 0;
float animationTime = 0.f;
const float animationInterval = 0.1f; // The frame changes every 0.1 seconds
 
int a = 0;
int b = 0;
const int step = 192;
 
const unsigned int width = 400;
const unsigned int height = 400;
 
// This function runs once at startup
SDL_AppResult SDL_AppInit(void **appState, int argc, char *argv[])
{
    if (!SDL_Init(SDL_INIT_VIDEO))
    {
        SDL_Log("Couldn't initialize SDL: %s\n", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    const char *title = "Warrior Animations in SDL3 and C++";
    if (!SDL_CreateWindowAndRenderer(title, width, height, 0, &window, &renderer))
    {
        SDL_Log("Couldn't create window/renderer: %s\n", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    SDL_SetRenderVSync(renderer, 1);
 
    const char *texturePath = "./assets/Warrior_Blue.png";
    spriteTexture = IMG_LoadTexture(renderer, texturePath);
    if (!spriteTexture)
    {
        SDL_Log("Couldn't load %s: %s\n", texturePath, SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs when a new event (mouse input, keypresses, etc) occurs
SDL_AppResult SDL_AppEvent(void *appState, SDL_Event *event)
{
    if (event->type == SDL_EVENT_QUIT)
    {
        // End the program, reporting
        return SDL_APP_SUCCESS;
    }
    else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
    {
        if (event->button.button == SDL_BUTTON_LEFT)
        {
            b = b + step;
            if (b == 1344)
            {
                b = 0;
            }
        }
    }
 
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs once per frame, and it is the heart of the program
SDL_AppResult SDL_AppIterate(void *appState)
{
    SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(renderer);
 
    // Update animation
    SDL_FRect srcRect = { (float)a, (float)b, 192, 192 };
 
    // Player position
    float playerX = (float)width / 2.f;
    float playerY = (float)height / 2.f;
    SDL_FRect destRect = { playerX - 96.f, playerY - 96.f, 192.f, 192.f };
 
    // Render the current frame
    SDL_RenderTexture(renderer, spriteTexture, &srcRect, &destRect);
 
    // Update the screen
    SDL_RenderPresent(renderer);
 
    // Calculate delta time
    int currentTime = SDL_GetTicks();
    float deltaTime = (currentTime - lastTime) / 1000.f;
    lastTime = currentTime;
 
    animationTime += deltaTime;
 
    // Increment frame index and loop back to 0 when necessary
    if (animationTime > animationInterval)
    {
        animationTime = 0.f;
        a = a + step;
        if (a == 960)
        {
            a = 0;
        }
    }
 
    // std::cout << "currentTime: " << currentTime << std::endl;
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs once at shutdown
void SDL_AppQuit(void *appState, SDL_AppResult result)
{
    SDL_DestroyTexture(spriteTexture);
    // SDL will clean up the window/renderer for us
}


Собрал в WASM. Можно запустить в браузера по одному клику по ссылке: https://warrior-animations-sdl3.netlify.app/

Название: 3d7a5a2d66b0c7c6d3b956c762436e0ed84b958f.png
Просмотров: 48

Размер: 2.1 Кб

Прикрепил EXE без внешних зависимостей, то есть собранный с флагом -static:

Code
1
target_link_options(app PRIVATE -static)
Название: 7e1732d73c0626ba912e00939789d731551401b9.png
Просмотров: 48

Размер: 2.6 Кб

Мне проще собирать из консоли с помощью MinGW в EXE и WASM, программируя в легковесном Sublime Text 4, чем в VS. Если хотите, то можете попробовать скачать MinGW и собранные библиотеки SDL3 по ссылкам с моего сайта: https://8observer8.bitbucket.io/, добавить путь к mingw/bin в Path и собрать и запустить EXE командами из консоли из директории примера, предварительно подправив пути в батнике config-mingw.bat:

Название: ca9fe4bc5cbce3cc0590d70bccb09821805e93ea.png
Просмотров: 48

Размер: 2.7 Кб

Bash
1
2
3
config-mingw
build-mingw
dist\win\app
Миниатюра
Вложения
Тип файла: zip warrior-animations-sdl3.zip (532.8 Кб, 2 просмотров)
Тип файла: zip warrior-animations-sdl3-exe.zip (1.58 Мб, 0 просмотров)
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
06.04.2025, 19:53
Я переправил код игры Змейка на SDL3 из видео туториала FamTrinli на YouTube, скачав архив по ссылке из описания под видео (прикрепил архив по ссылке из под видео - 16_Games.zip):



Играть в браузере: https://famtrinli-snake-in-sdl3-cpp.netlify.app/



Код на SFML тоже прикрепил, исправив на версию 3.0.0. Прикрепил ещё версию, переписанную мною на Python и PySDL3.

Простые примеры на PySDL3: https://github.com/Aermoss/PySDL3/discussions/18

Для запуска игры на PySDL3, нужно установить PySDL3 командой:

Bash
1
pip install PySDL3
Эта команда установит все библиотеки SDL3: SDL3_image, SDL3_ttf (для текста), SDL3_mixer (для аудио файлов), SDL3_net (для мультиплеера) и т.д.

Запустить игру можно командой:

Bash
1
py main.py
На Python проще и быстрее писать учебные примеры и прототипы, а потом переписывать их на C++ для сборки EXE, WASM и APK. APK - это архив для установки приложений для Android. Вроде бы двойная работа, но она полезная - лучше усваиваешь материал при сравнении двух языков. Получается больше практики для запоминания SDL3 API.

SFML3-версию собрал в статику. Вес приложения - 3.54 MB:

Название: 40fcdb2f29b0b92bcfad3c88ab29df6c23df9f8b.png
Просмотров: 49

Размер: 1.5 Кб

SDL3-верия занимает чуть больше - 4.75 MB. Это больше на 1.21 MB:

Название: 96d59e8741d8ad373e9bbc58bb2220e9a2aa2cb7.png
Просмотров: 49

Размер: 2.6 Кб

Но зато SDL3 официально поддерживается для WebAssembly и лучше поддерживается для Android. Лучше поддерживается для Python. Можно программировать не только на C++, но и на Си. Ещё SDL является частью игрового движка компании Valve, на котором сделаны Counter-Strike, Dota и т.д.

PySDL3:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import ctypes
import os
import random
 
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
 
import sdl3
 
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
 
greenSpriteTexture = None
redSpriteTexture = None
whiteSpriteTexture = None
 
N = 30
M = 20
size = 16
w = size * N
h = size * M
 
keys = { "left": False, "right": False, "up": False, "down": False }
 
delay = 0.1
timer = 0
lastTime = 0
 
snakeLength = 4
snakeMaxLength = 100
snakeDir = 0
 
# Snake list
s = [{ "x": 0, "y": 0 } for _ in range(snakeMaxLength)]
 
# Fruit list
fruit = { "x": 7, "y": 5 }
 
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
    global greenSpriteTexture
    global redSpriteTexture
    global whiteSpriteTexture
 
    if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
        sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    title = "FamTrinli's Snake in PySDL3".encode()
    if not sdl3.SDL_CreateWindowAndRenderer(title, w, h, 0, window, renderer):
        sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
 
    # Green texture
    texturePath = "./assets/images/green.png".encode()
    greenSpriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
    if not greenSpriteTexture:
        sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
    sdl3.SDL_SetTextureScaleMode(greenSpriteTexture, sdl3.SDL_SCALEMODE_NEAREST)
 
    # Red texture
    texturePath = "./assets/images/red.png".encode()
    redSpriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
    if not redSpriteTexture:
        sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
    sdl3.SDL_SetTextureScaleMode(redSpriteTexture, sdl3.SDL_SCALEMODE_NEAREST)
 
    # White texture
    texturePath = "./assets/images/white.png".encode()
    whiteSpriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
    if not whiteSpriteTexture:
        sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
    sdl3.SDL_SetTextureScaleMode(whiteSpriteTexture, sdl3.SDL_SCALEMODE_NEAREST)
 
    return sdl3.SDL_APP_CONTINUE
 
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
    if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
        return sdl3.SDL_APP_SUCCESS
    elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_DOWN:
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP
            ):
            keys["up"] = True
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_A or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_LEFT
            ):
            keys["left"] = True
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN
            ):
            keys["down"] = True
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_D or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_RIGHT
            ):
            keys["right"] = True
    elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_UP:
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP
            ):
            keys["up"] = False
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_A or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_LEFT
            ):
            keys["left"] = False
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN
            ):
            keys["down"] = False
        if (
                sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_D or
                sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_RIGHT
            ):
            keys["right"] = False
 
    return sdl3.SDL_APP_CONTINUE
 
def keyboard():
    global snakeDir
 
    if snakeDir != 0 and keys["up"]:
        snakeDir = 3
    if snakeDir != 2 and keys["left"]:
        snakeDir = 1
    if snakeDir != 3 and keys["down"]:
        snakeDir = 0
    if snakeDir != 1 and keys["right"]:
        snakeDir = 2
 
def tick():
    global snakeLength
 
    for i in range(snakeLength, 0, -1):
        s[i]["x"] = s[i - 1]["x"]
        s[i]["y"] = s[i - 1]["y"]
 
    if snakeDir == 3:
        s[0]["y"] -= 1 # up
    if snakeDir == 1:
        s[0]["x"] -= 1 # left
    if snakeDir == 0:
        s[0]["y"] += 1 # down
    if snakeDir == 2:
        s[0]["x"] += 1 # right
 
    if s[0]["x"] >= N:
        s[0]["x"] = 0
    if s[0]["x"] < 0:
        s[0]["x"] = N - 1
    if s[0]["y"] >= M:
        s[0]["y"] = 0
    if s[0]["y"] < 0:
        s[0]["y"] = M - 1
 
    if s[0]["x"] == fruit["x"] and s[0]["y"] == fruit["y"]:
        snakeLength += 1
        if snakeLength != snakeMaxLength:
            fruit["x"] = random.randint(0, N - 1)
            fruit["y"] = random.randint(0, M - 1)
        else:
            print("You won the game!")
            fruit["x"] = -1
            fruit["y"] = -1
            snakeLength -= 1
 
    for i in range(1, snakeLength):
        if s[0]["x"] == s[i]["x"] and s[0]["y"] == s[i]["y"]:
            snakeLength = i
 
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
    global lastTime
    global timer
    global snakeLength
 
    # Calc delta time
    currentTime = sdl3.SDL_GetTicks()
    deltaTime = (currentTime - lastTime) / 1000
    lastTime = currentTime
 
    timer += deltaTime
    if timer > delay:
        timer = 0
        tick()
 
    keyboard()
 
    # Clear the canvas with a specific color
    sdl3.SDL_SetRenderDrawColor(renderer, 168, 185, 168, sdl3.SDL_ALPHA_OPAQUE)
    sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
 
    # Draw a background
    for i in range(N):
        for j in range(M):
            srcRect = sdl3.SDL_FRect(0, 0, size, size)
            destRect = sdl3.SDL_FRect(i * size, j * size, size, size)
            sdl3.SDL_RenderTexture(renderer, whiteSpriteTexture, srcRect, destRect)
 
    # Draw a snake
    for i in range(snakeLength):
        srcRect = sdl3.SDL_FRect(0, 0, size, size)
        destRect = sdl3.SDL_FRect(s[i]["x"] * size, s[i]["y"] * size, size, size)
        sdl3.SDL_RenderTexture(renderer, greenSpriteTexture, srcRect, destRect)
 
    # Draw a fruit
    srcRect = sdl3.SDL_FRect(0, 0, size, size)
    destRect = sdl3.SDL_FRect(fruit["x"] * size, fruit["y"] * size, size, size)
    sdl3.SDL_RenderTexture(renderer, redSpriteTexture, srcRect, destRect)
 
    sdl3.SDL_RenderPresent(renderer)
    return sdl3.SDL_APP_CONTINUE
 
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
    global greenSpriteTexture
    global redSpriteTexture
    global whiteSpriteTexture
    sdl3.SDL_DestroyTexture(greenSpriteTexture)
    sdl3.SDL_DestroyTexture(redSpriteTexture)
    sdl3.SDL_DestroyTexture(whiteSpriteTexture)
    # SDL will clean up the window/renderer for us
SDL3:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
 
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_image/SDL_image.h>
 
#include <map>
#include <iostream>
 
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
 
SDL_Texture *greenSpriteTexture = NULL;
SDL_Texture *redSpriteTexture = NULL;
SDL_Texture *whiteSpriteTexture = NULL;
 
int N = 30, M = 20;
int size = 16;
int w = size * N;
int h = size * M;
 
std::map<std::string, bool> keys;
 
float delay = 0.1f;
float timer = 0.f;
float lastTime = 0.f;
 
int snakeLength = 4;
const int snakeMaxLength = 100;
int snakeDir = 0;
 
struct snake
{
    int x, y;
} s[snakeMaxLength];
 
struct fruit
{
    int x, y;
} f;
 
// This function runs once at startup
SDL_AppResult SDL_AppInit(void ** appState, int argc, char *argv[])
{
    if (!SDL_Init(SDL_INIT_VIDEO))
    {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    const char *title = "FamTrinli's Snake in SDL3 and C++";
    if (!SDL_CreateWindowAndRenderer(title, w, h, 0, &window, &renderer))
    {
        SDL_Log("Couldn't create a window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    SDL_SetRenderVSync(renderer, 1);
 
    // Green texture
    const char *greenTexturePath = "./assets/images/green.png";
    greenSpriteTexture = IMG_LoadTexture(renderer, greenTexturePath);
    if (!greenSpriteTexture)
    {
        SDL_Log("Couldn't load %s: %s\n", greenTexturePath, SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // Red texture
    const char *redTexturePath = "./assets/images/red.png";
    redSpriteTexture = IMG_LoadTexture(renderer, redTexturePath);
    if (!redSpriteTexture)
    {
        SDL_Log("Couldn't load %s: %s\n", redTexturePath, SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // White texture
    const char *whiteTexturePath = "./assets/images/white.png";
    whiteSpriteTexture = IMG_LoadTexture(renderer, whiteTexturePath);
    if (!whiteSpriteTexture)
    {
        SDL_Log("Couldn't load %s: %s\n", whiteTexturePath, SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
void keyboard()
{
    if (snakeDir != 0 && keys["up"])
    {
        snakeDir = 3;
    }
    if (snakeDir != 2 && keys["left"])
    {
        snakeDir = 1;
    }
    if (snakeDir != 3 && keys["down"])
    {
        snakeDir = 0;
    }
    if (snakeDir != 1 && keys["right"])
    {
        snakeDir = 2;
    }
}
 
void tick()
{
    for (int i = snakeLength; i > 0; --i)
    {
        s[i].x = s[i - 1].x;
        s[i].y = s[i - 1].y;
    }
 
    if (snakeDir == 3)
    {
        s[0].y -= 1; // up
    }
    if (snakeDir == 1)
    {
        s[0].x -= 1; // left
    }
    if (snakeDir == 0)
    {
        s[0].y += 1; // down
    }
    if (snakeDir == 2)
    {
        s[0].x += 1; // right
    }
 
    if (s[0].x >= N)
    {
        s[0].x = 0;
    }
    if (s[0].x < 0)
    {
        s[0].x = N - 1;
    }
    if (s[0].y >= M)
    {
        s[0].y = 0;
    }
    if (s[0].y < 0)
    {
        s[0].y = M - 1;
    }
 
    if ((s[0].x == f.x) && (s[0].y == f.y))
    {
        snakeLength++;
        if (snakeLength != snakeMaxLength)
        {
            f.x = rand() % N;
            f.y = rand() % M;
        }
        else
        {
            std::cout << "You won the game!" << std::endl;
            f.x = -1;
            f.y = -1;
            snakeLength -= 1;
        }
    }
 
    for (int i = 1; i < snakeLength; i++)
    {
        if ((s[0].x == s[i].x) && (s[0].y) == s[i].y)
        {
            snakeLength = i;
        }
    }
}
 
// This function runs when a new event (mouse input, keypresses, etc) occurs
SDL_AppResult SDL_AppEvent(void *appState, SDL_Event *event)
{
    if (event->type == SDL_EVENT_QUIT)
    {
        // End the program
        return SDL_APP_SUCCESS;
    }
    else if (event->type == SDL_EVENT_KEY_DOWN)
    {
        if (event->key.scancode == SDL_SCANCODE_W || event->button.button == SDL_SCANCODE_UP)
        {
            keys["up"] = true;
        }
        if (event->key.scancode == SDL_SCANCODE_S || event->button.button == SDL_SCANCODE_DOWN)
        {
            keys["down"] = true;
        }
        if (event->key.scancode == SDL_SCANCODE_D || event->button.button == SDL_SCANCODE_RIGHT)
        {
            keys["right"] = true;
        }
        if (event->key.scancode == SDL_SCANCODE_A || event->button.button == SDL_SCANCODE_LEFT)
        {
            keys["left"] = true;
        }
    }
    else if (event->type == SDL_EVENT_KEY_UP)
    {
        if (event->key.scancode == SDL_SCANCODE_W || event->button.button == SDL_SCANCODE_UP)
        {
            keys["up"] = false;
        }
        if (event->key.scancode == SDL_SCANCODE_S || event->button.button == SDL_SCANCODE_DOWN)
        {
            keys["down"] = false;
        }
        if (event->key.scancode == SDL_SCANCODE_D || event->button.button == SDL_SCANCODE_RIGHT)
        {
            keys["right"] = false;
        }
        if (event->key.scancode == SDL_SCANCODE_A || event->button.button == SDL_SCANCODE_LEFT)
        {
            keys["left"] = false;
        }
    }
 
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs one per frame, ant it is the heart of the program
SDL_AppResult SDL_AppIterate(void *appState)
{
    // Calc delta time
    float currentTime = SDL_GetTicks();
    float deltaTime = (currentTime - lastTime) / 1000.f;
    lastTime = currentTime;
 
    timer += deltaTime;
    if (timer > delay)
    {
        timer = 0.f;
        tick();
    }
 
    keyboard();
 
    // Clear the canvas with a specific color
    SDL_SetRenderDrawColor(renderer, 168, 185, 168, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(renderer); // Start with a blank canvas
 
    // Draw a background
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            SDL_FRect srcRect = SDL_FRect(0.f, 0.f, size, size);
            SDL_FRect destRect = SDL_FRect(i * size, j * size, size, size);
            SDL_RenderTexture(renderer, whiteSpriteTexture, &srcRect, &destRect);
        }
    }
 
    // Draw a snake
    for (int i = 0; i < snakeLength; i++)
    {
        SDL_FRect srcRect = SDL_FRect(0, 0, size, size);
        SDL_FRect destRect = SDL_FRect(s[i].x * size, s[i].y * size, size, size);
        SDL_RenderTexture(renderer, greenSpriteTexture, &srcRect, &destRect);
    }
 
    // Draw a fruit
    SDL_FRect srcRect = SDL_FRect(0, 0, size, size);
    SDL_FRect destRect = SDL_FRect(f.x * size, f.y * size, size, size);
    SDL_RenderTexture(renderer, redSpriteTexture, &srcRect, &destRect);
 
    SDL_RenderPresent(renderer);
    return SDL_APP_CONTINUE; // Carry on with the program
}
 
// This function runs once at shutdown
void SDL_AppQuit(void *appState, SDL_AppResult result)
{
    SDL_DestroyTexture(greenSpriteTexture);
    SDL_DestroyTexture(redSpriteTexture);
    SDL_DestroyTexture(whiteSpriteTexture);
    // SDL will clean up the window/renderer for us
}
SFML3:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <SFML/Graphics.hpp>
#include <iostream>
#include <time.h>
 
using namespace sf;
 
static constexpr auto N = 30, M = 20;
unsigned int size = 16;
unsigned int w = size * N;
unsigned int h = size * M;
 
int dir = 0, num = 4;
 
struct snake
{
    int x, y;
} s[100];
 
struct fruit
{
    int x, y;
} f;
 
void tick()
{
    for (int i = num; i > 0; --i)
    {
        s[i].x = s[i - 1].x;
        s[i].y = s[i - 1].y;
    }
 
    if (dir == 0)
    {
        s[0].y += 1; // down
    }
    if (dir == 1)
    {
        s[0].x -= 1; // left
    }
    if (dir == 2)
    {
        s[0].x += 1; // right
    }
    if (dir == 3)
    {
        s[0].y -= 1; // up
    }
 
    if (s[0].x >= N)
    {
        s[0].x = 0;
    }
    if (s[0].x < 0)
    {
        s[0].x = N - 1;
    }
    if (s[0].y >= M)
    {
        s[0].y = 0;
    }
    if (s[0].y < 0)
    {
        s[0].y = M - 1;
    }
 
    if ((s[0].x == f.x) && (s[0].y == f.y))
    {
        num++;
        f.x = rand() % N;
        f.y = rand() % M;
    }
 
    for (int i = 1; i < num; i++)
    {
        if ((s[0].x == s[i].x) && (s[0].y) == s[i].y)
        {
            num = i;
        }
    }
}
 
int main()
{
    RenderWindow window(VideoMode({ w, h }), "Snake");
 
    // Enable VSync
    window.setVerticalSyncEnabled(true);
 
    Texture t1, t2;
    bool t1_load_status = t1.loadFromFile("./assets/images/white.png");
    bool t2_load_status = t2.loadFromFile("./assets/images/red.png");
    Sprite sprite1(t1);
    Sprite sprite2(t2);
    Clock clock;
    float timer = 0, delay = 0.1;
    f.x = 10;
    f.y = 10;
    while (window.isOpen())
    {
        float time = clock.getElapsedTime().asSeconds();
        clock.restart();
        timer += time;
        while (const std::optional event = window.pollEvent())
        {
            if (event->is<Event::Closed>())
            {
                window.close();
            }
        }
        if (dir != 2 && Keyboard::isKeyPressed(Keyboard::Key::Left))
        {
            dir = 1;
        }
        if (dir != 1 && Keyboard::isKeyPressed(Keyboard::Key::Right))
        {
            dir = 2;
        }
        if (dir != 0 && Keyboard::isKeyPressed(Keyboard::Key::Up))
        {
            dir = 3;
        }
        if (dir != 3 && Keyboard::isKeyPressed(Keyboard::Key::Down))
        {
            dir = 0;
        }
        if (timer > delay)
        {
            timer = 0;
            tick();
        }
        window.clear();
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < M; j++)
            {
                sprite1.setPosition({ float(i * size), float(j * size) });
                window.draw(sprite1);
            }
        }
        for (int i = 0; i < num; i++)
        {
            sprite2.setPosition({ float(s[i].x * size), float(s[i].y * size) });
            window.draw(sprite2);
        }
        sprite2.setPosition({ float(f.x * size), float(f.y * size) });
        window.draw(sprite2);
        window.display();
    }
    return 0;
}
Миниатюры
Вложения
Тип файла: zip famtrinli-snake-in-pysdl3.zip (5.0 Кб, 0 просмотров)
Тип файла: zip famtrinli-snake-in-sdl3-cpp.zip (8.1 Кб, 0 просмотров)
Тип файла: zip famtrinli-snake-in-sdl3-cpp-exe.zip (1.47 Мб, 0 просмотров)
Тип файла: zip famtrinli-snake-sfml3-cpp.zip (4.2 Кб, 0 просмотров)
Тип файла: zip famtrinli-snake-sfml3-cpp-exe.zip (890.6 Кб, 0 просмотров)
Тип файла: zip 16_Games.zip (13.29 Мб, 0 просмотров)
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141
06.04.2025, 22:52  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Собрал в WASM. Можно запустить в браузера по одному клику по ссылке
Дошел до вывода текста в окне. Почему то нет отображения и ошибок нет. Взгляните что не так? За основу взял часть кода из вашего файла.

Выделил код относящийся к тексту*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
код ...
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include<SDL3_image/SDL_image.h>
#include<iostream>
#include<stdio.h>
#include"Resource.h"
#include"Spr.h"
#include <SDL3_ttf/SDL_ttf.h>
 
 
static SDL_Window* window = NULL;
static SDL_Renderer* renderer = NULL;
Resource* gold = nullptr;
Spr* spr = nullptr;
 
static SDL_Texture* enTexture = NULL;
static SDL_Texture* ruTexture = NULL;
 
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_Init(SDL_INIT_VIDEO);
    SDL_CreateWindowAndRenderer("SDL3 Game", 800, 640, 0, &window, &renderer);
    gold = new Resource(renderer, {300, 300}, "assets/G_Idle.png");
    spr = new Spr(renderer, { 150, 150 }, "assets/Warrior_Blue.png");
    
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    
    std::locale utf8_locale("en_US.UTF-8"); // Or your desired UTF-8 locale
    std::locale::global(utf8_locale); // Set the global locale.
    TTF_Font* font = TTF_OpenFont("assets/fonts/arial.ttf", 48);
 
    // Text in English
    SDL_Color enTextColor = { 200, 255, 200 };
    std::string enText = "Text in English";
    SDL_Surface* enSurface = TTF_RenderText_Blended(font, enText.c_str(),
        enText.size(), enTextColor);
    enTexture = SDL_CreateTextureFromSurface(renderer, enSurface);
    SDL_DestroySurface(enSurface);
 
    // Text in Russian
    SDL_Color ruTextColor = { 200, 255, 255 };
    SDL_Surface* ruSurface = TTF_RenderText_Blended(font, "Текст на русском",
        30, ruTextColor);
    ruTexture = SDL_CreateTextureFromSurface(renderer, ruSurface);
    SDL_DestroySurface(ruSurface);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
    return(SDL_APP_CONTINUE);
}
 
 
SDL_AppResult SDL_AppIterate(void* appstate)
{
    SDL_SetRenderDrawColor(renderer, 0, 211, 211, 211);
    SDL_RenderClear(renderer);
 
    spr->update();
    spr->draw();
 
    if (gold) {
        gold->update();
        gold->draw();
    }
 
    //player->update();
    //player->draw();
 
    if (gold) {
        SDL_FRect playerDest = spr->getDest();
        SDL_FRect goldDest = gold->getDest();
        SDL_FRect result;
        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        if (SDL_GetRectIntersectionFloat(&playerDest, &goldDest, &result)) {
            //SDL_Log("w: %.2f\n", result.w);
            //SDL_Log("h: %.2f\n", result.h);
            //SDL_RenderRect(renderer, &result);
            if (result.w >= 125 && result.h >= 115) {
                delete gold;
            }
        }
    }
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    SDL_FRect trect;
    // Text in English
    SDL_GetTextureSize(enTexture, &trect.w, &trect.h);
    trect.x = 10.f;
    trect.y = 20.f;
    // Draw the text
    SDL_RenderTexture(renderer, enTexture, NULL, &trect);
 
    // Text in Russian
    SDL_GetTextureSize(ruTexture, &trect.w, &trect.h);
    trect.x = 10.f;
    trect.y = 100.f;
    // Draw the text
    SDL_RenderTexture(renderer, ruTexture, NULL, &trect);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
 
 
    SDL_RenderPresent(renderer);
 
    SDL_Delay(16);
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    switch (event->type)
    {
    case SDL_EVENT_QUIT:
        return SDL_APP_SUCCESS;
        break;
 
    default:
        break;
    }
    //player->handleEvents(event);
    spr->handleEvents(event);
 
    return SDL_APP_CONTINUE;
}
 
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    //SDL_DestroyTexture(player);
}
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
06.04.2025, 23:45
Надо добавить инициализацию SDL3_ttf:

C++
1
2
3
4
5
    // Initialize the TTF library
    if (!TTF_Init()) {
        SDL_Log("Couldn't initialize TTF: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
Текстуры надо удалять:

C++
1
2
3
4
5
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    SDL_DestroyTexture(enTexture);
    SDL_DestroyTexture(ruTexture);
}
Пример вывода счётчика кликов мыши на PySDL3. Он показывает, как выводить динамический текст:



Bash
1
2
pip install PySDL3
py main.py
main.py

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import ctypes
import os
 
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
 
import sdl3
 
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
 
font = None
textColor = sdl3.SDL_Color(255, 255, 255)
counter = 0
 
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
    global font
 
    if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
        sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    # Initialize the TTF library
    if not sdl3.TTF_Init():
        sdl3.SDL_Log("Couldn't initialize TTF: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    title = "Click counter using PySDL3".encode()
    if not sdl3.SDL_CreateWindowAndRenderer(title, 320, 320, 0, window, renderer):
        sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
 
    font = sdl3.TTF_OpenFont("C:/Windows/Fonts/arial.ttf".encode(), 28)
    if not font:
        sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    return sdl3.SDL_APP_CONTINUE
 
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
    global counter
 
    if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
        return sdl3.SDL_APP_SUCCESS
    elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_BUTTON_DOWN:
        counter += 1
 
    return sdl3.SDL_APP_CONTINUE
 
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
    global counter
    global font
 
    sdl3.SDL_SetRenderDrawColor(renderer, 55, 55, 55, sdl3.SDL_ALPHA_OPAQUE)
    sdl3.SDL_RenderClear(renderer)
 
    text = "Click counter = %d".encode() % counter
    surface = sdl3.TTF_RenderText_Blended(font, text, len(text), textColor)
    textTexture = sdl3.SDL_CreateTextureFromSurface(renderer, surface)
    sdl3.SDL_DestroySurface(surface)
 
    width, height = ctypes.c_float(), ctypes.c_float()
    sdl3.SDL_GetTextureSize(textTexture, ctypes.byref(width), ctypes.byref(height))
    rect = sdl3.SDL_FRect(20.0, 20.0, width.value, height.value)
    sdl3.SDL_RenderTexture(renderer, textTexture, None, rect)
 
    sdl3.SDL_RenderPresent(renderer)
    sdl3.SDL_DestroyTexture(textTexture)
    return sdl3.SDL_APP_CONTINUE
 
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
    ... # SDL will clean up the window/renderer for us
Миниатюры
Вложения
Тип файла: zip click-counter-pysdl3.zip (22.2 Кб, 2 просмотров)
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141
07.04.2025, 07:25  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Надо добавить инициализацию SDL3_ttf:
Спасибо!
Вы решили вопрос с выводом русского алфавита?
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
07.04.2025, 10:08
Цитата Сообщение от cosmos44 Посмотреть сообщение
Вы решили вопрос с выводом русского алфавита?
Я не помню, разве был вопрос по этому поводу? У меня ваш пример выводит текст на русском без проблем:


Файл шрифта можно не включать в проект:

C++
1
TTF_Font* font = TTF_OpenFont("assets/fonts/arial.ttf", 48);
Потому что он должен быть на всех Windows по стандартному пути:

C++
1
TTF_Font* font = TTF_OpenFont("C:/Windows/Fonts/arial.ttf", 48);
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
// #include<SDL3_image/SDL_image.h>
#include<iostream>
#include<stdio.h>
// #include"Resource.h"
// #include"Spr.h"
#include <SDL3_ttf/SDL_ttf.h>
 
 
static SDL_Window* window = NULL;
static SDL_Renderer* renderer = NULL;
// Resource* gold = nullptr;
// Spr* spr = nullptr;
 
static SDL_Texture* enTexture = NULL;
static SDL_Texture* ruTexture = NULL;
 
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();
    SDL_CreateWindowAndRenderer("SDL3 Game", 800, 640, 0, &window, &renderer);
    // gold = new Resource(renderer, {300, 300}, "assets/G_Idle.png");
    // spr = new Spr(renderer, { 150, 150 }, "assets/Warrior_Blue.png");
    
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    
    // std::locale utf8_locale("en_US.UTF-8"); // Or your desired UTF-8 locale
    // std::locale::global(utf8_locale); // Set the global locale.
    TTF_Font* font = TTF_OpenFont("assets/fonts/arial.ttf", 48);
 
    // Text in English
    SDL_Color enTextColor = { 200, 255, 200 };
    std::string enText = "Text in English";
    SDL_Surface* enSurface = TTF_RenderText_Blended(font, enText.c_str(),
        enText.size(), enTextColor);
    enTexture = SDL_CreateTextureFromSurface(renderer, enSurface);
    SDL_DestroySurface(enSurface);
 
    // Text in Russian
    SDL_Color ruTextColor = { 200, 255, 255 };
    SDL_Surface* ruSurface = TTF_RenderText_Blended(font, "Текст на русском",
        30, ruTextColor);
    ruTexture = SDL_CreateTextureFromSurface(renderer, ruSurface);
    SDL_DestroySurface(ruSurface);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
    return(SDL_APP_CONTINUE);
}
 
 
SDL_AppResult SDL_AppIterate(void* appstate)
{
    SDL_SetRenderDrawColor(renderer, 0, 211, 211, 211);
    SDL_RenderClear(renderer);
 
    // spr->update();
    // spr->draw();
 
    // if (gold) {
    //     gold->update();
    //     gold->draw();
    // }
 
    //player->update();
    //player->draw();
 
    // if (gold) {
    //     SDL_FRect playerDest = spr->getDest();
    //     SDL_FRect goldDest = gold->getDest();
    //     SDL_FRect result;
    //     SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
    //     if (SDL_GetRectIntersectionFloat(&playerDest, &goldDest, &result)) {
    //         //SDL_Log("w: %.2f\n", result.w);
    //         //SDL_Log("h: %.2f\n", result.h);
    //         //SDL_RenderRect(renderer, &result);
    //         if (result.w >= 125 && result.h >= 115) {
    //             delete gold;
    //         }
    //     }
    // }
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    SDL_FRect trect;
    // Text in English
    SDL_GetTextureSize(enTexture, &trect.w, &trect.h);
    trect.x = 10.f;
    trect.y = 20.f;
    // Draw the text
    std::cout << trect.w << " " << trect.h << std::endl;
    SDL_RenderTexture(renderer, enTexture, NULL, &trect);
 
    // Text in Russian
    SDL_GetTextureSize(ruTexture, &trect.w, &trect.h);
    trect.x = 10.f;
    trect.y = 100.f;
    // Draw the text
    SDL_RenderTexture(renderer, ruTexture, NULL, &trect);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
 
 
    SDL_RenderPresent(renderer);
 
    SDL_Delay(16);
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    switch (event->type)
    {
    case SDL_EVENT_QUIT:
        return SDL_APP_SUCCESS;
        break;
 
    default:
        break;
    }
    //player->handleEvents(event);
    // spr->handleEvents(event);
 
    return SDL_APP_CONTINUE;
}
 
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    SDL_DestroyTexture(enTexture);
    SDL_DestroyTexture(ruTexture);
}
Миниатюра
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.04.2025, 10:13
Цитата Сообщение от cosmos44 Посмотреть сообщение
std::locale utf8_locale("en_US.UTF-8"); // Or your desired UTF-8 locale
И не факт что у вас есть такая локаль.
1
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
07.04.2025, 10:23
cosmos44, попробуйте закомментировать эти строки:

C++
1
2
    // std::locale utf8_locale("en_US.UTF-8"); // Or your desired UTF-8 locale
    // std::locale::global(utf8_locale); // Set the global locale.
Компилируется ли проект в VS в этом случае? У меня без них компилируется без проблем с помощью MinGW GCC 11.2, который я взял из Qt 6.6.3
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.04.2025, 12:11
Цитата Сообщение от 8Observer8 Посмотреть сообщение
У меня ваш пример выводит текст на русском без проблем
Судя по описанию функции TTF_RenderText_Blended, он не использует locale, а принимает текст в определенной кодировке.
Function Parameters
TTF_Font * font the font to render with.
const char * text text to render, in Latin1 encoding.
SDL_Color fg the foreground color for the text.
Кодировка latin1 - кодовая страница, предназначенная для западноевропейских языков. Однобайтовая.

Для utf8 нужно использовать TTF_RenderUTF8_Blended()
Почти наверняка вам понадобится TTF_RenderUTF8_Blended(), если только вы не уверены, что у вас 1-байтовая кодировка Latin1. Символы US ASCII будут работать с любой из функций, но для большинства других символов Юникода, упакованных в const char *, потребуется UTF-8.
Но что бы utf8 литералы корректно хранились в обычных кавычках "", исходный текст должен быть в utf8 и компилятор должен об этом знать.

Это тема уже про кодировки.

Добавлено через 8 минут
Latin1, она же ISO/IEC 8859-1
8Observer8, как у вас на ней может выводится русские символы я
Таблица кодов символов ISO/IEC 8859-1
1
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,965
Записей в блоге: 227
07.04.2025, 13:48
cosmos44, а у вас тоже пример из сообщения #135 выводит текст на русском?
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 141
08.04.2025, 08:09  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
cosmos44, а у вас тоже пример из сообщения #135 выводит текст на русском?
На русском - каракули. Но я пока забил на данный вопрос - занимаюсь дальше.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.04.2025, 08:09
Помогаю со студенческими работами здесь

Неправильная отрисовка текстур в OpenGL
Всем доброго дня, недавно начал изучать как работать с графикой и решил повторить пример из урока, а именно - вращающийся кубик. Но...

QRubberBand медленно отрисовывается
С помощью QRubberBand выделяю участок наследника QGraphicsView для последующего сохранения, решил поставить ограничение на мышь чтобы если...

Не отрисовывается график
учусь делать оконное приложение вот по этому уроку. http://doc.qt.io/Qt-5/Qtqml-tutorials-extending-qml-example.html получилось...

Генератор текстур( с чего начать)
Всем привет, решил для своего 3д проекта написать генератор текстур, пока что необходима текстура булыжника. Никто не подскажет с помощью...

Qt с++ картинка постоянно отрисовывается
Ребята помогите пожалуйста, картинки один раз перемешивались и орисовывались и всё... а у меня эти действии повторяются каждый раз когда я...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
140
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru