我真的很熟悉使用SDL进行c++编程,并且在运行程序时遇到了一个非常奇怪的问题:当SDL到达SDL_CreateTextureFromSurface时,SDL崩溃,然后我什至无法使用任务管理器关闭窗口!我很困惑,因为代码运行得很好,并且在出现此问题之前我没有做任何更改!甚至尝试使用调试器,但未能找到错误:

c++ - 调用SDL_CreateTextureFromSurface时SDL崩溃-LMLPHP

经过数小时的谷歌搜索,没有发现任何令人满意的结果。这是我的代码:

#include <SDL.h>
#include <SDL_ttf.h>
#include <string>
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <vector>

const int WIN_W = 1000;
const int WIN_H = 550;

const int CEN_W = 511;
const int CEN_H = 511;

const int CEN_X = (WIN_W - CEN_W) / 2;
const int CEN_Y = (WIN_H - CEN_H) / 2;

const int SEP_W = 3;

const int MAX_X = 4;
const int MAX_Y = 4;

const int nbImages = 11;

int numbers[MAX_X][MAX_Y];
int winNumbers[MAX_X][MAX_Y];

TTF_Font* gameNbFont = NULL;
TTF_Font* textFont = NULL;
TTF_Font* pixelFont = NULL;

SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Texture* numbersTextures[MAX_X * MAX_Y - 1];
SDL_Texture* bgImage = NULL;
SDL_Texture* bgImages[nbImages];
SDL_Rect* numbersContsRectsPos[MAX_X][MAX_Y];
SDL_Rect* numbersContsRectsCrops[MAX_X * MAX_Y - 1];
SDL_Rect* restartButtonRect = NULL;

SDL_Texture* timeStringTexture = NULL;
SDL_Texture* timeIntTexture = NULL;
SDL_Texture* movesStringTexture = NULL;
SDL_Texture* movesIntTexture = NULL;
SDL_Texture* restartButtonTexture;

enum texturesSizesEnum{
    TIME_STRING,
    TIME_INT,
    MOVES_STRING,
    MOVES_INT,
    TEXTURES_SIZES_TOTAL
};
std::pair<int, int> texturesSizes[TEXTURES_SIZES_TOTAL];
std::pair<int, int> numbersTexturesSizes[MAX_X * MAX_Y - 1];

int currentTime = -1;
int nbMoves = -1;
int timeFraction = 0;
bool stop;

void updateTime(){
    if (currentTime == 999){
        return;
    }
    currentTime ++;

    std::ostringstream sm;
    sm << currentTime;
    std::string time = std::string(3-sm.str().length(), '0') + sm.str();

    SDL_Surface* timeIntSurface = TTF_RenderText_Solid(pixelFont, time.c_str(), SDL_Color({0XFF, 0XFF, 0XFF}));
    timeIntTexture = SDL_CreateTextureFromSurface(renderer, timeIntSurface);
    texturesSizes[TIME_INT] = std::make_pair(timeIntSurface->w, timeIntSurface->h);
}

void updateMoves(){
    if (nbMoves == 999){
        return;
    }
    nbMoves ++;

    std::ostringstream sm;
    sm << nbMoves;
    std::string moves = std::string(3-sm.str().length(), '0') + sm.str();

    SDL_Surface* movesIntSurface = TTF_RenderText_Solid(pixelFont, moves.c_str(), SDL_Color({0XFF, 0XFF, 0XFF}));
    movesIntTexture = SDL_CreateTextureFromSurface(renderer, movesIntSurface);
    texturesSizes[MOVES_INT] = std::make_pair(movesIntSurface->w, movesIntSurface->h);
}

bool initTextures(){
    printf("started\n");
    bool success=false;
    gameNbFont = TTF_OpenFont("data/fonts/gothic.ttf", 40);
    if (gameNbFont == NULL){
        printf("Couldn't load data/fonts/gothic.ttf font! TTF_Error: %s\n", TTF_GetError());
    }
    else{
        printf("breakpoint1\n");
        for (int i=1; i<MAX_X * MAX_Y; i++){
            printf("breakpoint1.%i.1\n", i);
            std::ostringstream stm;
            printf("breakpoint1.%i.2\n", i);
            stm << i;
            printf("breakpoint1.%i.3\n", i);
            SDL_Surface* number = TTF_RenderText_Solid(gameNbFont, stm.str().c_str(), SDL_Color({0X4E, 0XCD, 0XC4}));
            printf("breakpoint1.%i.4\n", i); //program crashes after printing this :(
            numbersTextures[i-1] = SDL_CreateTextureFromSurface(renderer, number);
            printf("breakpoint1.%i.5\n", i);
            SDL_FreeSurface(number);
            printf("breakpoint1.%i.6\n", i);
            numbersTexturesSizes[i-1] = std::make_pair(number->w, number->h);
        }
        printf("breakpoint2\n");
        textFont = TTF_OpenFont("data/fonts/PlayfairDisplay.ttf", 50);
        if (textFont == NULL){
            printf("Couldn't load data/fonts/PlayfairDisplay.ttf font! TTF_Error: %s", TTF_GetError());
        }
        else{
            printf("breakpoint3");
            SDL_Surface* timeStringSurface = TTF_RenderText_Solid(textFont, "TIME:", SDL_Color({0XFF, 0xFF, 0XFF}));
            timeStringTexture = SDL_CreateTextureFromSurface(renderer, timeStringSurface);
            texturesSizes[TIME_STRING] = std::make_pair(timeStringSurface->w, timeStringSurface->h);

            SDL_Surface* movesStringSurface = TTF_RenderText_Solid(textFont, "MOVES:", SDL_Color({0XFF, 0xFF, 0XFF}));
            movesStringTexture = SDL_CreateTextureFromSurface(renderer, movesStringSurface);
            texturesSizes[MOVES_STRING] = std::make_pair(movesStringSurface->w, movesStringSurface->h);

            pixelFont = TTF_OpenFont("data/fonts/pixels.ttf", 40);
            if (pixelFont == NULL){
                printf("Couldn't load data/fonts/pixels.ttf font! TTF_Error: %s", TTF_GetError());
            }
            else{
                bool loadedAllImages = true;
                for (int i=1; i<=nbImages; i++){
                    std::ostringstream sm;
                    sm << "data/images/examples/image" << i << ".bmp";
                    SDL_Surface* image = SDL_LoadBMP(sm.str().c_str());
                    if (image == NULL){
                        printf("Couldn't load %s! SDL_Error: %s", sm.str().c_str(), SDL_GetError());
                        loadedAllImages = false;
                        break;
                    }
                    else{
                        image = SDL_ConvertSurface(image, image->format, 0);
                        SDL_Surface* scaledImage = SDL_CreateRGBSurface(0, CEN_W, CEN_H, 32, 0, 0, 0, 0);
                        SDL_Rect* stretchRect = new SDL_Rect({0, 0, CEN_W, CEN_H});
                        SDL_BlitScaled(image, NULL, scaledImage, stretchRect);
                        bgImages[i] = SDL_CreateTextureFromSurface(renderer, scaledImage);
                    }
                }
                if (loadedAllImages){
                    bgImage = bgImages[rand() % nbImages + 1];
                    for (int i=0; i<MAX_X * MAX_Y - 1; i++){
                        numbersContsRectsCrops[i] = new SDL_Rect({
                                    numbersContsRectsPos[0][0]->w * (i % MAX_Y),
                                    numbersContsRectsPos[0][0]->h * (i / MAX_Y),
                                    numbersContsRectsPos[0][0]->w,
                                    numbersContsRectsPos[0][0]->h});
                    }
                    SDL_Surface* restartButton = SDL_LoadBMP("data/images/restart.bmp");
                    if (restartButton == NULL){
                        printf("Couldn't load data/images/restart.bmp! SDL_Error: %s)", SDL_GetError());
                    }
                    else{
                        restartButton = SDL_ConvertSurface(restartButton, restartButton->format, 0);
                        restartButtonTexture = SDL_CreateTextureFromSurface(renderer, restartButton);
                        restartButtonRect = new SDL_Rect({(CEN_X + CEN_W + WIN_W - restartButton->w) / 2,
                                                          CEN_Y,
                                                          restartButton->w,
                                                          restartButton->h});
                        updateTime();
                        updateMoves();
                        success = true;
                    }
                }
            }
        }
    }
    return success;
}

void shuffle(std::vector<int> *arr){
    srand(time(0));
    std::vector<int> workspace;
    for (int i=0; i<MAX_X*MAX_Y-1; i++){
        workspace.push_back(i);
    }
    for (int i=0; i<MAX_X*MAX_Y-1; i++){
        int rv = rand() % (MAX_X * MAX_Y - 1 - i);
        arr->push_back(workspace[rv]);
        workspace.erase(workspace.begin() + rv);
    }
}

void initNumbers(){

    std::vector<int> shuffledNumbers;
    shuffle(&shuffledNumbers);
    for (int x=0; x<MAX_X; x++){
        for (int y=0; y<MAX_Y; y++){
            numbers[x][y] = shuffledNumbers[x + y * MAX_X];
        }
    }
    numbers[MAX_X-1][MAX_Y-1] = -1;
    for (int x=0; x<MAX_X; x++){
        for (int y=0; y<MAX_Y; y++){
            winNumbers[x][y] = x + y * MAX_X;
            numbersContsRectsPos[x][y] = new SDL_Rect({CEN_X + SEP_W + ((CEN_W - SEP_W) / MAX_X) * x,
                                               CEN_Y + SEP_W + ((CEN_H - SEP_W) / MAX_Y) * y,
                                               (CEN_W - SEP_W) / MAX_X - SEP_W,
                                               (CEN_H - SEP_W) / MAX_Y - SEP_W});
        }
    }
    winNumbers[MAX_X][MAX_Y] = -1;
}

bool init(){
    bool success = false;
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0){
        printf("SDL couldn't init! SDL_Error: %s\n", SDL_GetError());
    }
    else if (TTF_Init() < 0){
        printf("TTF couldn't init! TTF_Error: %s\n", TTF_GetError());
    }
    else{
        window = SDL_CreateWindow("Sliding Puzzle", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIN_W, WIN_H, SDL_WINDOW_SHOWN);
        if (window==NULL){
            printf("SDL Window couldn't be created!  SDL_Error: %s\n", SDL_GetError());
        }
        else{
            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
            if (renderer == NULL){
                printf("SDL Renderer couldn't be created! SDL_Error: %s\n", SDL_GetError());
            }
            else{
                SDL_Surface* icon = SDL_LoadBMP("data/images/icon.bmp");
                if (icon == NULL){
                    printf("Couldn't load data/images/icon.bmp! SDL_Error: %s\n", SDL_GetError());
                }
                else{
                    SDL_SetWindowIcon(window, icon);
                    initNumbers();
                    success = initTextures();
                }
            }
        }
    }
    return success;
}

void mouseClick(int mouseX, int mouseY){
    int rx1 = restartButtonRect->x;
    int ry1 = restartButtonRect->y;
    int rx2 = restartButtonRect->w + rx1;
    int ry2 = restartButtonRect->h + ry1;
    if (mouseX >= rx1 && mouseX <= rx2 &&
        mouseY >= ry1 && mouseY <= ry2){
        std::vector<int> shuffledNumbers;
        shuffle(&shuffledNumbers);
        for (int x=0; x<MAX_X; x++){
            for (int y=0; y<MAX_Y; y++){
                numbers[x][y] = shuffledNumbers[x + y * MAX_X];
            }
        }
        numbers[MAX_X-1][MAX_Y-1] = -1;
        currentTime = -1;
        updateTime();
        timeFraction = 0;
        nbMoves = 0;
        bgImage = bgImages[rand() % nbImages + 1];
    }
    else{
        std::pair<int, int> collCoor = {-1, -1};
        for (int x=0; x<MAX_X; x++){
            for (int y=0; y<MAX_Y; y++){
                if (numbers[x][y] != -1){
                    int nbx1 = numbersContsRectsPos[x][y]->x;
                    int nby1 = numbersContsRectsPos[x][y]->y;
                    int nbx2 = numbersContsRectsPos[x][y]->w + nbx1;
                    int nby2 = numbersContsRectsPos[x][y]->h + nby1;
                    if (mouseX >= nbx1 && mouseX <= nbx2 &&
                        mouseY >= nby1 && mouseY <= nby2){
                        collCoor.first  = x;
                        collCoor.second = y;
                    }
                }
            }
        }
        if (collCoor.first != -1){
            std::pair<int, int>  swapCoor = {-1, -1};
            for (int x=-1; x<=1; x+=2){
                if (collCoor.first + x >= 0 && collCoor.first + x <MAX_X){
                    if (numbers[collCoor.first +  x][collCoor.second] == -1){
                        swapCoor.first = collCoor.first + x;
                        swapCoor.second = collCoor.second;
                    }
                }
            }
            for (int y=-1; y<=1; y+=2){
                if (collCoor.second + y >= 0 && collCoor.second + y <MAX_Y){
                    if (numbers[collCoor.first][collCoor.second + y] == -1){
                        swapCoor.first = collCoor.first;
                        swapCoor.second = collCoor.second + y;
                    }
                }
            }
            if (swapCoor.first != -1){
                std::swap(numbers[collCoor.first][collCoor.second], numbers[swapCoor.first][swapCoor.second]);
                updateMoves();
            }
        }
    }
}


int main(int argc, char **argv){
    if (init()){
        bool quit = false;
        stop = false;
        SDL_Event e;

        int mouseX, mouseY;
        while (!quit){
            while (SDL_PollEvent(&e) != 0){
                switch(e.type){
                    case SDL_QUIT:
                        quit = true;
                        break;
                    case SDL_MOUSEBUTTONDOWN:
                        SDL_GetMouseState(&mouseX, &mouseY);
                        mouseClick(mouseX, mouseY);
                        break;
                }
            }
            SDL_SetRenderDrawColor(renderer, 0XFF, 0X6B, 0X6B, SDL_ALPHA_OPAQUE);
            SDL_RenderClear(renderer);

            SDL_Rect* fillRect = new SDL_Rect({CEN_X, CEN_Y, CEN_W, CEN_H});
            SDL_SetRenderDrawColor(renderer, 0XFF, 0XFF, 0XFF, SDL_ALPHA_OPAQUE);
            SDL_RenderFillRect(renderer, fillRect);

            SDL_SetRenderDrawColor(renderer, 0XFF, 0XFF, 0XFF, SDL_ALPHA_OPAQUE);
            for (int x=0; x<MAX_X; x++){
                for (int y=0; y<MAX_Y; y++){
                    if (numbers[x][y] != -1){
                        //SDL_RenderFillRect(renderer, numbersContsRectsPos[x][y]);
                        SDL_RenderCopy(renderer, bgImage,
                                       numbersContsRectsCrops[numbers[x][y]],
                                       numbersContsRectsPos[x][y]);
                    }
                }
            }
            SDL_Rect* numberRect;
            for (int x=0; x<MAX_X; x++){
                for (int y=0; y<MAX_Y; y++){
                    if (numbers[x][y] != -1){
                        numberRect = new SDL_Rect({numbersContsRectsPos[x][y]->x + 5,
                                      numbersContsRectsPos[x][y]->y + 5,
                                      numbersTexturesSizes[numbers[x][y]].first,
                                      numbersTexturesSizes[numbers[x][y]].second});
                        SDL_RenderCopy(renderer, numbersTextures[numbers[x][y]], NULL, numberRect);
                    }
                }
            }
            SDL_Rect* posRect;
            posRect = new SDL_Rect({10, 10, texturesSizes[TIME_STRING].first, texturesSizes[TIME_STRING].second});
            SDL_RenderCopy(renderer, timeStringTexture, NULL, posRect);

            posRect = new SDL_Rect({10, posRect->y + texturesSizes[TIME_STRING].second + 5,
                                    texturesSizes[TIME_INT].first, texturesSizes[TIME_INT].second});
            SDL_RenderCopy(renderer, timeIntTexture, NULL, posRect);

            posRect = new SDL_Rect({10, posRect->y + texturesSizes[TIME_INT].second + 15,
                                   texturesSizes[MOVES_STRING].first, texturesSizes[MOVES_STRING].second});
            SDL_RenderCopy(renderer, movesStringTexture, NULL, posRect);

            posRect = new SDL_Rect({10, posRect->y + texturesSizes[MOVES_STRING].second + 5,
                                    texturesSizes[MOVES_INT].first, texturesSizes[MOVES_INT].second});
            SDL_RenderCopy(renderer, movesIntTexture, NULL, posRect);

            SDL_RenderCopy(renderer, restartButtonTexture, NULL, restartButtonRect);

            SDL_RenderPresent(renderer);
            SDL_ShowWindow(window);
            SDL_Delay(10);
            if (!stop){
                timeFraction += 10;
                if (timeFraction == 1000){
                    updateTime();
                    timeFraction = 0;
                }
                if (winNumbers == numbers){
                    stop = true;
                }
            }
        }
    }
    SDL_Quit();
    return 0;
}

我正在将mingw编译器与code::blocks一起使用(对不起我的英语不好)

c&#43;&#43; - 调用SDL_CreateTextureFromSurface时SDL崩溃-LMLPHP

最佳答案

刚刚修好了。错误非常简单:我尝试访问的winNumbers的长度为MAX_X的长度,索引为MAX_X(应该为MAX_X - 1)。但是,我不知道为什么调试器没有检测到错误。

10-07 18:15