我使用sdl2在c ++中制作一个简单的类似太空入侵者的游戏。事情进展得很好。游戏工作正常,直到我注意到SDL在大约1分钟和22秒之后无法加载我的任何PNG。它无论出于何种原因都会停止工作。我试了几个小时才找到类似的问题,但没有任何运气。 (一般来说,我对游戏开发和图形编程都很陌生。)
main.cpp:
#include "SpaceInv.h"
int main(int argc, char* args[]) {
SpaceInv si;
si.StartGame();
return 0;
}
SpaceInv.h:
#pragma once
#ifndef SPACEINV
#define SPACEINV
#include <SDL_mixer.h>
#include "Ship.h"
#include "SpaceContainer.h"
#include "ScoreBoard.h"
class SpaceInv {
public:
SpaceInv();
~SpaceInv();
void StartGame();
void Close();
bool Initialize();
SDL_Texture* LoadTexture(std::string file);
void generateEnemy();
void generateAsteroid();
bool checkCollitions(SDL_Rect& a, SDL_Rect& b);
int randNum(int min, int max);
private:
const int SCREEN_WIDTH = 720;
const int SCREEN_HEIGHT = 480;
SDL_Window* window = NULL;
SDL_Surface* screen = NULL;
SDL_Renderer* renderer = NULL;
SDL_Texture* background = NULL;
Ship ship;
ScoreBoard score;
int frameWidth, frameHeight;
int textureWidth, textureHeight;
SpaceContainer lazers;
SpaceContainer explosions;
SpaceContainer enemyLazers;
SpaceContainer asteroids;
SpaceContainer enemyShips;
};
#endif
SpaceInv.cpp:
#include "SpaceInv.h"
#include "Asteroid.h"
#include <SDL_ttf.h>
#include <random>
SpaceInv::SpaceInv(){
}
SpaceInv::~SpaceInv(){}
void SpaceInv::StartGame() {
if (!Initialize()) {
printf("Could not initialize!\n");
return;
}
//load background music
Mix_Chunk *bgm = Mix_LoadWAV("bgm.wav");
Mix_Chunk *lazerBeam = Mix_LoadWAV("Lazerbeam.wav");
if (!bgm) {
std::cout << "no music found..." << std::endl;
}
Mix_PlayChannel(0, bgm, 0);
if (bgm==NULL) {
std::cout << "no music found..." << std::endl;
}
background = LoadTexture("img.png");
ship.setSpriteName("ship.png");
ship.setTexture(renderer);
score.setTexture(renderer, "Score: 0");
int points = 0;
const int FPS = 60;
int frameTime = 0;
bool exit = false;
while (!exit) {
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT || e.key.keysym.sym == SDLK_ESCAPE) {
exit = true;
}
if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.sym==SDLK_LEFT){
ship.moveX(-1); //std::cout << "left";
}
if (e.key.keysym.sym == SDLK_RIGHT){
ship.moveX(1); //std::cout << "Right";
}
if (e.key.keysym.sym == SDLK_UP){
ship.moveY(-1); //std::cout << "UP";
}
if (e.key.keysym.sym == SDLK_DOWN){
ship.moveY(1); //std::cout << "DOWN";
}
if (e.key.keysym.sym == SDLK_SPACE && e.key.repeat==0) {
//skapa laser om input = SPACE
SpaceObject lazer("lazer.png", ship.getPos(), 5, 10);
lazer.setSpriteName("lazer.png");
int x = ship.getPos().x;
int y = ship.getPos().y - 20;
lazer.setPos(x , y);
lazer.setTexture(renderer);
lazers.pushBack(lazer);
Mix_PlayChannel(1, lazerBeam, 0);
//std::cout << "SPACE";
}
}
}
frameTime++;
if (FPS / frameTime == 4) {
frameTime = 0;
//animate ship
ship.animate();
//animate lazers
for (size_t i = 0; i < lazers.size(); i++) {
lazers.getObject(i).animate();
}
//animate asteroids
for (size_t i = 0; i < asteroids.size(); i++) {
asteroids.getObject(i).animate();
}
//animate enemy lazers
for (size_t i = 0; i < enemyLazers.size(); i++) {
enemyLazers.getObject(i).animate();
}
//animate enemy ships
for (size_t i = 0; i < enemyShips.size(); i++) {
enemyShips.getObject(i).animate();
}
//animate explosions
for (size_t i = 0; i < explosions.size(); i++){
explosions.getObject(i).animate();
}
}
//random generate asteroids
if (randNum(1, 100) >= 99) {
generateAsteroid();
}
//random generate enemy ships
if (randNum(-200, 200) >= 199) {
generateEnemy();
}
//make enemy ships fire at random
for (size_t i = 0; i < enemyShips.size(); i++){
if (randNum(0, 200) >= 199) {
SpaceObject enemyLazer("lazer.png", enemyShips.getObject(i).getPos(), 5, -10);
enemyLazer.setSpriteName("lazer.png");
enemyLazer.setTexture(renderer);
enemyLazers.pushBack(enemyLazer);
Mix_PlayChannel(i+2, lazerBeam, 0);
}
}
//clear the renderer
SDL_RenderClear(renderer);
//render ship and background image
SDL_RenderCopy(renderer, background, NULL, NULL);
SDL_RenderCopy(renderer, ship.getTexture(), &ship.getRect(), &ship.getPos());
//rendrer scoreboard
SDL_RenderCopy(renderer, score.getTexture(), NULL, &score.getPos());
//uppdate and render lazers
for (size_t i = 0; i < lazers.size(); i++) {
lazers.getObject(i).moveY();
SDL_RenderCopy(renderer, lazers.getObject(i).getTexture(), &lazers.getObject(i).getRect(),
&lazers.getObject(i).getPos());
}
//uppdate and render asteroids
for (size_t i = 0; i < asteroids.size(); i++) {
asteroids.getObject(i).moveY();
SDL_RenderCopy(renderer, asteroids.getObject(i).getTexture(), &asteroids.getObject(i).getRect(),
&asteroids.getObject(i).getPos());
}
//uppdate and render enemy lazers
for (size_t i = 0; i < enemyLazers.size(); i++) {
enemyLazers.getObject(i).moveY();
SDL_RenderCopy(renderer, enemyLazers.getObject(i).getTexture(), &enemyLazers.getObject(i).getRect(),
&enemyLazers.getObject(i).getPos());
}
//uppdate and render enemy ships
for (size_t i = 0; i < enemyShips.size(); i++) {
enemyShips.getObject(i).moveY();
SDL_RenderCopy(renderer, enemyShips.getObject(i).getTexture(), &enemyShips.getObject(i).getRect(),
&enemyShips.getObject(i).getPos());
}
//render explosions
for (size_t i = 0; i < explosions.size(); i++) {
SDL_RenderCopy(renderer, explosions.getObject(i).getTexture(), &explosions.getObject(i).getRect(),
&explosions.getObject(i).getPos());
}
//look for collisions between lazers and enemy ships
for (size_t i = 0; i < lazers.size(); i++) {
for (size_t j = 0; j < enemyShips.size(); j++) {
if (checkCollitions(lazers.getObject(i).getPos(), enemyShips.getObject(j).getPos())) {
//std::cout << "collision!!" << std::endl;
lazers.getObject(i).setTimeToLive(0);
enemyShips.getObject(j).setTimeToLive(0);
SpaceObject explosion("explosion.png", enemyShips.getObject(j).getPos(), 1, 0);
explosion.setSpriteName("explosion.png");
//lazer.setPos(ship.getPos());
explosion.setTexture(renderer);
explosions.pushBack(explosion);
points += 10;
}
}
}
////look for collisions between lazers and asteroids
for (size_t i = 0; i < lazers.size(); i++) {
for (size_t j = 0; j < asteroids.size(); j++) {
if (checkCollitions(lazers.getObject(i).getPos(), asteroids.getObject(j).getPos())) {
//std::cout << "collision!!" << std::endl;
lazers.getObject(i).setTimeToLive(0);
asteroids.getObject(j).setTimeToLive(0);
SpaceObject explosion("explosion.png", asteroids.getObject(j).getPos(), 1, 0);
explosion.setSpriteName("explosion.png");
//lazer.setPos(ship.getPos());
explosion.setTexture(renderer);
explosions.pushBack(explosion);
points += 2;
}
}
}
////look for collisions between ship and asteroids
for (size_t i = 0; i < asteroids.size(); i++) {
if (checkCollitions(ship.getPos(), asteroids.getObject(i).getPos())) {
//exit = true;
}
}
////look for collisions between ship and enemy lazers
for (size_t i = 0; i < enemyLazers.size(); i++) {
if (checkCollitions(ship.getPos(), enemyLazers.getObject(i).getPos())) {
//exit = true;
}
}
//check the lifetime of every object on the screen.
enemyShips.checkLifetime();
enemyLazers.checkLifetime();
asteroids.checkLifetime();
lazers.checkLifetime();
explosions.checkLifetime();
//update score
score.setTexture(renderer, "Score: " + std::to_string(points));
SDL_RenderPresent(renderer);
}
Close();
return;
}
bool SpaceInv::Initialize() {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
printf("SDL could not be initialized! SDL Error %s\n", SDL_GetError);
return false;
}
window = SDL_CreateWindow("Super Space Wars Extreme",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL) {
printf("Window could not be created! SDL Error %s\n", SDL_GetError);
return false;
}
//screen = SDL_GetWindowSurface(window);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == NULL) {
printf("Not able to create renderer! SDL Error %s\n", SDL_GetError);
return false;
}
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
int imgFlags = IMG_INIT_PNG;
if (!IMG_Init(imgFlags & imgFlags)) {
printf("SDL_image could not be initialized! SDL_image Error %s\n", IMG_GetError);
return false;
}
if (TTF_Init() == -1)
{
std::cout << "Init TTF failt : " << SDL_GetError() << std::endl;
return false;
}
/*if (Mix_Init() == -1) {
std::cout << "Audio Error : " << Mix_GetError() << std::endl;
}*/
if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0){
std::cout << "Audio Error : " << Mix_GetError() << std::endl;
}
return true;
}
SDL_Texture* SpaceInv::LoadTexture(std::string file) {
SDL_Texture* newTexture = NULL;
SDL_Surface* loadedSurface = IMG_Load(file.c_str());
if (loadedSurface == NULL) {
printf("Unable to load image! SDL_image Error %s\n", file.c_str(), IMG_GetError);
}
else {
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if (newTexture == NULL) {
printf("Unable to create the texture from %s! SDL_image Error %s\n", SDL_GetError);
SDL_FreeSurface(loadedSurface);
}
}
return newTexture;
}
void SpaceInv::generateAsteroid() {
SpaceObject asteroid(20, -randNum(1,5)); //TODO kolla livslängd
asteroid.setSpriteName("asteroid.png");
asteroid.setTexture(renderer);
asteroid.setPos(randNum(0, SCREEN_WIDTH) , -200);
asteroid.makeEnemy();
asteroid.changeSpriteSize(8, 8, 128);
asteroids.pushBack(asteroid);
}
void SpaceInv::generateEnemy() {
SpaceObject enemy(20, -2); //TODO kolla livslängd
enemy.setSpriteName("enemyship.png");
enemy.setTexture(renderer);
enemy.setPos(randNum(0, SCREEN_WIDTH), -200);
enemy.makeEnemy();
enemyShips.pushBack(enemy);
}
int SpaceInv::randNum(int min, int max) {
int output = min + (rand() % static_cast<int>(max - min + 1));
return output;
}
bool SpaceInv::checkCollitions(SDL_Rect& a, SDL_Rect& b) {
//The sides of the rectangles
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;
leftA = a.x;
rightA = a.x + a.w;
topA = a.y;
bottomA = a.y + a.h;
leftB = b.x;
rightB = b.x + b.w;
topB = b.y;
bottomB = b.y + b.h;
if (bottomA <= topB) {
return false;
}
if (topA >= bottomB) {
return false;
}
if (rightA <= leftB) {
return false;
}
if (leftA >= rightB) {
return false;
}
//If none of the sides from A are outside B
return true;
}
void SpaceInv::Close() {
SDL_DestroyWindow(window);
window = NULL;
Mix_Quit();
SDL_Quit();
}
SpaceObject.h
#pragma once
#ifndef SPACEOBJECT
#define SPACEOBJECT
#include <SDL.h>
#include <stdio.h>
#include <SDL_image.h>
#include <string>
#include <ctime>
class SpaceObject {
public:
SpaceObject();
SpaceObject(double t, int sp);
SpaceObject(std::string s, SDL_Rect startPos, double t, int sp);
~SpaceObject();
double getDuration();
double getTimeToLive();
void setSpriteName(std::string s);
void setTimeToLive(int i);
std::string getSpriteName();
void setTexture(SDL_Renderer* &renderer);
SDL_Texture*& getTexture();
SDL_Rect getRect();
SDL_Rect* getRectP();
SDL_Rect getPos();
void setPos(int x, int y);
void moveY();
void animate();
void makeEnemy();
void changeSpriteSize(int a, int b, int c);
bool isEnemy();
protected:
//int test;
std::string spriteName;
SDL_Texture* texture;
SDL_Rect sprite;
SDL_Rect pos;
int speed;
int frameWidth, frameHeight;
int textureWidth, textureHeight;
bool enemy = false;
bool asteroid = false;
bool lazer = false;
double timeToLive;
double duration;
std::clock_t start;
};
#endif
SpaceObject.cpp
#include "SpaceObject.h"
#include <iostream>
SpaceObject::SpaceObject(){}
SpaceObject::SpaceObject(double t, int sp):timeToLive(t), speed(sp) {
start = std::clock();
enemy = false;
}
SpaceObject::SpaceObject(std::string s, SDL_Rect startPos, double t, int sp) : spriteName(s), timeToLive(t), pos(startPos), speed(sp) {
//pos.y = pos.y - 27;
start = std::clock();
enemy = false;
}
SDL_Rect* SpaceObject::getRectP() {
return &sprite;
}
void SpaceObject::makeEnemy() {
enemy = true;
}
void SpaceObject::changeSpriteSize(int a, int b, int c){
frameWidth = textureWidth / a;
frameHeight = textureHeight / b;
sprite.w = frameWidth;
sprite.h = frameHeight;
sprite.h = sprite.w = c;
}
bool SpaceObject::isEnemy() {
//enemy = false;
////std::cout.setf(std::ios::boolalpha);
////std::cout << enemy << std::endl;
return enemy;
}
void SpaceObject::setTimeToLive(int i) {
timeToLive = i;
}
void SpaceObject::setPos(int x, int y) {
pos.x = x;
pos.y = y;
}
SDL_Rect SpaceObject::getPos() {
//pos.y = pos.y - 5;
return pos;
}
double SpaceObject::getTimeToLive() { return timeToLive; }
std::string SpaceObject::getSpriteName() { return spriteName; }
void SpaceObject::setSpriteName(std::string s) {
spriteName = s;
}
void SpaceObject::setTexture(SDL_Renderer* &renderer) {
////std::cout << spriteName << std::endl;
SDL_Texture* newTexture = NULL;
SDL_Surface* loadedSurface = IMG_Load(spriteName.c_str());
if (loadedSurface == NULL) {
printf("Unable to load image! SDL_image Error %s\n", spriteName.c_str(), IMG_GetError);
}
else {
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if (newTexture == NULL) {
printf("Unable to create the texture from %s! SDL_image Error %s\n", SDL_GetError);
SDL_FreeSurface(loadedSurface);
}
}
texture = newTexture;
SDL_QueryTexture(texture, NULL, NULL, &textureWidth, &textureHeight);
frameWidth = textureWidth /2;
frameHeight = textureHeight /2;
//sprite.x = 0;
//sprite.y = 0;
sprite.w = frameWidth;
sprite.h = frameHeight;
pos.w = pos.h = 64;
}
SDL_Rect SpaceObject::getRect() {
return sprite;
}
void SpaceObject::animate() {
sprite.x += frameWidth;
if (sprite.x >= textureWidth) {
sprite.x = 0;
sprite.y += frameHeight;
if (sprite.y >= textureWidth) {
sprite.y = 0;
}
}
}
void SpaceObject::moveY() {
pos.y = pos.y - speed;
}
double SpaceObject::getDuration() {
duration = (std::clock() - start) / (double)CLOCKS_PER_SEC;
return duration;
}
SDL_Texture*& SpaceObject::getTexture() { return texture; }
SpaceObject::~SpaceObject() { ////std::cout << "Rymdobjekt borttaget" << std::endl;
}
Ship.h
#pragma once
#ifndef SHIP
#define SHIP
// "Lazer.h"
#include <SDL.h>
#include <stdio.h>
#include <SDL_image.h>
#include <string>
#include <iostream>
#include <string>
#include <thread>
//#include "SpaceInv.h"
class Ship {
public:
Ship();
Ship(std::string s);
~Ship();
void setSpriteName(std::string s);
std::string getSpriteName();
void setTexture(SDL_Renderer* &renderer);
SDL_Texture*& getTexture();
void animate();
SDL_Rect getRect();
SDL_Rect getPos();
//SDL_Texture*& Ship::fire(int speed, SDL_Rect start, SDL_Renderer* &renderer);
//void fire(int speed, SDL_Rect start);
void moveX(int speed);
void moveY(int speed);
private:
std::string spriteName;
SDL_Texture* texture;
SDL_Rect sprite;
SDL_Rect pos;
int frameWidth, frameHeight;
int textureWidth, textureHeight;
const int SCREEN_WIDTH = 720;
const int SCREEN_HEIGHT = 480;
};
#endif
Ship.cpp
#include "Ship.h"
//#include "Lazer.h"
Ship::Ship(){}
Ship::Ship(std::string s):spriteName(s){}
std::string Ship::getSpriteName() { return spriteName; }
void Ship::setSpriteName(std::string s) {
spriteName = s;
}
SDL_Texture*& Ship::getTexture(){ return texture; }
void Ship::setTexture(SDL_Renderer* &renderer) {
SDL_Texture* newTexture = NULL;
SDL_Surface* loadedSurface = IMG_Load(spriteName.c_str());
if (loadedSurface == NULL) {
printf("Unable to load image! SDL_image Error %s\n", spriteName.c_str(), IMG_GetError);
}
else {
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if (newTexture == NULL) {
printf("Unable to create the texture from %s! SDL_image Error %s\n", SDL_GetError);
SDL_FreeSurface(loadedSurface);
}
}
texture = newTexture;
SDL_QueryTexture(texture, NULL, NULL, &textureWidth, &textureHeight);
pos.w = pos.h = 64;
pos.x = 340;
pos.y = 255;
frameWidth = 192 / 2;
frameHeight = 192 / 2;
sprite.x = 0;
sprite.y = 0;
sprite.w = frameWidth;
sprite.h = frameHeight;
}
SDL_Rect Ship::getRect() {
return sprite;
}
SDL_Rect Ship::getPos() {
return pos;
}
void Ship::moveX(int speed){
if ((pos.x <= 0 && speed<0) || (pos.x >= SCREEN_WIDTH && speed>0)) {
//std:://std:://std::cout << "/n";
return;
}
pos.x = pos.x +speed*(SCREEN_WIDTH/20);
}
void Ship::moveY(int speed) {
if ((pos.y <= 0 && speed<0) || (pos.y >= SCREEN_HEIGHT && speed>0)) {
return;
}
pos.y = pos.y + speed*(SCREEN_WIDTH / 20);
}
void Ship::animate() {
sprite.x += frameWidth;
if (sprite.x >= textureWidth) {
sprite.x = 0;
sprite.y += frameHeight;
if (sprite.y >= textureWidth) {
sprite.y = 0;
}
}
}
/*
SDL_Texture*& Ship::fire(int speed, SDL_Rect start, SDL_Renderer* &renderer) {
Lazer lazer("lazer.png", start);
lazer.setTexture(renderer);
return lazer.getTexture();
}*/
Ship::~Ship() {}
SpaceContainer.h
#pragma once
#ifndef SPACECONTAINER
#define SPACECONTAINER
#include <SDL.h>
#include <stdio.h>
#include <SDL_image.h>
#include <string>
#include <iostream>
#include <string>
#include <vector>
#include "SpaceObject.h"
//#include "SpaceInv.h"
class SpaceContainer {
public:
SpaceContainer();
~SpaceContainer();
SpaceObject& getObject(int i);
std::vector<SpaceObject>& getVec();
void checkLifetime();
void pushBack(SpaceObject o);
void popAt(int i);
bool checkCollitions(SDL_Rect& a, SDL_Rect& b);
size_t size();
private:
std::vector<SpaceObject> vec;
};
#endif
SpaceContainer.cpp
#include "SpaceContainer.h"
SpaceContainer::SpaceContainer(){}
void SpaceContainer::checkLifetime(){
if (vec.empty()) {
return;
}
for (size_t i = 0; i < vec.size(); i++)
{
////std::cout << vec[i].getDuration() << std::endl;
if (vec[i].getDuration() >= vec[i].getTimeToLive()) {
vec.erase(vec.begin() + i);
// delete &vec[i];
////std::cout << "Object destroyed " << std::endl;
}
}
}
void SpaceContainer::popAt(int i) {
vec.erase(vec.begin() + i);
}
void SpaceContainer::pushBack(SpaceObject o) {
vec.push_back(o);
}
SpaceObject& SpaceContainer::getObject(int i) {
return vec.at(i);
}
std::vector<SpaceObject>& SpaceContainer::getVec() {
return vec;
}
size_t SpaceContainer::size(){
return vec.size();
}
SpaceContainer::~SpaceContainer(){}
ScoreBoard.h
#pragma once
#ifndef SCOREBOARD
#define SCOREBOARD
#include <SDL.h>
#include <stdio.h>
#include <SDL_image.h>
#include <string>
#include <iostream>
#include <string>
#include <thread>
#include <SDL_ttf.h>
class ScoreBoard {
public:
ScoreBoard();
void setTexture(SDL_Renderer* &renderer, std::string mes);
SDL_Texture*& getTexture();
SDL_Rect getRect();
SDL_Rect getPos();
~ScoreBoard();
private:
SDL_Rect sprite;
SDL_Rect pos;
SDL_Texture* texture;
};
#endif
ScoreBoard.cpp
#include "ScoreBoard.h"
#include <SDL_ttf.h>
#include <SDL_mixer.h>
ScoreBoard::ScoreBoard(){}
SDL_Texture*& ScoreBoard::getTexture() { return texture; }
SDL_Rect ScoreBoard::getRect() {
return sprite;
}
SDL_Rect ScoreBoard::getPos() {
return pos;
}
void ScoreBoard::setTexture(SDL_Renderer* &renderer, std::string mes) {
TTF_Font* Sans = TTF_OpenFont("FreeSansBold.ttf", 24);
SDL_Color White = { 255, 255, 255 };
if (!Sans) {
std::cout << "font not found..." << std::endl;
return;
}
const char * c = mes.c_str();
SDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, c, White);
texture = SDL_CreateTextureFromSurface(renderer, surfaceMessage);
pos.w = 128;
pos.h = 64;
pos.x = 15;
pos.y = 5;
}
ScoreBoard::~ScoreBoard(){};
对不起,代码不是那么漂亮。 (它包含一些控制台输出和用于调试的东西+一些不再使用的超出评论的对象)。为什么我的游戏停止工作的任何建议?先谢谢!
答案 0 :(得分:0)
感谢nwp 3的评论,我解决了!问题确实是我的计划要求提供大量资源。通过在我的SpaceContainer类中调用&#34; SDL_DestroyTexture(SDL_Texture * texture)&#34;,每次SpaceObject被销毁时,问题就解决了!
<强> SpaceContainer.cpp 强>
Expression