我真的很熟悉使用SDL进行c++编程,并且在运行程序时遇到了一个非常奇怪的问题:当SDL到达SDL_CreateTextureFromSurface时,SDL崩溃,然后我什至无法使用任务管理器关闭窗口!我很困惑,因为代码运行得很好,并且在出现此问题之前我没有做任何更改!甚至尝试使用调试器,但未能找到错误:
经过数小时的谷歌搜索,没有发现任何令人满意的结果。这是我的代码:
#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一起使用(对不起我的英语不好)
最佳答案
刚刚修好了。错误非常简单:我尝试访问的winNumbers
的长度为MAX_X
的长度,索引为MAX_X
(应该为MAX_X - 1
)。但是,我不知道为什么调试器没有检测到错误。