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

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

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

Author24 — интернет-сервис помощи студентам
Не отрисовывается текстура! Путь, формат 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...

123
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 110
11.03.2025, 19:27  [ТС]
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Я имел ввиду, что мне надо было обновить страницу форума перед ответом. Я начал отвечать, отвлёкся, дописал ответ, ответил, но потом только увидел, что вы уже решили проблему.
Так дело в том, что все включено, а диагностики нет.
Пишет: Microsoft Visual Studio не удалось запустить ваш сеанс диагностики.

В нэте пишут запустить службу "VSStandardCollectorService150" - пробую запустить - ошибка запуска.

У меня не изучения C++. а борьба с геморроем на компьютере. Сейчас ищу решения.
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
11.03.2025, 20:04
Цитата Сообщение от cosmos44 Посмотреть сообщение
У меня не изучения C++. а борьба с геморроем на компьютере.
Отложите эту проблему с диагностикой на потом. У вас без неё, вроде, всё нормально стало собираться.

Цитата Сообщение от cosmos44 Посмотреть сообщение
Прочитал тут
В этом сообщении на скриншоте нормально выводится изображение. Кстати, для этого персонажа есть спрайтовая анимация? Можете в архиве приложить, если это не нарушает чьи-то авторские права? Лучше двигать персонажа с помощью Box2D - это сильно упростит и убыстрит процесс программирования игры. Вам не нежно будет самому проверять не упёрлись ли вы в забор, стену или другие препятствия. Иначе вам придётся каждый кадр самому пробегаться по всем объектам и проверять, не пересекли ли вы его границу. Я позже скину маленький пример, как перемещать персонажа. Перепишу следующий пример с Pygame и PyBox2D на SDL3 и C++, но со спрайтами:



Можете попробовать у себя его запустить. Здесь управление персонажем. Он не может пройти сквозь стену и вентилятор. Когда персонаж касается стены и вентилятора, то в консоль выводится сообщение.

Bash Скопировано
1
pip install Box2D Pygame
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
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
# pip install Box2D Pygame
 
import math
 
import pygame
from Box2D import (b2_dynamicBody, b2_kinematicBody, b2_staticBody, b2BodyDef,
                   b2ContactListener, b2FixtureDef, b2PolygonShape, b2Vec2,
                   b2World)
 
from debug_drawer import DebugDrawer
 
 
class ContactListener(b2ContactListener):
 
    def BeginContact(self, contact):
        userDataA = contact.fixtureA.userData
        userDataB = contact.fixtureB.userData
        print(userDataA["name"], "<--->", userDataB["name"])
 
def main():
 
    pygame.init()
 
    # Create a window of a given size with a title
    window = pygame.display.set_mode((268, 268))
    pygame.display.set_caption("PyBox2D and Pygame")
 
    # Create a physical world with zero gravity
    gravity=b2Vec2(0, 0)
    world = b2World(gravity)
 
    # The size of the physical world must be between 0.1 and 10
    # so a constant pixelsPerMeter is created to
    # translate from the pixel world to the Box2D physical world
    pixelsPerMeter = 30
 
    # Create DebugDrawer and configure it
    debugDrawer = DebugDrawer(window, pixelsPerMeter)
    debugDrawer.flags = { "drawShapes": True }
    world.renderer = debugDrawer
 
    # Create a ContactListener
    world.contactListener = ContactListener()
 
    # Creating a player body
    playerBodyDef = b2BodyDef() # Object for setting the position and type of the object
    # Set player position and type
    playerBodyDef.position = b2Vec2(200 / pixelsPerMeter, 100 / pixelsPerMeter)
    playerBodyDef.type = b2_dynamicBody
    # Prevent player from spinning
    playerBodyDef.fixedRotation = True
    # Create a player body
    playerBody = world.CreateBody(playerBodyDef)
    # The player must not fall asleep
    playerBody.sleepingAllowed = False
    # Create a player shape in the form of a rectangle
    playerShape = b2PolygonShape()
    playerShape.SetAsBox(10 / pixelsPerMeter, 20 / pixelsPerMeter)
    # Linking the player's body and form
    playerFixtureDef = b2FixtureDef()
    playerFixtureDef.shape = playerShape
    # Player density. This is analogous to mass
    playerFixtureDef.density = 1
    playerFixture = playerBody.CreateFixture(playerFixtureDef)
    playerFixture.userData = { "name": "player" }
 
    # Create a wall similar to the player, but now
    # the body type is static and density = 0
    wallBodyDef = b2BodyDef()
    # Set the position and type of the wall
    wallBodyDef.position = b2Vec2(100 / pixelsPerMeter, 150 / pixelsPerMeter)
    wallBodyDef.type = b2_staticBody
    wallBodyDef.angle = math.radians(30)
    # Create the body of the wall
    wallBody = world.CreateBody(wallBodyDef)
    # Create a player shape in the form of a rectangle
    wallShape = b2PolygonShape()
    wallShape.SetAsBox(10 / pixelsPerMeter, 50 / pixelsPerMeter)
    # Combine wall body and shape
    wallFixtureDef = b2FixtureDef()
    wallFixtureDef.shape = wallShape
    # Wall density. This is analogous to mass.
    wallFixtureDef.density = 0
    wallFixture = wallBody.CreateFixture(wallFixtureDef)
    wallFixture.userData = { "name": "wall" }
 
    # Create a kinematic fan
    # with a static body and density = 0
    fanBodyDef = b2BodyDef()
    # Set the position and type of the fan
    fanBodyDef.position = b2Vec2(200 / pixelsPerMeter, 200 / pixelsPerMeter)
    fanBodyDef.type = b2_kinematicBody
    fanBodyDef.angle = math.radians(0)
    # Create the body of the fan
    fanBody = world.CreateBody(fanBodyDef)
    # Create a rectangular fan shape
    fanShape = b2PolygonShape()
    fanShape.SetAsBox(5 / pixelsPerMeter, 30 / pixelsPerMeter)
    # Connect the fan body and the shape
    fanFixtureDef = b2FixtureDef()
    fanFixtureDef.shape = fanShape
    # Fan density. This is analogous to mass.
    fanFixtureDef.density = 0
    fanFixture = fanBody.CreateFixture(fanFixtureDef)
    fanFixture.userData = { "name": "fan" }
 
    # Dictionary for storing pressed keys
    keys = { "left": False, "right": False, "up": False, "down": False }
 
    clock = pygame.time.Clock()
    playerSpeed = 5
    fanSpeed = 180
 
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                key = pygame.key.name(event.key)
                keys[key] = True
            if event.type == pygame.KEYUP:
                key = pygame.key.name(event.key)
                keys[key] = False
 
        if keys["left"]:
            playerBody.linearVelocity.x = -playerSpeed
        if keys["right"]:
            playerBody.linearVelocity.x = playerSpeed
        if keys["up"]:
            playerBody.linearVelocity.y = -playerSpeed
        if keys["down"]:
            playerBody.linearVelocity.y = playerSpeed
 
        # Set the number of frames per second (60) and
        # calculate the time interval between frames dt (~0.16)
        dt = clock.tick(60) / 1000
 
        # Set the angle of the fan
        fanBody.angle += math.radians(fanSpeed * dt)
 
        # Take physics simulation one step further
        world.Step(dt, 3, 2)
 
        # Stop the player
        playerBody.linearVelocity = b2Vec2(0, 0)
 
        # Fill the screen with black color
        window.fill(0)
 
        # Drawing colliders
        world.DrawDebugData()
 
        # Updating the display
        pygame.display.flip()
 
if __name__ == '__main__':
    main()
Класс для рисования линий вокруг коллайдеров для отладки. Рисование отладочных линий можно отключить, если закомментировать строку world.DrawDebugData() в коде выше.

debug_drawer.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
import math
 
import pygame
from Box2D import b2Draw
 
 
class DebugDrawer(b2Draw):
 
    def __init__(self, window, pixelsPerMeter, thickness=3):
        super().__init__()
        self.window = window
        self.pixelsPerMeter = pixelsPerMeter
        self.thickness = thickness
 
    def DrawSolidPolygon(self, vertices, color):
        pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
            (vertices[0][0] * self.pixelsPerMeter, vertices[0][1] * self.pixelsPerMeter),
            (vertices[1][0] * self.pixelsPerMeter, vertices[1][1] * self.pixelsPerMeter),
            self.thickness)
        pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
            (vertices[1][0] * self.pixelsPerMeter, vertices[1][1] * self.pixelsPerMeter),
            (vertices[2][0] * self.pixelsPerMeter, vertices[2][1] * self.pixelsPerMeter),
            self.thickness)
        pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
            (vertices[2][0] * self.pixelsPerMeter, vertices[2][1] * self.pixelsPerMeter),
            (vertices[3][0] * self.pixelsPerMeter, vertices[3][1] * self.pixelsPerMeter),
            self.thickness)
        pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
            (vertices[3][0] * self.pixelsPerMeter, vertices[3][1] * self.pixelsPerMeter),
            (vertices[0][0] * self.pixelsPerMeter, vertices[0][1] * self.pixelsPerMeter),
            self.thickness)
 
    def DrawSolidCircle(self, center, radius, axis, color):
        pass
    def DrawPolygon(self, vertices, color):
        pass
    def DrawSegment(self, p1, p2, color):
        pass
    def DrawPoint(self, p, size, color):
        pass
    def DrawCircle(self, center, radius, color, drawwidth=1):
        pass
    def DrawTransform(self, xf):
        pass
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 110
11.03.2025, 20:24  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
В этом сообщении на скриншоте нормально выводится изображение. Кстати, для этого персонажа есть спрайтовая анимация? Можете в архиве приложить, если это не нарушает чьи-то авторские права? Лучше двигать персонажа с помощью Box2D - это сильно упростит и убыстрит процесс программирования игры. Вам не нежно будет самому проверять не упёрлись ли вы в забор, стену или другие препятствия. Иначе вам придётся каждый кадр самому пробегаться по всем объектам и проверять, не пересекли ли вы его границу. Я позже скину маленький пример, как перемещать персонажа. Перепишу следующий пример с Pygame и PyBox2D на SDL3 и C++, но со спрайтами:
Так это же на Python. Я начинал изучать Python - кое чего достиг в изучении. Вышлю архив - игрушка 2D. В общем там все понятно, но мне ни это нужно было. Начал писать IPTV плеер на питон. но то что я хотел (функционал) - знающие люди написали, что требуется писать на С, так как возможности Python ограничены.
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
12.03.2025, 13:07
Цитата Сообщение от cosmos44 Посмотреть сообщение
Вышлю архив - игрушка 2D
Я нашёл этот пак через Chrome с помощью: Menu > Search with Google Lens: https://pixelfrog-assets.itch.io/tiny-swords Спрайты рыцаря с мечом находятся в папке: Factions/Knights/Troops/Warrior

Миниатюры
SDL3_image - не отрисовывается текстура  
Вложения
Тип файла: mp4 Видео анимаций спрайтов пака.mp4 (1.20 Мб, 0 просмотров)
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 110
12.03.2025, 15:41  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Я нашёл этот пак через Chrome с помощью: Menu > Search with Google Lens: https://pixelfrog-assets.itch.io/tiny-swords Спрайты рыцаря с мечом находятся в папке: Factions/Knights/Troops/Warrior
ОК. спасибо.

Реализация 3D - пример - https://examples.libsdl.org/SD... eneye-008/

Движение W, A, S, D + мышка
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
13.03.2025, 13:34
Цитата Сообщение от cosmos44 Посмотреть сообщение
У меня не изучения C++. а борьба с геморроем на компьютере.
Надо стараться расставлять расставлять приоритеты и разбивать задачи на подзадачи. Вы решили проблему с отображением спрайта. Получили изображение рыцаря. Надо двигаться дальше. Ставить следующую цель. Если задача кажется сложной, то надо разбивать её на подзадачи. Например, у вас есть код, как сделать спрайтовую анимацию на SDL3 для бегущего человечка. В паке ассета выше с рыцарем есть спрайтовые анимации покоя, ходьбы, атаки и т.д. Реализуйте перемещение рыцаря с анимацией ходьбы и анимацию покоя. Добавьте препятствий, чтобы рыцарь не проходил сквозь них - для этой цели лучше сразу взять Box2D, как в примере в сообщении 102 на Pygame и Box2D. Box2D очень сильно облегчит вам процесс создания игр. Знания этого физического движка пригодятся, например, если вы потом возьмёте Unity. С помощью Box2D можно переводить эти туториалы с Unity и C# на SDL3 и C++: http://noobtuts.com/unity/ (сайт работает с VPN). Unity использует Box2D и в Unity практически точно такие же настройки для 2D-физики, как в Box2D. Добавьте мешочки с золотом из пака и отображайте собранное количество монет в виде текста + число. Разбейте эти задачи на подзадачи. Сначала сделайте анимацию покоя. Эту подзадачу разбейте ещё на подзадачи - спрайты анимации рыцаря находятся на расстоянии друг от друга:



Это неудобно для использования в SDL3. Я нарезал спрайты в GIMP и расположил их друг за другом. В GIMP можно отобразить сетку заданного размера, в данном случае, это сетка с ячейками 96x96 пикселей. Можно переносить нарезанные спрайты мышкой в GIMP и выравнивать их ориентируясь на заданную сетку:



В результате получается sprite sheet, который удобно использовать в SDL3:



Экспортировать из GIMP надо в формат PNG, чтобы был альфа канал (канал прозрачности). GIMP - это бесплатный редактор изображений похожий на Photoshop. Есть ещё Krita и какие-то другие. GIMP занимает 1 GB. Вы можете нажать правой кнопкой мыши по spritesheet выше и сделать спрайтовую анимацию покоя - это ближайший шаг, что делать дальше. Если возникнут проблемы, то создавайте новые темы. Если проблема связана с C++, то создавайте тему в C++ разделе. Если проблема связана с какими-то игровыми механикам или с SDL3, то создавайте тему в разделе Программирование игр. Если хотите, чтобы вашу игру запускали и тестировали, то создавайте тему в разделе Бета-тестирование. Можете описывать процесс разработки игры в своём блоге - здесь на форуме можно создать блог.

Ещё более удобно закинуть нарезанные спрайты в Texture Packer и экспортировать в два файла PNG и JSON. В PNG будет атлас спрайтов, а в JSON информация: имена спрайтов, x, y, width, height. Я использую библиотеку simdjson для парсинга JSON.

Цитата Сообщение от cosmos44 Посмотреть сообщение
Я начинал изучать Python - кое чего достиг в изучении.
Я время от времени практикуюсь с Python. На нём можно быстро сделать прототип примера на OpenGL. Его легко перевести на C++, особенно, если использовать PyOpenGL, PyGLM, PyBox2D, pugixml На нём проще практиковаться с OpenGL, делая простые учебные примеры для кого-то или для себя. На КиберФоруме можно много найти задачек для практики или самому придумывать на основе других задач или комбинируя их. Python удобен, как расширенный калькулятор. Удобен для автоматизации процессов моделирования и анимирования в Blender.

Цитата Сообщение от cosmos44 Посмотреть сообщение
Реализация 3D - пример
Я делаю перемещение от первого лица с использованием библиотеки для 3D физики Bullet Physics: демка в браузере. 3D-графику рисую на шейдерном OpenGL. Для создания окна и обработки событий мыши и клавиатуры использую SDL3. Собираю в WebAssembly (WASM) с помощью Emscripten и MinGW GCC 11.2. MinGW взял из Qt. Для сборки в EXE использую MinGW, потому что мне проще собирать из консоли и кодить в легковесном редакторе Sublime Text 4.

В Bullet Physics есть механизм для помощи в рисовании коллайдеров. Он автоматически вызывает метод куда передаёт начала и концы отрезков и цвет отрезков. Между координатами отрезков можно нарисовать отрезки:



Это необходимо, чтобы видеть коллайдеры во время разработки приложений, иначе, будет невозможно их увидеть. Отображение коллайдеров легко отключается. Это общая практика практически для всех физических движков. Я читал, что такой механизм есть в физическом движке PhysX. Этот механизм есть в Box2D, OimoPhysics и т.д.

Управляю коллайдером-сферой с вращением только вокруг вертикальной оси. Двигаю сферу на W и S, а вращаю вокруг Y с помощью мышки. Камере присваиваю позицию (со смещением по Y) и угол сферы. Объекты загружаю из файлов формата .dae (Collada) - этот формат легко парсить с помощью pugixml, потому что это XML: демка в браузере с загруженными 3D-моделями



Миниатюры

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

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

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

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

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

0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 110
13.03.2025, 17:44  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Надо стараться расставлять расставлять приоритеты и разбивать задачи на подзадачи.
В сравнении Python + PyGame с С++ SDL3 довольно сложно для новичка как я.
У меня не стоит задача - писать игры. Задача понять хотя бы 60% C++ на основе игры. Для меня интересно видеть результат визуально на данном этапе изучения.
На данный момент есть желание что то написать мелкое 3D без сторонних библиотек 3D. Что бы понимать процесс написания на более низком уровне. Но в данный момент мало времени + затормозило отображение текстуры.

Если будет возможность, взгляните на код новичка (файл.zip). c C++ намного сложнее - прорвемся.

cosmoProject.zip

И еще вопрос?! Использование BOX2d с С++ проще для понимания чем SDL3 + C ?
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
13.03.2025, 19:48
Цитата Сообщение от cosmos44 Посмотреть сообщение
В сравнении Python + PyGame с С++ SDL3 довольно сложно для новичка как я.
Да, как правило, на Python проще и быстрее писать. На нём проще изучать основы OpenGL. Легко устанавливать необходимые библиотеки. Но есть субъективные минусы. Например, на C++ гораздо проще создать EXE, APK и WASM. Создание исполняемый файлов из программ на Python - это против природы Python. Он должен исполняться из исходников, без сборки исполняемых файлов. Субъективный минус Python, на мой взгляд, в том, что на нём автор Bullet Physics извратил его до неузнаваемости, создав PyBullet.

Цитата Сообщение от cosmos44 Посмотреть сообщение
У меня не стоит задача - писать игры. Задача понять хотя бы 60% C++ на основе игры. Для меня интересно видеть результат визуально на данном этапе изучения.
Я к программированию игр отношусь как к тренажёру, как к хобби. Это и увлекательно и это практика. Есть свобода, что можно изучать. Можно подключить базу данных SQLite к игрушке, чтобы сохранять таблицу рекордов. Можно сделать сетевую игрушку по интернету - крестики-нолики, шашки, морской бой и т.д. Это тренировка клиент серверного-взаимодействия. Можно изучать линейную алгебру на шейдерном OpenGL. Когда вы потихоньку развиваете игрушку, то за одно практикуетесь в C++. Можно алгоритмы какие-нибудь практиковать, например, поиск пути A* и Flood fill - это алгоритм можно использовать для открытия пустых ячеек в Сапёре и игре Го. В 2D вам надо не упустить возможность дальше двигаться с демкой, которую вы начали. Вы вывели рыцаря, а теперь ему нужно добавить анимацию покоя - это 6 кадров. У вас уже есть пример бегущего человечка. Возьмите этот пример и сделайте вывод кадров рыцаря.

Цитата Сообщение от cosmos44 Посмотреть сообщение
Использование BOX2d с С++ проще для понимания чем SDL3 + C ?
Box2D в самом начале требует понимания, что нужно создать объект типа World - это физический 2D-мир. Этому миру можно задать гравитацию, но в примере с рыцарем гравитация должна быть нулевой. Нужно создать динамический объект для рыцаря. Нужно сделать, чтобы этот объект можно было перемещать клавишами, задавая скорость или действуя силами. При отрисовке рыцаря нужно считывать координаты динамического объекта и рисовать его по этим координатам. Box2D автоматически вызовет обработчик столкновения, где можно будет узнать, какие объекты столкнулись - если это стена, дерево или забор, то ничего не делать, а если это враг, то убрать часть жизней, если монеты, то увеличить их число и т.д. Вы можете посмотреть код на Python из сообщения #102 и спросить, какая строчка кода непонятна. Код Box2D на Python и C++ абсолютно одинаковый.

Цитата Сообщение от cosmos44 Посмотреть сообщение
Если будет возможность, взгляните на код новичка (файл.zip). c C++ намного сложнее - прорвемся.
Не запускается. Пишет, что файл не может найти. Надо было использовать относительные пути, а не абсолютные. Вы лучше знаете, где что поправить. Надо заменить на пути вида: "./images/bg1.png"

Цитата Сообщение от cosmos44 Посмотреть сообщение
На данный момент есть желание что то написать мелкое 3D без сторонних библиотек 3D.
Это слишком сложно для вас на данном этапе. Вам нужно заставить рыцаря двигаться с помощью клавиш W, A, S, D или стрелок. Сделайте, чтобы когда рыцарь не двигается, то проигрывается анимация покоя, а когда вы нажимаете клавиши для перемещения, нужно чтобы проигрывалась анимация движения. Когда вы отпустили клавиши, то нужно чтобы опять проигрывалась анимация перемещения. Не забрасывайте сейчас эту задачу. Она простая, но как раз вам нужно набивать руки на очень простых вещах.
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
14.03.2025, 22:05
У меня мало опыта с SDL3, поэтому я переписал прошлый пример с нуля без копипаста. Я думаю, что если чаще и регулярнее так переписывать, то всё лучше будут запоминаться функции и будет проще с каждым разом.

Я заменил бегущего человечка на анимацию покоя рыцаря. У человечка размер кадра 128x128, а кадров 4 штуки:
C++ Скопировано
1
2
3
4
5
6
SDL_FRect frames[4] = {
    { 0, 0, 128, 128 }, // Frame 1
    { 128, 0, 128, 128 }, // Frame 2
    { 0, 128, 128, 128 }, // Frame 3
    { 128, 128, 128, 128 } // Frame 4
};
У рыцаря размер кадра 96x96, а кадров 6 штук. Их удобнее расположить не в одну линию, как ранее, а в две, так как проще посчитать (x, y) на атласе:
C++ Скопировано
1
2
3
4
5
6
7
8
SDL_FRect frames[6] = {
    { 0, 0, 96, 96 }, // Frame 0
    { 96, 0, 96, 96 }, // Frame 1
    { 192, 0, 96, 96 }, // Frame 2
    { 0, 96, 96, 96 }, // Frame 3
    { 96, 96, 96, 96 }, // Frame 4
    { 192, 96, 96, 96 } // Frame 5
};
Нужно поменять 4 на 6 в расчёте номера следующего кадра анимации:
C++ Скопировано
1
2
3
4
5
6
    // Increment frame index and loop back to 0 when necessary
    if (animationTime > animationPeriod)
    {
        frameIndex = (frameIndex + 1) % 6;
        animationTime = 0.f;
    }
Название: idle.png
Просмотров: 143

Размер: 8.3 Кб

Собрал в WASM, для запуска в браузере в один клик: https://blue-warrior-sprite-an... tlify.app/

Собрал в APK из WASM с помощью Cordova. Собрал в EXE c помощью MinGW 11.2 из консоли. Прикрепил проект с батниками для сборки.



Следующим шагом может быть - написать обработчики нажатий клавиш W, A, S, D и/или клавиш стрелок. Для начала, чтобы в консоль выводилось направление, то есть текст: up, left, down, right. Это шаг к движению персонажа по нажатию клавиш. В будущем можно было бы добавить врагов, которые бы искали путь с помощью алгоритма A*. Есть пример на WebGL: Алгоритм поиска пути A*. В общем, есть от чего отталкиваться. Можно писать разные демки на C++, опираясь не предыдущий опыт и тем самым практиковаться в программировании. Предыдущий опыт - это отображение текстуры, спрайтовая анимация покоя, а следующий опыт - это нажатие клавиш, движение персонажа, переключение на анимацию ходьбы, добавление преград, запрет персонажу проходить сквозь преграды, добавление монеток, сбор монеток и отображение их. Это всё пишется кодом на C++, а значит идёт практика. Например, вы поймёте, как преобразовать число в строку, чтобы отобразить в виде текста на экране.

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
#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>
 
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *spriteTexture = NULL;
 
int frameIndex = 0;
int lastTime = 0;
float animationTime = 0.f;
const float animationPeriod = 0.1f;
 
// Define animation frame
SDL_FRect frames[6] = {
    { 0, 0, 96, 96 }, // Frame 0
    { 96, 0, 96, 96 }, // Frame 1
    { 192, 0, 96, 96 }, // Frame 2
    { 0, 96, 96, 96 }, // Frame 3
    { 96, 96, 96, 96 }, // Frame 4
    { 192, 96, 96, 96 } // Frame 5
};
 
// 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/sprites/blue-warrior/idle.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 = frames[frameIndex];
    SDL_FRect destRect = { 100, 100, 128, 128 };
 
    // 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 > animationPeriod)
    {
        frameIndex = (frameIndex + 1) % 6;
        animationTime = 0.f;
    }
 
    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);
}
CMakeLists.txt

Code Скопировано
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
cmake_minimum_required(VERSION 3.20)
project(blue-warrior-sprite-animation-sdl3)
add_executable(app)
 
target_compile_features(app PRIVATE cxx_std_20)
 
# Check for WebAssembly
if (CMAKE_SYSTEM_NAME MATCHES "Emscripten")
    target_link_options("app" PRIVATE "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/assets/sprites/blue-warrior/idle.png@/assets/sprites/blue-warrior/idle.png")
    set_property(TARGET "app" APPEND PROPERTY LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/assets/sprites/blue-warrior/idle.png")
endif()
 
target_sources(app
PRIVATE
    src/main.cpp
)
 
find_package(SDL3)
find_package(SDL3_image)
target_link_libraries(app PRIVATE SDL3_image::SDL3_image SDL3::SDL3)
 
# Check for Windows
if (WIN32)
    # Copy the assets folder to the dist folder
    add_custom_command(TARGET app POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${CMAKE_SOURCE_DIR}/assets $<TARGET_FILE_DIR:app>/assets)
 
    target_link_options(app PRIVATE -static)
endif()
Миниатюры
SDL3_image - не отрисовывается текстура
Вложения
Тип файла: zip app-apk.zip (3.26 Мб, 0 просмотров)
Тип файла: zip app-exe.zip (1,018.8 Кб, 4 просмотров)
Тип файла: zip blue-warrior-sprite-animation-sdl3.zip (13.5 Кб, 0 просмотров)
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
15.03.2025, 10:26
Очень важный шаг, который необходимо сделать и он очень простой - это подключение Box2D. Я прикрепил собранную библиотеку для MSVC и MinGW GCC 11.2. Можно подключить через CMake - в папке lib есть папка cmake, либо в VS подключить через настройке в проекте типа vcxproj. Не факт, что всегда можно подключать библиотеку собранную на другом компиляторе, особенно, MinGW, но у МSVC значительно больше шансов. В архиве box2d-2.4.1-prefix.zip кроме MinGW-сборки для Desktop есть сборка для Web, а в примере есть батники для конфигурирования и сборки для Desktop и Web. Если не прокатит подключение собранной библиотеки, то можно собрать Box2D из исходников с помощью CMake-GUI - тоже очень полезный опыт, так как на C++ очень часто бывает, что нет pre-built библиотеки и нужно самому собирать из исходников с GitHub с помощью CMake.

Прикрепил пример на SDL3 в котором подключена Box2D. Пример подключает Box2D и SDL3 в CMakeLists.txt:

Code Скопировано
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cmake_minimum_required(VERSION 3.20)
project(print-gravity-box2d-sdl3)
add_executable(app)
 
target_compile_features(app PRIVATE cxx_std_20)
 
target_sources(app
PRIVATE
    src/main.cpp
)
 
find_package(box2d)
find_package(SDL3)
target_link_libraries(app PRIVATE box2d::box2d SDL3::SDL3)
 
target_link_options(app PRIVATE -static)
В коде на C++ создаётся физический мир, задаётся гравитация и значение гравитации выводится в консоль:

C++ Скопировано
1
2
3
4
5
    b2Vec2 gravity(0.f, 9.8f);
    world = new b2World(gravity);
    float gx = world->GetGravity().x;
    float gy = world->GetGravity().y;
    std::cout << "gravity = (" << gx << ", " << gy << ")" << std::endl;
Число 9.8 - это значение ускорения свободного падения. Этим значением можно регулировать, как быстро падают объекты. Хорошо бы, чтобы вы запустили этот пример у себя. Это большой шаг. Ещё был бы большой шаг - собрать Box2D из исходников с помощью CMake и MSVC. Я описал каждый шаг с большим количеством скриншотов для CMake и VS 2022: Installation -> Setting up

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
#define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
 
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <box2d/box2d.h>
 
#include <iostream>
 
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
b2World *world;
 
// 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);
 
    b2Vec2 gravity(0.f, 9.8f);
    world = new b2World(gravity);
    float gx = world->GetGravity().x;
    float gy = world->GetGravity().y;
    std::cout << "gravity = (" << gx << ", " << gy << ")" << std::endl;
 
    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);
 
    // Draw your stuff here
    // ...
 
    // Update the screen
    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 will clean up the window/renderer for us
 
    delete world;
}
Вложения
Тип файла: zip box2d-2.4.1-prefix.zip (692.2 Кб, 0 просмотров)
Тип файла: zip box2d-2.4.2-msvc.zip (1.07 Мб, 0 просмотров)
Тип файла: zip print-gravity-box2d-sdl3.zip (3.7 Кб, 0 просмотров)
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
15.03.2025, 11:55
Ещё они очень важный шаг - это рисование коллайдеров. Box2D предоставляет класс b2Draw, от которого можно наследоваться и переопределить два метода - одни для рисования прямоугольников, а другой для рисования окружностей:

C++ Скопировано
1
2
3
4
5
6
7
8
9
10
11
class DebugDrawer : public b2Draw
{
/* ... */
public:
    virtual void DrawSolidPolygon(const b2Vec2 *vertices,
        int32 vertexCount, const b2Color &color) override;
 
    virtual void DrawSolidCircle(const b2Vec2 &center,
        float radius, const b2Vec2 &axis, const b2Color &color) override;
/* ... */
};
В цикл рисования нужно добавить вызов world->DebugDraw();, тогда будут вызываться переопределённые методы. Эти методам передаются данные с помощью которых можно нарисовать отрезки заданных цветов. Рисования коллайдеров - это очень важная вещь для отладки. Легко будет настроить расположение границ коллайдеров относительно спрайтов и тайлов. Рисование коллайдеров можно отключить закомментировав строку world->DebugDraw();

Небольшой пример рисования коллайдеров на SDL3:

Демка в браузере, собранная в WASM



Миниатюры

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

Вложения
Тип файла: zip debug-drawer-box2d-sdl3.zip (5.8 Кб, 0 просмотров)
Тип файла: zip app-exe.zip (1.56 Мб, 0 просмотров)
Тип файла: zip app-apk.zip (3.22 Мб, 0 просмотров)
Тип файла: zip app-wasm.zip (376.9 Кб, 0 просмотров)
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
16.03.2025, 03:28
Вот как я поступил, приставив себя на вашем месте. Я выкладывал маленький пример на Python и Pygame для определения контакта игрока с объектами средствами Box2D в сообщении #102. За вас Box2D делает проверку и делает это оптимизированно, то есть если даже у вас будет очень большая карта, то он быстро найдёт объект, с которым произошёл контакт. Тем более, что Box2D используется многими игровыми движками, например, в Unity и была протестирована множество раз. Box2D значительно упрощает решение и экономит время. Так как если этот пример писать без Box2D, то ушло бы гораздо больше сил и времени. На C++ код выглядит почти один в один, как на Python, но со спецификой C++. В процессе переписывания волей не волей изучаешь C++ на практике. Переписал пример из Python/Pygame/PyBox2D на C++/SDL3/Box2D: демка в браузере WASM Управление - WASD либо клавиши стрелки.



Миниатюры

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

Вложения
Тип файла: zip player-and-fan-box2d-sdl3.zip (536.1 Кб, 0 просмотров)
Тип файла: zip app-exe.zip (2.45 Мб, 0 просмотров)
Тип файла: zip app-wasm.zip (1.16 Мб, 0 просмотров)
Тип файла: zip app-apk.zip (4.09 Мб, 0 просмотров)
Тип файла: zip player-and-fan-pybox2d-pygame.zip (2.6 Кб, 0 просмотров)
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 110
16.03.2025, 16:59  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Вот как я поступил, приставив себя на вашем месте.
Спасибо за помощь и ваш труд. Обязательно дойду и попробую все.
В данный момент нет времени. По этому и нет вопросов. С понедельника начнем.

В файле ниже пример геометрии, движения и отражения. о без библиотек. Если плохо видно, уменьшите размер символов до 8.
test.zip
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
16.03.2025, 22:41
Цитата Сообщение от cosmos44 Посмотреть сообщение
В файле ниже пример геометрии, движения и отражения. о без библиотек.
В прикреплённых вами файлах находится реализация маленького физического движка. Эти файлы в совокупности надо называть библиотекой физики, как и Box2D. Разницы нет в том, как вы подключаете библиотеку - в виде исходных файлов (только .h или .h + .cpp) или в виде .lib или .a или .dll. Вы можете так же скачать исходники Box2D, закинуть их в себе в проект и подключить к проекту, как и эту библиотеку. Вы прикрепили header-only библиотеку - такому же точно классу библиотек принадлежит, например, библиотека GLM. Есть свои плюсы и минусы в написании своей библиотеки с нуля (или развитии чье-то маленькой не совсем с нуля) и в использовании общей библиотеки. Плюсы и минусы зависят от обстоятельств.

Просто прикреплённая вами библиотека более понятна для вас. Как вариант, можете сделать с помощью предоставленной вами библиотеки такой пример, где можно двигать персонаж (пусть будет тоже круг) и выведите несколько прямоугольников с разными цветами, чтобы в консоль выводилось с каким прямоугольником произошёл контакт. Например, выводите прямоугольники разных цветов - красный, зелёный и синий. Управляйте кругом клавишами. Если круг коснулся красного прямоугольника, то выводите в консоль - red, если зелёного, то green, если синего, то blue. Практикуйтесь на небольших примерах и комбинируйте эти примеры. После того, как сделаете пример с выводом цвета прямоугольника при касании, нужно сделать пример, чтобы круг не проходил сквозь прямоугольник, то есть, чтобы главный персонаж игры не проходил сквозь препятствия.

На Box2D можно двигаться вдоль стены с заданным коэффициентом трения, то есть скользить с заданным трением, как на гиф-анимации ниже. Не знаю, реализовано ли это на той кастомной физической библиотеке. Я сделал комбинацию примера со спрайтовой анимацией из сообщения #109 и примера с движением коллайдера-окружности с определением контакта из сообщения #112. Здесь добавил анимацию ходьбы. Сделал два круговых коллайдера для главного героя.

Демка в браузере, собранная в WebAssembly



Миниатюры
SDL3_image - не отрисовывается текстура
Вложения
Тип файла: zip warrior-control-box2d-sdl3.zip (573.5 Кб, 7 просмотров)
Тип файла: zip app-exe.zip (2.85 Мб, 0 просмотров)
Тип файла: zip app-wasm.zip (1.25 Мб, 3 просмотров)
Тип файла: zip app-apk.zip (4.19 Мб, 3 просмотров)
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
20.03.2025, 18:53
Скорее всего, вам было бы интересно и полезно писать короткие игровые демки очень простых мини-игр. Например, я переписал код демки Змейка из текстового туториала NoobTuts Snake Game на PySDL3. В этом туториале очень простой английский. Можно за одно поупражняться в английском. Попробуйте переписать мой код с Python на C++, читая тот туториал. Для этой игровой демки нужно уметь рисовать квадраты заданного цвета с помощью SDL3. В целом PySDL очень близко повторяет оригинальный SDL3 на C/C++. Вместо списка Python используйте std::vector из стандартной библиотеки C++.

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
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
import ctypes
import os
import time
from random import randint
 
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
 
import sdl3
 
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
 
windowWidth = 400
windowHeight = 400
 
snake = [(20, 20)] # Snake list of (x, y) positions
snakeDir = (10, 0) # Snake movement direction
 
interval = 0.2 # update interval in milliseconds
keyFrameTime = 0
lastTime = 0
 
keys = { "left": False, "right": False, "up": False, "down": False }
 
food = [] # Food list of type (x, y)
 
def vecAdd(v1, v2):
    return (v1[0] + v2[0], v1[1] + v2[1])
 
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
    global windowWidth
    global windowHeight
 
    if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
        sdl3.SDL_Log("Couldn't initialize SDL: %s", sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    if not sdl3.SDL_CreateWindowAndRenderer("Snake NoobTuts".encode(), windowWidth, windowHeight, 0, window, renderer):
        sdl3.SDL_Log("Couldn't create window/renderer: %s", sdl3.SDL_GetError())
        return sdl3.SDL_APP_FAILURE
 
    sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
 
    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_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_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_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_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_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_D or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_RIGHT:
            keys["right"] = False
 
    return sdl3.SDL_APP_CONTINUE
 
def keyboard():
    global snakeDir # important if we want to set it to a new value
 
    if keys["up"]:
        snakeDir = (0, -10)
    if keys["down"]:
        snakeDir = (0, 10)
    if keys["left"]:
        snakeDir = (-10, 0)
    if keys["right"]:
        snakeDir = (10, 0)
 
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
    global interval
    global lastTime
    global keyFrameTime
    global snake
    global snakeDir
 
    # As you can see from this, rendering draws over whatever was drawn before it
    sdl3.SDL_SetRenderDrawColor(renderer, 33, 33, 33, sdl3.SDL_ALPHA_OPAQUE)
    sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
 
    keyboard();
 
    currentTime = sdl3.SDL_GetTicks()
    deltaTime = (currentTime - lastTime) / 1000
    lastTime = currentTime
 
    # Game tick
    keyFrameTime += deltaTime
    if keyFrameTime > interval:
        # Insert new position in the beginning of the snake list
        snake.insert(0, vecAdd(snake[0], snakeDir))
        # Remove the last element
        snake.pop()
 
        # Spawn food
        r = randint(0, 20) # Spawn food with 5% chance
        if r == 0:
            # Random spawn position
            x = randint(0, int(windowWidth / 10)) * 10
            y = randint(0, int(windowHeight / 10)) * 10
            food.append((x, y))
            print("spawn food:", x, y)
 
        # Let the snake eat the food
        (hx, hy) = snake[0]          # Get the snake's head x and y position
        for x, y in food:            # Go through the food list
            if hx == x and hy == y:  # Is the head where the food is?
                snake.append((x, y)) # Make the snake longer
                food.remove((x, y))  # Remove the food
 
        # Start a new frame
        keyFrameTime = 0
 
    rect = sdl3.SDL_FRect()
    rect.w = 10
    rect.h = 10
 
    # Draw a food
    sdl3.SDL_SetRenderDrawColor(renderer, 128, 128, 255, sdl3.SDL_ALPHA_OPAQUE)
    for x, y in food:
        rect.x = x
        rect.y = y
        sdl3.SDL_RenderFillRect(renderer, rect)
 
    # Draw a snake
    sdl3.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl3.SDL_ALPHA_OPAQUE)
    for x, y in snake:
        rect.x = x
        rect.y = y
        sdl3.SDL_RenderFillRect(renderer, rect)
 
    sdl3.SDL_RenderPresent(renderer)
    return sdl3.SDL_APP_CONTINUE
 
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
    ... # SDL will clean up the window/renderer for us.
Миниатюры
SDL3_image - не отрисовывается текстура
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
20.03.2025, 19:13
Движок форума добавляет пустые пробелы в пустых строках, поэтому прикрепил исходники.

https://rextester.com/MBDA81854

Bash Скопировано
1
2
pip install PySDL3
py main.py


Миниатюры
SDL3_image - не отрисовывается текстура
Вложения
Тип файла: zip snake-noobtuts-pysdl3.zip (1.9 Кб, 0 просмотров)
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
30.03.2025, 13:41
cosmos44, я стараюсь каждый день уделять хотя бы 30 минут в день для практики с SDL3 и OpenGL с самыми базовыми упражнениями. Пока выкладываю на Python, а на C++ не выкладываю. Вам может быть будет интересно и полезно переписывать мои примеры с Python на С++. Я сделал две отдельные темы на официальном репозитории PySDL3, где в первой используется 2D API, а во второй используется чистый шейдерный OpenGL 2.1:

На данный момент сделано 19 маленьких примеров на PySDL3 и 7 базовых примеров на OpenGL. Я считаю, что вам лучше переключиться с 2D API на чистый шейдерный OpenGL, потому что 2D API крайне ущербный - в нём много чего не хватает, либо это сделано неэффективно. Как, например, вывод текста или скрыто и непонятно, как сделано. Нет детектирования клика по объекту, а на OpenGL это делается легко методом цветового ID. Либо делается сложно и неэффективно, например, чтобы повернуть прямоугольник на 2D API вам нужно сначала нарисовать его на текстуре, а потом повернуть созданную текстуру и нарисовать текстуру, а на OpenGL и PyGLM это делается гораздо понятнее и более эффективно. PyGLM - библиотека для работы с линейной алгеброй. OpenGL намного более прозрачный с точки зрения понимания математики и процессов компьютерной графики. На OpenGL вы можете строить графики функций и геометрические фигуры не только в 2D, но и в 3D. Вам несложно будет в дальнейшем переписывать примеры с Python, PySDL3, PyOpenGL, PyGLM и т.д. на C++, SDL3, OpenGL, GLM и т.д.
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 110
01.04.2025, 19:40  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
cosmos44, я стараюсь каждый день уделять хотя бы 30 минут в день для практики с SDL3 и OpenGL с самыми базовыми упражнениями.
Спасибо за уделенное мне внимание. В данный момент нет времени.
0
8 / 6 / 4
Регистрация: 21.05.2022
Сообщений: 110
Вчера, 17:22  [ТС]
Цитата Сообщение от 8Observer8 Посмотреть сообщение
cosmos44, я стараюсь каждый день уделять хотя бы 30 минут в день для практики с SDL3 и OpenGL с самыми базовыми упражнениями.
Поясните пожалуйста мне логику анимации "на пальцах" (без переменных).
1) У нас есть int currentTime = SDL_GetTicks();
2) Есть массив из 6-ти фреймов (считаю длинным кодом, но все же давайте на данном примере).
3)....
4)....
За ранее спасибо.
0
7965 / 2915 / 489
Регистрация: 05.10.2013
Сообщений: 7,796
Записей в блоге: 209
Вчера, 18:36
Цитата Сообщение от cosmos44 Посмотреть сообщение
Поясните пожалуйста мне логику анимации "на пальцах" (без переменных).
С огромным удовольствием! Скопирую код под спойлер, чтобы удобнее было подглядывать в него:

Код

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
#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>
 
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;
 
// Define animation frame
SDL_FRect frames[6] = {
    { 0, 0, 96, 96 }, // Frame 0
    { 96, 0, 96, 96 }, // Frame 1
    { 192, 0, 96, 96 }, // Frame 2
    { 0, 96, 96, 96 }, // Frame 3
    { 96, 96, 96, 96 }, // Frame 4
    { 192, 96, 96, 96 } // Frame 5
};
 
// 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/sprites/blue-warrior/idle.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 = frames[frameIndex];
    SDL_FRect destRect = { 100, 100, 96, 96 };
 
    // 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)
    {
        frameIndex = (frameIndex + 1) % 6;
        animationTime = 0.f;
    }
 
    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);
}


Пример маленький, потому я постараюсь объяснить с самого начала, потому что повторение - мать учения. В SDL3 появилась новая очень удобная концепция - отказ от функции main() в пользу четырёх функций:
  • SDL_AppInit - тело этой функция, то есть команды в фигурных скобках, срабатывает только одни раз. Как только вы запустили приложение, то команды внутри тела функции сработают первыми. Здесь можно, например, загрузить такие файлы, как: файлы изображений, звуковые файлы, фалы шрифтов. Здесь можно вызвать функции для расстановки игровых объектов.
  • SDL_AppEvent - тело этой функции срабатывает всякий раз когда происходит какое-либо событие. Например: нажатие кнопки клавиатуры, кнопки мыши, движение мышью, изменение размеров окна и много другое.
  • SDL_AppIterate - тело этой функции срабатывает постоянно по кругу, много раз в секунду. Здесь, например, вызываются функции для рисования объектов. Здесь можно изменять положения или состояния игровых объектов - например, можно передвинуть змейку и нарисовать её новое состояние в новых клеточках игрового поля
  • SDL_AppQuit - тело этой функции сработает, когда вы нажали кнопку для закрытия окна. Перед тем как завершить приложение, в этой функции можно освободить выделенные ресурсы. В C++ нет сборщика мусора и поэтому, например, созданные с помощью ключевого слова "new" объекты должны быть удалены в этой функции с помощью ключевого слова "delete"

Теперь по поводу работы спрайтовой анимации.

1) Создание текстуры из файла. Первым делом в теле функции SDL_AppInit загружаем файл idle.png с кадрами спрайтовой анимации:

C++ Скопировано
1
spriteTexture = IMG_LoadTexture(renderer, texturePath);
Заметьте, что перед переменной spriteTexture нет типа, потому что эта переменная уже объявлена глобально в самом верху файла main.cpp:

C++ Скопировано
1
SDL_Texture *spriteTexture = NULL;
Сразу надо отметить, что когда вы создаёте глобально переменную со звёздочной, которая называется указатель, то нужно сразу, в функции SDL_AppQuit написать код для удаления выделенных ресурсов. В данном случае, нужно удалить созданную текстуру, через указатель на неё, с помощью функции SDL_DestroyTexture. Можете посмотреть в самом конце кода, как вызывается SDL_DestroyTexture в теле функции SDL_AppQuit.

2) Концепция спрайтовой анимации. Суть спрайтовой анимации в том, что отображается кадр на прямоугольнике в течении определённого времени. Далее, на прямоугольник выводится следующий кадр и он тоже отображается в течении указанного времени. Когда кадры заканчиваются, то происходит переключение на самый первый кадр. Этот указанный промежуток времени хранится в переменной animationInterval и равен в данном примере 0.1, то есть 100 миллисекунд.

3) Концепция дельта тайм. Дельта тайм - это промежуток времени между кадрами, но кадрами не спрайтовой анимации, а кадрами перерисовки всей сцены. Это время между вызовами функции SDL_AppIterate. Например, если FPS - 60 кадров в секунду (frame per seconds), то дельта тайм будет равен 0.016 секунды или 16 миллисекунд, потому что 1000 / 60 = 16.66666 (6). Концепция дельта тайм центральная для всех видов анимаций, будь то спрайтовая анимация, key frame анимация перемещения/поворота/масштабирования, скелетная анимация, анимация на физическом движке и т.д. В данном примере, дельта тайм используется для отсчёта промежутков времени, когда нужно переключаться на следующий кадр спрайта

4) Реализация расчёта delta time. Для расчёта delta time используется следующий код:

C++ Скопировано
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int lastTime = 0;
 
 /* ... */
 
SDL_AppResult SDL_AppIterate(void *appState)
{
    /* ... */
 
    int currentTime = SDL_GetTicks();
    float deltaTime = (currentTime - lastTime) / 1000.f;
    lastTime = currentTime;
 
    /* ... */
}
Сначала нужно создать глобальную переменную lastTime, чтобы хранить предыдущий момент времени на прошлом кадре отображения. Узнаём текущий момент времени:

C++ Скопировано
1
int currentTime = SDL_GetTicks();
Находим разницу между предыдущим и текущим моментом и делим на 1000, чтобы получить delta time в формате, например, 0.016, а не 16:

C++ Скопировано
1
float deltaTime = (currentTime - lastTime) / 1000.f;
Важный момент, что нужно сохранить в глобальную переменную lastTime текущее время, чтобы для следующего кадра значение в lastTime было моментов времени предыдущего кадра:

C++ Скопировано
1
lastTime = currentTime;
5) Создание таймера для переключения кадров спрайтовой анимации. Дельта тайм найден и может быть использован для расчёта моментов переключения кадров спрайтовой анимации. С помощью дельта тайм можно создать таймер. Создаём константу, которая хранит интервал между кадрами спрайтовой анимации:

C++ Скопировано
1
const float animationInterval = 0.1f;
Создаём переменную, где будет накапливать значения delta timе:

C++ Скопировано
1
float animationTime = 0.f;
Накапливаем следующим образом:

C++ Скопировано
1
animationTime += deltaTime;
Как только накопили больше или равно, чем animationInterval, то сбрасываем animationTime в ноль:

C++ Скопировано
1
2
3
4
5
    if (animationTime > animationInterval)
    {
        frameIndex = (frameIndex + 1) % 6;
        animationTime = 0.f;
    }

6) Индекс следующего кадра спрайтовой анимации. При этом мы рассчитываем новый индекс следующего кадра спрайтовой анимации с помощью строки:

C++ Скопировано
1
frameIndex = (frameIndex + 1) % 6;
Сначала frameIndex равен нулю, а потом он будет равен 1, 2, 3, 4, 5, а потом опять будет равен 0 и так по кругу. Оператор % остаток от целочисленного деления. Зная frameIndex можно выбрать значение из массива фреймов:

C++ Скопировано
1
2
3
4
5
6
7
8
SDL_FRect frames[6] = {
    { 0, 0, 96, 96 }, // Frame 0
    { 96, 0, 96, 96 }, // Frame 1
    { 192, 0, 96, 96 }, // Frame 2
    { 0, 96, 96, 96 }, // Frame 3
    { 96, 96, 96, 96 }, // Frame 4
    { 192, 96, 96, 96 } // Frame 5
};
Первые два числа - это координаты кадра спрайтовой анимации (x, y), а вторые два числа - это размеры кадра спрайтовой анимации (width, height)

7) Рисование кадра спрайтовой анимации. Рисуем кадр спрайтовой анимации:

C++ Скопировано
1
2
3
4
5
6
    // Update animation
    SDL_FRect srcRect = frames[frameIndex];
    SDL_FRect destRect = { 100, 100, 96, 96 };
 
    // Render the current frame
    SDL_RenderTexture(renderer, spriteTexture, &srcRect, &destRect);
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
Вчера, 18:36
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
120
Ответ Создать тему
Новые блоги и статьи
Оптимизация производительности Node.js с помощью кластеризации
run.dev 04.04.2025
Масштабирование приложений для обработки тысяч и миллионов запросов — обыденная задача для многих команд. Node. js, благодаря своей асинхронной событийно-ориентированной архитектуре, стал популярной. . .
Управление зависимостями в Python с Poetry
py-thonny 04.04.2025
Стандартный инструмент для установки пакетов в Python - pip - прекрасно справляется с базовыми сценариями: установил пакет командой pip install и используешь его. Но что произойдёт, когда разные. . .
Мониторинг с Prometheus в PHP
Jason-Webb 04.04.2025
Prometheus выделяется среди других систем мониторинга своим подходом к сбору и хранению метрик. В отличие от New Relic, который использует агентный подход и отправляет данные во внешнее хранилище,. . .
Пакет Context в Golang: Управление потоками и ресурсами
golander 04.04.2025
Работа с горутинами в Go часто напоминает управление непослушными детьми - они разбегаются кто куда, делают что хотят и не всегда завершаются вовремя. К счастью, в Go 1. 7 появился пакет context,. . .
Контейнеризация React приложений с Docker
Reangularity 03.04.2025
Контейнеризация позволяет упаковать приложение со всеми его зависимостями в автономный контейнер, который можно запустить на любой платформе с установленным Docker. Это существенно упрощает процессы. . .
Свой попап в SwiftUI
mobDevWorks 03.04.2025
SwiftUI, как декларативный фреймворк от Apple, предоставляет множество инструментов для создания пользовательских интерфейсов. В нашем распоряжении есть такие API как alerts, popovers, action sheets. . .
Антипаттерны микросервисной архитектуры
ArchitectMsa 03.04.2025
Хорошо спроектированная микросервисная система может выдержать испытание временем, оставаясь гибкой, масштабируемой и устойчивой к большинству проблем. Такая архитектура обладает высоким уровнем. . .
std::mutex в C++: Советы и примеры использования
bytestream 03.04.2025
std::mutex - это механизм взаимного исключения, который гарантирует, что критический участок кода выполняется только одним потоком в каждый момент времени. Это простое, но могущественное средство. . .
Не удержался от оценки концепции двигателя Стирлинга.
Hrethgir 03.04.2025
Сколько не пытался - она выдавала правильные схемы, причём случайно рисовала горячие области в середине, холодные по краям, трубки с краёв в низ и магнит в соединяющей, но при этой выдавала описание. . .
Метод с двумя буферами (или double buffering) или ping-pong buffering
Hrethgir 02.04.2025
Из ответов LM модели. Метод, который предполагает использование двух массивов для хранения промежуточных результатов сложения векторов, обычно применяется в сценариях, где необходимо минимизировать. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru
Выделить код Копировать код Сохранить код Нормальный размер Увеличенный размер