BackgroundHello! This is my first post on SFML forums, having been introduced to SFML about a week ago. I am making a 2d worms-like game in which I need a random map generator for two islands. For that I am using SFML::Image and SFML::Shape to dish out the map and add some rocklike structures (actually more like gold patches for the player to mine for money in bedrock). Unfortunately this approach SEGFAULTs at every instance my program tries to destruct an SFML object, ultimately at program exit if not sooner.
The codeHere is my version of the code, the exact place which raises the segfault is the calling of generate for terrainMap in the constructor of Terrain. The program faults between the end of generate and the return to the constructor, but more of that later.
Terrain.cc:
#include <SFML/Graphics.hpp> // SFML image
#include <iostream> // std::cout
#include <vector> // vector
#include <cstdlib> // rand
#include <ctime> // ctime
#include <cmath> // cos, sin
#include <algorithm> // max
#include "terrain.hh"
Terrain::Terrain()
{
width = 0;
height = 0;
}
Terrain::Terrain(size_t width, size_t height, double roughness, size_t waterLvl) {
width = width;
height = height;
this->generate(width, height, roughness, waterLvl);
}
Terrain::~Terrain() {
delete &terrainMap;
}
void Terrain::generate(size_t width, size_t height, double roughness, size_t waterLvl) {
terrainMap.create(width, height, sf::Color::White);
double displacementFactor = 1.0 * height / 2;
// Here editing the amount of initial cells determines the amount of mountains
// Use [Number you want] + 1
std::vector<int> heightMap(3, 0);
// Create waterlevel
for (size_t x = 0; x < width; x++) {
for (size_t y = 0; y < waterLvl; y++) {
terrainMap.setPixel(x, height - y, sf::Color::Blue);
}
}
// Create sand
for (int i = 0; i < 6; i++) {
heightMap = split(heightMap, displacementFactor);
displacementFactor *= roughness;
}
// Draw sand
double segmentWidth = (width / (2 * heightMap.size()));
for (size_t x = 0; x < heightMap.size() - 1; x++) {
double slope = (heightMap[x + 1] - heightMap[x]) / segmentWidth;
for (size_t xMap = 0; xMap < segmentWidth; xMap++) {
for (size_t y = 0; y < heightMap[x] + slope * xMap; y++) {
terrainMap.setPixel(width / 4 + x * segmentWidth + xMap, height - y, sf::Color::Green);
}
}
}
// Clear and initialize the heightMap (again)
heightMap.clear();
heightMap.resize(3);
// Create stone
displacementFactor = 0.7 * height / 2;
for (int i = 0; i < 6; i++) {
heightMap = split(heightMap, displacementFactor);
displacementFactor *= roughness;
}
// Draw stone
segmentWidth = (width / (2 * heightMap.size()));
for (size_t x = 0; x < heightMap.size() - 1; x++) {
double slope = (heightMap[x + 1] - heightMap[x]) / segmentWidth;
for (size_t xMap = 0; xMap < segmentWidth; xMap++) {
for (size_t y = 0; y < heightMap[x] + slope * xMap; y++) {
terrainMap.setPixel(width / 4 + x * segmentWidth + xMap, height - y, sf::Color::Black);
}
}
}
// Create gold patches
size_t xGold, yGold;
sf::ConvexShape shape;
shape.setPointCount(6);
size_t max_patches = size_t(width / 500);
for(size_t i = 0; i < max_patches; i++){
xGold = rand() % width; yGold = rand() % height;
if (getMaterial(xGold, yGold) == Terrain::Material::STONE || getMaterial(xGold, yGold) == Terrain::Material::SAND){ //if random point on map is STONE, make an elliptical gold patch around it
for (size_t i = 0; i < 6; i++) {
size_t radius = rand() % 60 + 1;
shape.setPoint(i, sf::Vector2f( xGold + radius * cos(30*i), yGold + radius * sin(30 * i)));
}
for (size_t i = 0; i < shape.getPointCount() - 1; i++) {
terrainMap.setPixel(shape.getPoint(i).x, shape.getPoint(i).y, sf::Color::Yellow);
}
}
} <<<<<<<<< GDB OUTPUT PASTED FROM HERE ONWARDS
}
// Generate the mountain ridge with midpoint dislocation algorithm
std::vector<int> Terrain::split(std::vector<int> heightMap, double displacementFactor) {
std::vector<int> newHeightMap(2 * heightMap.size() - 1);
for (size_t i = 0; i < heightMap.size() - 1; i++) {
// Calculate midpoint heights
double midpoint = (heightMap[i] + heightMap[i + 1]) / 2;
double fRand = (double)rand() / (double)RAND_MAX;
double displacement = fRand * displacementFactor;
// Force island shape
if (i == 0) {
if (displacement < 0) {
displacement *= -1;
}
}
newHeightMap[2 * i] = heightMap[i];
newHeightMap[2 * i + 1] = midpoint + displacement;
}
return newHeightMap;
}
Terrain::Material Terrain::getMaterial(const size_t x, const size_t y) {
sf::Color pixel = terrainMap.getPixel(x, y);
if (pixel == sf::Color::Blue) {
return WATER;
}
if (pixel == sf::Color::Green) {
return SAND;
}
if (pixel == sf::Color::Black) {
return STONE;
}
if (pixel == sf::Color::Yellow) {
return GOLD;
}
return AIR;
}
Terrain.hh:
#ifndef ART_13_TERRAIN
#define ART_13_TERRAIN
#include <SFML/Graphics.hpp> // SFML image
#include <vector> // vector
#include <cstdlib> //rand
/**
* This is the class for generating and modifying the terrain image
* Terrain is constructed from an image representing the different materials.
* The physics library is used to erode the class after initial generating.
*/
class Terrain {
public:
enum Material {
STONE,
SAND,
AIR,
WATER,
GOLD
};
// Constructor
Terrain();
// Constructor with parameters
Terrain(size_t width, size_t height, double roughness, size_t waterLvl);
// CpyConstructor - DELETED
Terrain(const Terrain& terrain) = delete;
// Destructor
~Terrain();
// Generate rough terrain
void generate(size_t width, size_t height, double roughness, size_t waterLvl);
// Recursive function for splitting the heightmap
std::vector<int> split(std::vector<int> heightMap, double roughness);
// Erode sand until stationary
void erode();
// Get the map
sf::Image getMap() {
return terrainMap;
}
// Get map width
size_t getWidth() {
return width;
}
// Get map height
size_t getHeight() {
return height;
}
// Returns the material of given pixel
Material getMaterial(const size_t x, const size_t y);
sf::Image emptyImage();
private:
sf::Image terrainMap;
size_t width;
size_t height;
};
#endif
I compile this with SFML 2.1 and GCC (compile++ is my alias for compiling c++ with std=c++11 and all the warnings enabled)
compile++ main main.cc terrain.cc -I/home/Developement/SMFL2.1 -lsfml-graphics -lsfml-window -lsfml-system
GDBAs I said earlier the code seems to segfault just as it returns from the generate-method. This is the GDB output from my code from line 95 (end of generate, marked in the code for your enjoyment) onwards using gdb's step command:
Breakpoint 1, Terrain::generate (this=0x7fffffffe290, width=3200, height=800, roughness=0.5, waterLvl=100) at terrain.cc:95
95 }
(gdb) step
sf::ConvexShape::~ConvexShape (this=0x7fffffffdfc0, __in_chrg=<optimized out>) at /usr/local/include/SFML/Graphics/ConvexShape.hpp:42
42 class SFML_GRAPHICS_API ConvexShape : public Shape
(gdb)
std::__debug::vector<sf::Vector2<float>, std::allocator<sf::Vector2<float> > >::~vector (this=0x7fffffffe150, __in_chrg=<optimized out>)
at /usr/include/c++/4.7/debug/vector:140
140 ~vector() _GLIBCXX_NOEXCEPT { }
(gdb)
__gnu_debug::_Safe_sequence<std::__debug::vector<sf::Vector2<float>, std::allocator<sf::Vector2<float> > > >::~_Safe_sequence (this=0x7fffffffe168,
__in_chrg=<optimized out>) at /usr/include/c++/4.7/debug/safe_sequence.h:112
112 class _Safe_sequence : public _Safe_sequence_base
(gdb)
__gnu_debug::_Safe_sequence_base::~_Safe_sequence_base (this=0x7fffffffe168, __in_chrg=<optimized out>) at /usr/include/c++/4.7/debug/safe_base.h:199
199 { this->_M_detach_all(); }
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7527f60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
This seems to me like the destructor for convexShape failed, but how? I am by no means an expert C++ coder and just now working my way out from pure standard libraries but I can't get my head around to which could be the source of this. If this is an error in my understanding of SFML/C++ altogether it would help to get it solved now rather than 2000 more lines into the code. Thank you ever so much for your time!