Загрузка данных


#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_image.h>
#include <cmath>
#include <vector>
#include <algorithm>
#include <cstring>

// Подключение специфичного заголовка Emscripten для веб-цикла
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

const int WIDTH = 640;
const int HEIGHT = 600;
const int FPS = 30;
const float FOV = M_PI / 2.5f;
const int CASTED_RAYS = 320;
const int SCALE = WIDTH / CASTED_RAYS;
const float WALL_HEIGHT_SCALE = 10.0f;
Uint32 fireStartTime = 0;
bool gunFiring = false;

SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_Texture* screen_texture = nullptr;
Uint32* screen_buffer = nullptr;

Uint32* baseTexture = nullptr;
int baseTexW = 0, baseTexH = 0;

SDL_Texture* gunTex1 = nullptr;
SDL_Texture* gunTex2 = nullptr;

struct Wall {
    float x1, y1, x2, y2;
    Uint32* tex;
    int texW, texH;
    Wall(float _x1, float _y1, float _x2, float _y2,
         Uint32* _tex = nullptr, int _w = 0, int _h = 0)
        : x1(_x1), y1(_y1), x2(_x2), y2(_y2),
          tex(_tex), texW(_w), texH(_h) {}
};

struct Enemy {
    float x, y;
    float speed = 1.0f;
    int hp = 3;
    Uint32* aliveTex; int aW, aH;
    Uint32* deadTex;  int dW, dH;
    Enemy(float _x, float _y,
          Uint32* a, int aw, int ah,
          Uint32* d, int dw, int dh)
        : x(_x), y(_y), aliveTex(a), aW(aw), aH(ah),
          deadTex(d), dW(dw), dH(dh) {}
};

struct Player {
    float x = 150.0f, y = 150.0f;
    float angle = 0.0f;
    float vx = 0.0f, vy = 0.0f;
    const float accel = 0.5f, decel = 0.15f, maxSpeed = 4.0f; 
    float rot_speed = 0.07f; 
};

Player player;
int currentLevel = 1;

std::vector<Wall> staticWalls;
std::vector<Enemy> enemies;

Uint32* loadPixels(SDL_Surface* surf, int& w, int& h) {
    if (!surf) {
        // Fallback генерация шахматной текстуры, если файл не найден
        w = 64; h = 64;
        Uint32* pixels = new Uint32[w * h];
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                pixels[y * w + x] = ((x / 8 + y / 8) % 2 == 0) ? 0xFF00FF00 : 0xFF000000;
            }
        }
        return pixels;
    }
    SDL_Surface* s = SDL_ConvertSurface(surf, SDL_PIXELFORMAT_ARGB8888);
    SDL_DestroySurface(surf);
    w = s->w; h = s->h;
    Uint32* pixels = new Uint32[w * h];
    memcpy(pixels, s->pixels, w * h * sizeof(Uint32));
    SDL_DestroySurface(s);
    return pixels;
}

Uint32* fimozTexAlive = nullptr, *fimozTexDead = nullptr;
int fimozW = 0, fimozH = 0, fimozDW = 0, fimozDH = 0;

void loadLevel1() {
    staticWalls.clear(); enemies.clear();
    staticWalls = {
        {100,100,300,100, baseTexture, baseTexW, baseTexH},
        {300,100,300,300, baseTexture, baseTexW, baseTexH},
        {300,300,100,300, baseTexture, baseTexW, baseTexH},
        {100,300,100,100, baseTexture, baseTexW, baseTexH}
    };
    enemies.emplace_back(200,200, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel2() {
    staticWalls.clear(); enemies.clear();
    staticWalls = {
        {50,50, 600,50, baseTexture, baseTexW, baseTexH},
        {600,50, 600,400, baseTexture, baseTexW, baseTexH},
        {600,400, 50,400, baseTexture, baseTexW, baseTexH},
        {50,400, 50,50, baseTexture, baseTexW, baseTexH}
    };
    enemies.emplace_back(300,200, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel3() {
    staticWalls.clear(); enemies.clear();
    for (int i = 0; i < 5; ++i)
        staticWalls.emplace_back(100+i*100, 100, 100+i*100, 500, baseTexture, baseTexW, baseTexH);
    enemies.emplace_back(550, 300, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(400, 150, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel4() {
    staticWalls.clear(); enemies.clear();
    for (int i = 0; i < 5; ++i)
        staticWalls.emplace_back(100+i*100, 100, 100+i*100, 500, baseTexture, baseTexW, baseTexH);
    enemies.emplace_back(550, 300, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(400, 150, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(300,200, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(500,200, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel5() {
    staticWalls.clear(); enemies.clear();
    for (int i = 0; i < 4; ++i) {
        if (i % 2 == 0)
            staticWalls.emplace_back(50, 100 + i * 100, 500, 100 + i * 100, baseTexture, baseTexW, baseTexH);
        else
            staticWalls.emplace_back(150, 100 + i * 100, 600, 100 + i * 100, baseTexture, baseTexW, baseTexH);
    }
    enemies.emplace_back(100, 150, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(550, 250, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(100, 350, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel6() {
    staticWalls.clear(); enemies.clear();
    staticWalls.emplace_back(50, 50, 250, 50, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(250, 50, 250, 250, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(250, 250, 50, 250, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(50, 250, 50, 50, baseTexture, baseTexW, baseTexH);

    staticWalls.emplace_back(350, 300, 550, 300, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(550, 300, 550, 500, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(550, 500, 350, 500, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(350, 500, 350, 300, baseTexture, baseTexW, baseTexH);

    enemies.emplace_back(150, 150, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(450, 400, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(300, 100, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel7() {
    staticWalls.clear(); enemies.clear();
    staticWalls.emplace_back(320, 100, 320, 250, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(320, 350, 320, 500, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(100, 300, 250, 300, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(390, 300, 540, 300, baseTexture, baseTexW, baseTexH);

    enemies.emplace_back(150, 150, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(480, 150, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(150, 450, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(480, 450, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel8() {
    staticWalls.clear(); enemies.clear();
    for (int i = 0; i < 6; ++i) {
        float x_offset = i * 60;
        staticWalls.emplace_back(100 + x_offset, 100, 100 + x_offset, 200, baseTexture, baseTexW, baseTexH);
        staticWalls.emplace_back(100 + x_offset, 400, 100 + x_offset, 500, baseTexture, baseTexW, baseTexH);
    }
    staticWalls.emplace_back(460, 200, 460, 400, baseTexture, baseTexW, baseTexH);

    enemies.emplace_back(420, 300, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(420, 250, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(420, 350, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel9() {
    staticWalls.clear(); enemies.clear();
    for (int x = 150; x <= 500; x += 150) {
        for (int y = 150; y <= 450; y += 150) {
            staticWalls.emplace_back(x - 10, y, x + 10, y, baseTexture, baseTexW, baseTexH);
            staticWalls.emplace_back(x, y - 10, x, y + 10, baseTexture, baseTexW, baseTexH);
        }
    }
    enemies.emplace_back(200, 200, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(450, 200, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(200, 400, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(450, 400, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
    enemies.emplace_back(320, 300, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel10() {
    staticWalls.clear(); enemies.clear();
    staticWalls.emplace_back(20, 20, 620, 20, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(620, 20, 620, 580, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(620, 580, 20, 580, baseTexture, baseTexW, baseTexH);
    staticWalls.emplace_back(20, 580, 20, 20, baseTexture, baseTexW, baseTexH);

    enemies.emplace_back(300, 100, fimozTexAlive, fimozW, fimozH, fimozTexDead, fimozDW, fimozDH);
}

void loadLevel(int i) {
    if (i == 1) loadLevel1();
    else if (i == 2) loadLevel2();
    else if (i == 3) loadLevel3();
    else if (i == 4) loadLevel4();
    else if (i == 5) loadLevel5();
    else if (i == 6) loadLevel6();
    else if (i == 7) loadLevel7();
    else if (i == 8) loadLevel8();
    else if (i == 9) loadLevel9();
    else loadLevel10();
}

bool initSDL() {
    if (!SDL_Init(SDL_INIT_VIDEO)) return false;
    window = SDL_CreateWindow("Webasm Raycaster", WIDTH, HEIGHT, 0);
    renderer = SDL_CreateRenderer(window, nullptr);
    screen_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT);
    screen_buffer = new Uint32[WIDTH * HEIGHT];

    baseTexture = loadPixels(IMG_Load("bricks.png"), baseTexW, baseTexH);
    fimozTexAlive = loadPixels(IMG_Load("fimoz.png"), fimozW, fimozH);
    fimozTexDead = loadPixels(IMG_Load("fimozD.png"), fimozDW, fimozDH);

    auto loadGun = [&](const char* file) {
        SDL_Surface* s = IMG_Load(file);
        if(!s) return (SDL_Texture*)nullptr;
        SDL_Surface* c = SDL_ConvertSurface(s, SDL_PIXELFORMAT_ARGB8888);
        SDL_DestroySurface(s);
        SDL_Texture* t = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, c->w, c->h);
        SDL_UpdateTexture(t, NULL, c->pixels, c->w * sizeof(Uint32));
        SDL_DestroySurface(c);
        return t;
    };
    gunTex1 = loadGun("gun1.png");
    gunTex2 = loadGun("gun2.png");

    return true;
}

bool shootEnemy(Player& p, const std::vector<Wall>& walls) {
    float ray_angle = p.angle;
    float dir_x = cosf(ray_angle), dir_y = sinf(ray_angle);
    float wallDist = INFINITY;
    for (auto& w : walls) {
        float dx = w.x2 - w.x1, dy = w.y2 - w.y1;
        float det = dir_x * dy - dir_y * dx;
        if (fabs(det) < 1e-6f) continue;
        float t = ((p.x - w.x1) * dy - (p.y - w.y1) * dx) / det;
        float u = ((w.x1 - p.x) * dir_y - (w.y1 - p.y) * dir_x) / det;
        if (t > 0 && u >= 0 && u <= 1) {
            float ix = p.x + t * dir_x;
            float iy = p.y + t * dir_y;
            wallDist = std::min(wallDist, hypotf(ix - p.x, iy - p.y));
        }
    }
    for (auto& enemy : enemies) {
        if (enemy.hp <= 0) continue;
        float dx = enemy.x - p.x;
        float dy = enemy.y - p.y;
        float nx = -dy, ny = dx;
        float len = hypotf(nx, ny);
        if (len < 1e-3f) len = 1.0f;
        nx /= len; ny /= len;
        float half = 20.0f;
        Wall ew(enemy.x - nx * half, enemy.y - ny * half, enemy.x + nx * half, enemy.y + ny * half);
        float det = dir_x * (ew.y2 - ew.y1) - dir_y * (ew.x2 - ew.x1);
        if (fabs(det) < 1e-6f) continue;
        float t = ((p.x - ew.x1) * (ew.y2 - ew.y1) - (p.y - ew.y1) * (ew.x2 - ew.x1)) / det;
        float u = ((ew.x1 - p.x) * dir_y - (ew.y1 - p.y) * dir_x) / det;
        if (t > 0 && u >= 0 && u <= 1) {
            float ex = p.x + t * dir_x;
            float ey = p.y + t * dir_y;
            float dist = hypotf(ex - p.x, ey - p.y);
            if (dist < wallDist) {
                enemy.hp--;
                return true;
            }
        }
    }
    return false;
}

void drawCrosshair(Uint32 color = 0xFF0000) {
    int cx = WIDTH / 2, cy = HEIGHT / 2;
    for (int dy = -5; dy <= 5; ++dy)
        if (cy + dy >= 0 && cy + dy < HEIGHT)
            screen_buffer[(cy + dy) * WIDTH + cx] = color;
    for (int dx = -5; dx <= 5; ++dx)
        if (cx + dx >= 0 && cx + dx < WIDTH)
            screen_buffer[cy * WIDTH + cx + dx] = color;
}

void renderFrame(Player& p) {
    float start = p.angle - FOV / 2;
    float step = FOV / CASTED_RAYS;
    
    // ОТРИСОВКА ПОЛА И ПОТОЛКА (Чтобы сцена не проваливалась в темноту)
    std::fill_n(screen_buffer, WIDTH * (HEIGHT / 2), 0xFF444444);        // Потолок
    std::fill_n(screen_buffer + WIDTH * (HEIGHT / 2), WIDTH * (HEIGHT / 2), 0xFF222222); // Пол

    std::vector<float> depthBuffer(CASTED_RAYS, INFINITY);
    std::vector<Wall> all = staticWalls;

    for (int r = 0; r < CASTED_RAYS; ++r) {
        float ang = start + r * step;
        float dx = cosf(ang), dy = sinf(ang);
        float minD = INFINITY, bestU = 0;
        Uint32* curTex = nullptr; int tW = 0, tH = 0;

        for (auto& w : all) {
            float ex = w.x2 - w.x1, ey = w.y2 - w.y1;
            float det = dx * ey - dy * ex;
            if (fabs(det) < 1e-6f) continue;
            float t = ((p.x - w.x1) * ey - (p.y - w.y1) * ex) / det;
            float u = ((w.x1 - p.x) * dy - (w.y1 - p.y) * dx) / det;
            if (t > 0 && u >= 0 && u <= 1 && t < minD) {
                minD = t; bestU = u;
                curTex = w.tex; tW = w.texW; tH = w.texH;
            }
        }

        if (minD < INFINITY && curTex) {
            float dd = minD * cosf(p.angle - ang);
            depthBuffer[r] = dd;
            
            int h = int((HEIGHT * 2 * WALL_HEIGHT_SCALE) / (dd + 0.0001f));
            int y0 = std::max(-h / 2 + HEIGHT / 2, 0);
            int y1 = std::min(h / 2 + HEIGHT / 2, HEIGHT - 1);
            int tx = std::clamp(int(bestU * tW), 0, tW - 1);
            for (int y = y0; y < y1; ++y) {
                int ty = (y - y0) * tH / h;
                Uint32 col = curTex[ty * tW + tx];
                if ((col >> 24) < 128) continue; // Пропуск прозрачных пикселей

                for (int dxp = 0; dxp < SCALE; ++dxp) {
                    int sx = r * SCALE + dxp;
                    if (sx < WIDTH) screen_buffer[y * WIDTH + sx] = col;
                }
            }
        }
    }
    
    all.clear();
    for (auto& e : enemies) {
        float dx = e.x - p.x, dy = e.y - p.y;
        float nx = -dy, ny = dx;
        float len = hypotf(nx, ny);
        if(len < 1e-3f) len = 1.0f;
        nx /= len; ny /= len;
        float half = 20;
        Uint32* tex = (e.hp > 0 ? e.aliveTex : e.deadTex);
        int w = (e.hp > 0 ? e.aW : e.dW);
        int h = (e.hp > 0 ? e.aH : e.dH);
        all.emplace_back(e.x - nx * half, e.y - ny * half, e.x + nx * half, e.y + ny * half, tex, w, h);
    }
    
    for (int r = 0; r < CASTED_RAYS; ++r) {
        float ang = start + r * step;
        float dx = cosf(ang), dy = sinf(ang);
        float minD = INFINITY, bestU = 0;
        Uint32* curTex = nullptr; int tW = 0, tH = 0;

        for (auto& w : all) {
            float ex = w.x2 - w.x1, ey = w.y2 - w.y1;
            float det = dx * ey - dy * ex;
            if (fabs(det) < 1e-6f) continue;
            float t = ((p.x - w.x1) * ey - (p.y - w.y1) * ex) / det;
            float u = ((w.x1 - p.x) * dy - (w.y1 - p.y) * dx) / det;
            if (t > 0 && u >= 0 && u <= 1 && t < minD) {
                minD = t; bestU = u;
                curTex = w.tex; tW = w.texW; tH = w.texH;
            }
        }

        if (minD < INFINITY && curTex) {
            float dd = minD * cosf(p.angle - ang);
            if(dd > depthBuffer[r]) continue; // Проверка перекрытия стенами
            
            int h = int((HEIGHT * 2 * WALL_HEIGHT_SCALE) / (dd + 0.0001f));
            int y0 = std::max(-h / 2 + HEIGHT / 2, 0);
            int y1 = std::min(h / 2 + HEIGHT / 2, HEIGHT - 1);
            int tx = std::clamp(int(bestU * tW), 0, tW - 1);
            for (int y = y0; y < y1; ++y) {
                int ty = (y - y0) * tH / h;
                Uint32 col = curTex[ty * tW + tx];
                if ((col >> 24) < 128) continue;
                for (int dxp = 0; dxp < SCALE; ++dxp) {
                    int sx = r * SCALE + dxp;
                    if (sx < WIDTH) screen_buffer[y * WIDTH + sx] = col;
                }
            }
        }
    }

    drawCrosshair(0xFF2D9ED8); 
}

// Главная функция одного игрового кадра (Main Loop Tick) для Emscripten
void main_loop_tick() {
    SDL_Event e;
    Uint32 frame_start = SDL_GetTicks();
    
    while (SDL_PollEvent(&e)) {
        if (e.type == SDL_EVENT_QUIT) {
#ifdef __EMSCRIPTEN__
            emscripten_cancel_main_loop();
#endif
            return;
        }
        if (e.type == SDL_EVENT_KEY_DOWN && e.key.scancode == SDL_SCANCODE_SPACE) {
            gunFiring = true;
            fireStartTime = frame_start;
            shootEnemy(player, staticWalls);
        }
    }

    const bool* keys = SDL_GetKeyboardState(NULL);
    bool isAccel = false;

    // УПРАВЛЕНИЕ: Стрелка ВВЕРХ — вперед, ВНИЗ — назад 
    if (keys[SDL_SCANCODE_DOWN]) {
        player.vx += cosf(player.angle) * player.accel;
        player.vy += sinf(player.angle) * player.accel;
        isAccel = true;
    }
    if (keys[SDL_SCANCODE_UP]) {
        player.vx -= cosf(player.angle) * player.accel;
        player.vy -= sinf(player.angle) * player.accel;
        isAccel = true;
    }

    float vlen = hypotf(player.vx, player.vy);
    if (vlen > player.maxSpeed) {
        player.vx *= player.maxSpeed / vlen;
        player.vy *= player.maxSpeed / vlen;
    }
    
    if(!isAccel) {
        player.vx *= (1.0f - player.decel);
        player.vy *= (1.0f - player.decel);
        if (hypotf(player.vx, player.vy) < 0.05f) { player.vx = 0; player.vy = 0; }
    }
    
    player.x += player.vx;
    player.y += player.vy;

    if (keys[SDL_SCANCODE_LEFT]) player.angle -= player.rot_speed;
    if (keys[SDL_SCANCODE_RIGHT]) player.angle += player.rot_speed;

    renderFrame(player);
    SDL_UpdateTexture(screen_texture, NULL, screen_buffer, WIDTH * sizeof(Uint32));
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    SDL_RenderTexture(renderer, screen_texture, NULL, NULL);
    
    // Отрисовка интерфейса оружия поверх кадра
    int gw = 200, gh = 150;
    SDL_FRect dst = { (float)WIDTH / 2.0f - (float)gw / 2.0f, (float)HEIGHT - gh, (float)gw, (float)gh };
    if (gunFiring && SDL_GetTicks() - fireStartTime < 200) {
        if(gunTex2) SDL_RenderTexture(renderer, gunTex2, NULL, &dst);
    } else {
        gunFiring = false;
        if(gunTex1) SDL_RenderTexture(renderer, gunTex1, NULL, &dst);
    }

    SDL_RenderPresent(renderer);
    
    // Проверка триггера смены уровней
    bool allDead = true;
    for(auto& e : enemies) {
        if(e.hp > 0) {
            allDead = false;
            break;
        }
    }
    
    if(allDead && !enemies.empty()) {
        currentLevel++;
        if(currentLevel > 10) currentLevel = 1;
        loadLevel(currentLevel);
        player.x = 150.0f; player.y = 150.0f; player.angle = 0.0f; // Сброс позиции игрока
    }
}

int main(int argc, char* argv[]) {
    if (!initSDL()) return 1;
    
    loadLevel(currentLevel);

#ifdef __EMSCRIPTEN__
    // Передаем управление циклом браузеру
    emscripten_set_main_loop(main_loop_tick, 0, 1);
#else
    // Нативный цикл для десктопа (для отладки)
    while (true) {
        Uint32 start = SDL_GetTicks();
        main_loop_tick();
        Uint32 dt = SDL_GetTicks() - start;
        if (dt < 1000 / FPS) SDL_Delay(1000 / FPS - dt);
    }
#endif

    // Очистка ресурсов при закрытии приложения
    delete[] baseTexture;
    delete[] screen_buffer;
for (auto& e : enemies) {delete[] e.aliveTex;delete[] e.deadTex;}if(screen_texture) SDL_DestroyTexture(screen_texture);if(renderer) SDL_DestroyRenderer(renderer);if(window) SDL_DestroyWindow(window);SDL_Quit();return 0;}