Edit: The fix for this is in my 2nd post.
So, I spent pretty much all day trying to fix this and am about ready to pull my hair out. My program runs fine right up until it exits main(), at which point it complains about "Unhandled exception at 0x006853cc in Tile Engine Tutorial.exe: 0xC0000005: Access violation reading location 0x02fec040." I'm using VC++ 2010 Express and SFML 2.0. The code is part of a tile engine for roguelike. (IN SPACE!)
//Include the tile engine
#include "Engine.h"
// basic file operations
#include <iostream>
#include <fstream>
using namespace std;
int main(int args, char* argc[])
{
Engine* engine = new Engine(800, 600, 16);
try
{
engine->Go();
}
catch(char* e)
{
ofstream errorLog;
errorLog.open ("error.txt");
errorLog << e;
errorLog.close();
return 0;
}
delete engine;
}
#ifndef _ENGINE_H
#define _ENGINE_H
// basic file operations
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <SFML\Graphics.hpp>
#include <SFML\System.hpp>
#include <SFML\Window.hpp>
//Memory leak detection with Visual Leak Detector
#include <vld.h>
#include "ImageManager.h"
#include "Tile.h"
#include "Camera.h"
#include "Level.h"
#include "Text.h"
#include "Player.h"
#include "Sound.h"
class Engine
{
private:
//SFML Render Window
sf::RenderWindow* window;
sf::Window* windowMain;
sf::Vector2i videoSize;
//Camera
Camera* camera;
//Debug output for the camera
TextOutput* cameraPos;
std::string cameraPosX;
std::string cameraPosY;
std::string cameraPosString;
//Debug output for the mouse
TextOutput* mousePos;
std::string mousePosX;
std::string mousePosY;
std::string mousePosString;
ImageManager imageManager;
//Window events.
sf::Event evt;
//Current Level
Level* currentLevel;
//Sound effects
SoundEffect* collisionSound;
//The global clock
sf::Clock clock;
sf::Time time1;
//Tile Dimensions
int tileSize;
//The player
Player* player;
bool inShip;
//Initializes the engine
bool Init();
//Main Game Loop
void MainLoop();
//Renders one frame
void RenderFrame();
//Processes user input
void ProcessInput();
//Updates all Engine internals
void Update();
public:
Engine(int w, int h, int tileSize);
~Engine();
void Go(); //Starts the engine
};
#endif
#include "Engine.h"
#define DEBUG 0
#define AREA_SIZE 10
using namespace std;
Engine::Engine(int w, int h, int tileSize)
{
videoSize = sf::Vector2i(w, h);
this->tileSize = tileSize;
imageManager.setTileSize(tileSize);
}
Engine::~Engine()
{
}
bool Engine::Init()
{
//Set up the main window and associated debug output.
window = new sf::RenderWindow(sf::VideoMode(videoSize.x, videoSize.y, 32), "RPG");
if(!window)
throw "Could not create window!";
window->setFramerateLimit(60);
mousePos = new TextOutput("swansea.ttf", 30);
if(!mousePos)
throw "Could not create mouse position text!";
//Set up the camera and associated debug output.
camera = new Camera(videoSize.x, videoSize.y, 1);
if(!camera)
throw "Could not create camera!";
cameraPos = new TextOutput("swansea.ttf", 30);
if(!cameraPos)
throw "Could not create camera position text!";
//Set up the player object, position the camera and listener and create any sound effects needed.
player = new Player(4 * tileSize, 1 * tileSize, imageManager.LoadPlayer("player.png"));
if(!player)
throw "Could not create player!";
collisionSound = new SoundEffect("knock.wav");
if(!collisionSound)
throw "Could not create sound!";
sf::Listener::setPosition(player->playerPos.x, player->playerPos.y, -1);
camera->MoveCenter(player->playerPos.x, player->playerPos.y);
//Set up the level.
currentLevel = new Level();
if(!currentLevel)
throw "Could not create level!";
currentLevel->LoadLevel("shipList.xml", imageManager);
inShip = false;
return true;
}
void Engine::RenderFrame()
{
//Camera offsets
int camOffsetX, camOffsetY;
Tile* tile;
window->setActive();
//Get the tile bounds we need to draw
sf::IntRect bounds = camera->GetTileBounds(tileSize);
//Figure out how much to offset each tile
camOffsetX = camera->GetTileOffset(tileSize).x;
camOffsetY = camera->GetTileOffset(tileSize).y;
//Draw the background so the map edges don't glitch
sf::Texture backgroundTexture;
backgroundTexture.loadFromFile("background.png");
sf::Sprite backgroundSprite;
backgroundSprite.setTexture(backgroundTexture);
window->draw(backgroundSprite);
//Loop through and draw each tile
//We're keeping track of two variables in each loop. How many tiles
//we've drawn (x and y), and which tile on the map we're drawing (tileX
//and tileY)
for(int y = 0, tileY = bounds.top; y < bounds.height; y++, tileY++)
{
for(int x = 0, tileX = bounds.left; x < bounds.width; x++, tileX++)
{
//Get the tile we're drawing
tile = currentLevel->GetTile(tileX, tileY);
if(tile)
{
if(currentLevel->mapUnWalkable[tileX][tileY])
tile->baseSprite.setColor(sf::Color::Red);
else
tile->baseSprite.setColor(sf::Color::White);
tile->Draw((x * tileSize) - camOffsetX, (y * tileSize) - camOffsetY, window);
}
}
}
if(DEBUG) //Display the camera and mouse co-ordinates in the bottom left corner of the screen
{
cameraPosX = static_cast<ostringstream*>( &(ostringstream() << camera->GetPosition().x) )->str();
cameraPosY = static_cast<ostringstream*>( &(ostringstream() << camera->GetPosition().y) )->str();
cameraPosString = "Camera Pos: " + cameraPosX + ", " + cameraPosY + ".";
cameraPos->write(cameraPosString, window, sf::Vector2f(5, videoSize.y - cameraPos->text1.getCharacterSize() - 5));
mousePosX = static_cast<ostringstream*>( &(ostringstream() << sf::Mouse::getPosition(*window).x) )->str();
mousePosY = static_cast<ostringstream*>( &(ostringstream() << sf::Mouse::getPosition(*window).y) )->str();
mousePosString = "Mouse Pos: " + mousePosX + ", " + mousePosY + ".";
mousePos->write(mousePosString, window, sf::Vector2f(5, videoSize.y - (2 * mousePos->text1.getCharacterSize()) - 5));
}
//Draw the player in the center of the screen
player->DrawPlayer(sf::Vector2f(videoSize.x/2, videoSize.y/2), window);
window->display();
}
void Engine::ProcessInput()
{
//Loop through all window events
while(window->pollEvent(evt))
{
if(evt.type == sf::Event::Closed)
{
window->close();
delete player;
delete collisionSound;
delete currentLevel;
delete camera;
delete cameraPos;
delete mousePos;
}
}
//Check how long it was since we last took any input to avoid spam.
time1 = clock.getElapsedTime();
if(time1.asMilliseconds() > 500)
{
bool keyPressed = false;
//Check to see if the player wants to move in a given direction, and whether they're at the map edge or next to a wall.
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && player->playerPos.x > 0)
{
if(!currentLevel->mapUnWalkable[(player->playerPos.x/tileSize) - 1][player->playerPos.y/tileSize])
{
player->playerPos.x -= tileSize;
keyPressed = true;
}
else
collisionSound->PlaySoundEffect();
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && player->playerPos.x < AREA_SIZE)
{
if(!currentLevel->mapUnWalkable[(player->playerPos.x/tileSize) + 1][player->playerPos.y/tileSize])
{
player->playerPos.x += tileSize;
keyPressed = true;
}
else
collisionSound->PlaySoundEffect();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && player->playerPos.y > 0)
{
if(!currentLevel->mapUnWalkable[player->playerPos.x/tileSize][(player->playerPos.y/tileSize) - 1])
{
player->playerPos.y -= tileSize;
keyPressed = true;
}
else
collisionSound->PlaySoundEffect();
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && player->playerPos.y < AREA_SIZE)
{
if(!currentLevel->mapUnWalkable[player->playerPos.x/tileSize][(player->playerPos.y/tileSize) + 1])
{
player->playerPos.y += tileSize;
keyPressed = true;
}
else
collisionSound->PlaySoundEffect();
}
if(keyPressed)
{
camera->MoveCenter(player->playerPos.x, player->playerPos.y);
sf::Listener::setPosition(player->playerPos.x, player->playerPos.y, -1);
clock.restart();
}
}
}
void Engine::Update()
{
//Disabled for now
if(inShip)
{
camera->Update();
}
}
void Engine::MainLoop()
{
//Loop until our window is closed
while(window->isOpen())
{
ProcessInput();
if(window->isOpen())
{
Update();
RenderFrame();
}
}
delete window;
}
void Engine::Go()
{
if(!Init())
throw "Could not initialize Engine";
MainLoop();
}
#ifndef _SOUND_H
#define _SOUND_H
#include <SFML\Audio.hpp>
class SoundEffect
{
public:
SoundEffect(std::string file);
~SoundEffect();
void SoundEffect::PlaySoundEffect();
sf::SoundBuffer buffer;
sf::Sound sound;
};
#endif
#include "Sound.h"
SoundEffect::SoundEffect(std::string file)
{
buffer.loadFromFile(file);
sound.setBuffer(buffer);
}
SoundEffect::~SoundEffect()
{
}
void SoundEffect::PlaySoundEffect()
{
sound.play();
}
Commenting out any reference to "sf::SoundBuffer buffer" or "sf::Sound sound" stops the access violation, so I'm pretty sure it's related to the sound module. The call stack also mentions openal32.dll last, and sfml-audio-d-2.dll right before it.
Apologies if my code sucks and/or is hard to read, it's a mix of a tutorial (From someone who uses new without delete) and my own code. (From someone who generally isn't very good)