Пример #1
0
int main(int argc, char *argv[])
{
    QGuiApplication a(argc, argv);

    a.setOrganizationDomain(QLatin1String("mapeditor.org"));
    a.setApplicationName(QLatin1String("TerrainGenerator"));
    a.setApplicationVersion(QLatin1String("1.0"));

    CommandLineOptions options;

    if (!parseCommandLineArguments(options)) {
        // Something went wrong, abort.
        return 1;
    }

    if (options.showVersion)
        showVersion();
    if (options.showHelp)
        showHelp();
    if (options.showVersion || options.showHelp)
        return 0;

    if (options.target.isEmpty()) {
        qWarning() << "Error: No target tileset provided";
        showHelp();
        return 1;
    }
    if (options.sources.isEmpty()) {
        qWarning() << "Error: No source tilesets provided";
        showHelp();
        return 1;
    }

    // Check terrain priorities.
    if (options.terrainPriority.isEmpty()) {
        qWarning("Error: No terrain priorities set (option -p).");
        showHelp();
        return 1;
    }

    MapReader reader;
    SharedTileset targetTileset;
    QList<SharedTileset> sources;

    if (!options.overwrite && QFile::exists(options.target)) {
        targetTileset = reader.readTileset(options.target);
        if (!targetTileset) {
            qCritical("Error reading target tileset:\n%s",
                      qUtf8Printable(reader.errorString()));
        }

        // Remove empty tiles from the end of the tileset
        int nextTileId = targetTileset->nextTileId();
        for (int id = nextTileId - 1; id >= 0; --id) {
            if (Tile *tile = targetTileset->findTile(id)) {
                if (isEmpty(tile->image().toImage())) {
                    targetTileset->deleteTile(id);
                    nextTileId = id;
                    continue;
                }
            }

            break;
        }
        targetTileset->setNextTileId(nextTileId);

        // If the target tileset already exists, it is also a source tileset
        sources.append(targetTileset);
    }

    // Read source tilesets.
    for (const QString &sourceFileName : options.sources) {
        SharedTileset source = reader.readTileset(sourceFileName);
        if (!source) {
            qCritical("Error reading source tileset '%s':\n%s",
                      qUtf8Printable(sourceFileName),
                      qUtf8Printable(reader.errorString()));
        }
        sources.append(source);
    }

    // If the target tileset does not exist yet, create it
    if (!targetTileset) {
        QString name = QFileInfo(options.target).completeBaseName();
        const SharedTileset &firstSource = sources.first();
        int tileWidth = firstSource->tileWidth();
        int tileHeight = firstSource->tileHeight();

        targetTileset = Tileset::create(name, tileWidth, tileHeight);
    }

    // Set up a mapping from terrain to tile, for quick lookup
    QMap<TileTerrainNames, Tile*> terrainToTile;
    for (const SharedTileset &tileset : sources)
        for (Tile *tile : tileset->tiles())
            if (tile->terrain() != 0xFFFFFFFF)
                if (!terrainToTile.contains(TileTerrainNames(tile))) // TODO: Optimize
                    terrainToTile.insert(TileTerrainNames(tile), tile);

    // Set up the list of all terrains, mapped by name.
    QMap<QString, Terrain*> terrains;
    for (const SharedTileset &tileset : sources)
        for (Terrain *terrain : tileset->terrains())
            if (!terrains.contains(terrain->name()))
                terrains.insert(terrain->name(), terrain);

    // Check if there is anything to combine.
    if (options.combineList.size() == 0) {
        qWarning() << "No terrain specified to combine (-c option).";
    } else {
        // Dump the combine lists.
        qWarning() << "Terrains to combine:";
        for (const QStringList &combine : options.combineList) {
            if (combine.isEmpty()) {
                qCritical("Empty combine set");
            }
            qWarning() << combine;

            // Make sure every terrain from this set was defined.
            for (const QString &terrainName : combine)
                if (!terrains.contains(terrainName))
                    qCritical("Terrain %s is in combine list, however it wasn't defined by any tileset.",
                              qUtf8Printable(terrainName));
        }
    }

    // Setup terrain priorities.
    TerrainLessThan lessThan;
    int priority = 0;
    for (const QString &terrainName : options.terrainPriority) {
        lessThan.terrainPriority.insert(terrainName, priority);
        ++priority;
    }

    qDebug() << "Terrains found:" << terrains.keys();

    // Check if all terrains from priority list were found and loaded.
    for (const QString &terrainName : lessThan.terrainPriority.keys())
        if (!terrains.contains(terrainName))
            qWarning() << "Terrain" << terrainName << "from priority list not found.";

    // Add terrain names not specified from command line.
    for (const QString &terrainName : terrains.keys()) {
        if (!lessThan.terrainPriority.contains(terrainName)) {
            qWarning() << "No priority set for" << terrainName;
            lessThan.terrainPriority.insert(terrainName, priority);
            ++priority;
        }
    }

    // Add terrains that are not defined in the target tileset yet
    // TODO: This step should be more configurable
    for (Terrain *terrain : terrains) {
        if (!hasTerrain(*targetTileset, terrain->name())) {
            Tile *terrainTile = terrain->imageTile();
            QPixmap terrainImage = terrainTile->image();

            Tile *newTerrainTile = targetTileset->addTile(terrainImage);
            newTerrainTile->setProperties(terrainTile->properties());

            Terrain *newTerrain =  targetTileset->addTerrain(terrain->name(),
                                                             newTerrainTile->id());

            // WARNING: This assumes the terrain tile has this terrain on all
            // its corners.
            newTerrainTile->setTerrain(makeTerrain(newTerrain->id()));
            terrainToTile.insert(TileTerrainNames(newTerrainTile),
                                 newTerrainTile);
        }
    }

    // Prepare a list of terrain combinations.
    QVector<TileTerrainNames> process;
    for (const QStringList &combine : options.combineList) {
        QList<Terrain*> terrainList;
        // Get the terrains to combine
        for (const QString &terrainName : combine)
            terrainList.append(terrains[terrainName]);

        // Construct a vector with all terrain combinations to process
        for (Terrain *topLeft : terrainList) {
            for (Terrain *topRight : terrainList) {
                for (Terrain *bottomLeft : terrainList) {
                    for (Terrain *bottomRight : terrainList) {
                        process.append(TileTerrainNames(topLeft->name(),
                                                        topRight->name(),
                                                        bottomLeft->name(),
                                                        bottomRight->name()));
                    }
                }
            }
        }
    }

    // Go through each combination of terrains and add the tile to the target
    // tileset if it's not in there yet.
    for (const TileTerrainNames &terrainNames : process) {
        Tile *tile = terrainToTile.value(terrainNames);

        if (tile && tile->tileset() == targetTileset)
            continue;

        QPixmap image;
        Properties properties;

        if (!tile) {
            qWarning() << "Generating" << terrainNames;

            // Start a new image
            QImage tileImage = QImage(targetTileset->tileWidth(),
                                      targetTileset->tileHeight(),
                                      QImage::Format_ARGB32);
            tileImage.fill(Qt::transparent);
            QPainter painter(&tileImage);

            QStringList terrainList = terrainNames.terrainList();
            qSort(terrainList.begin(), terrainList.end(), lessThan);

            // Draw the lowest terrain to avoid pixel gaps
            QString baseTerrain = terrainList.first();
            QPixmap baseImage = terrains[baseTerrain]->imageTile()->image();
            painter.drawPixmap(0, 0, baseImage);

            for (const QString &terrainName : terrainList) {
                TileTerrainNames filtered = terrainNames.filter(terrainName);
                Tile *tile = terrainToTile.value(filtered);
                if (!tile) {
                    qWarning() << "Missing" << filtered;
                    continue;
                }

                painter.drawPixmap(0, 0, tile->image());
                properties.merge(tile->properties());
            }

            image = QPixmap::fromImage(tileImage);
        } else {
            qWarning() << "Copying" << terrainNames << "from"
                       << QFileInfo(tile->tileset()->fileName()).fileName();

            image = tile->image();
            properties = tile->properties();
        }

        Tile *newTile = targetTileset->addTile(image);
        newTile->setTerrain(terrainNames.toTerrain(*targetTileset));
        newTile->setProperties(properties);
        terrainToTile.insert(terrainNames, newTile);
    }

    if (targetTileset->tileCount() == 0)
        qCritical("Target tileset is empty");

    if (options.embedImage) {
        // Make sure there is no source name, this way the image will be saved in the TSX file.
        targetTileset->setImageSource(QString());
    } else {
        // Save the target tileset image as separate file.
        int columns = qMin(options.columns, targetTileset->tileCount());
        int rows = targetTileset->tileCount() / options.columns;
        if (targetTileset->tileCount() % options.columns > 0)
            ++rows;

        qWarning() << "Writing external tileset image.";
        // Save the target tileset image
        QImage image(targetTileset->tileWidth() * columns,
                     targetTileset->tileHeight() * rows,
                     QImage::Format_ARGB32);

        image.fill(Qt::transparent);
        QPainter painter(&image);

        for (Tile *tile : targetTileset->tiles()) {
            int x = (tile->id() % options.columns) * targetTileset->tileWidth();
            int y = (tile->id() / options.columns) * targetTileset->tileHeight();
            painter.drawPixmap(x, y, tile->image());
        }

        QString imageFileName = QFileInfo(options.target).completeBaseName();
        imageFileName += ".png";
        image.save(imageFileName);

        targetTileset->setImageSource(imageFileName);
        targetTileset->setColumnCount(options.columns);
    }

    // Save the target tileset
    MapWriter writer;
    targetTileset->setFileName(QString());
    writer.writeTileset(*targetTileset, options.target);

    return 0;
}
Пример #2
0
int TmxRasterizer::render(const QString &mapFileName,
                          const QString &imageFileName)
{
    MapReader reader;
    std::unique_ptr<Map> map { reader.readMap(mapFileName) };
    if (!map) {
        qWarning("Error while reading \"%s\":\n%s",
                 qUtf8Printable(mapFileName),
                 qUtf8Printable(reader.errorString()));
        return 1;
    }

    std::unique_ptr<MapRenderer> renderer;

    switch (map->orientation()) {
    case Map::Isometric:
        renderer.reset(new IsometricRenderer(map.get()));
        break;
    case Map::Staggered:
        renderer.reset(new StaggeredRenderer(map.get()));
        break;
    case Map::Hexagonal:
        renderer.reset(new HexagonalRenderer(map.get()));
        break;
    case Map::Orthogonal:
    default:
        renderer.reset(new OrthogonalRenderer(map.get()));
        break;
    }

    QRect mapBoundingRect = renderer->mapBoundingRect();
    QSize mapSize = mapBoundingRect.size();
    QPoint mapOffset = mapBoundingRect.topLeft();
    qreal xScale, yScale;

    if (mSize > 0) {
        xScale = (qreal) mSize / mapSize.width();
        yScale = (qreal) mSize / mapSize.height();
        xScale = yScale = qMin(1.0, qMin(xScale, yScale));
    } else if (mTileSize > 0) {
        xScale = (qreal) mTileSize / map->tileWidth();
        yScale = (qreal) mTileSize / map->tileHeight();
    } else {
        xScale = yScale = mScale;
    }

    QMargins margins = map->computeLayerOffsetMargins();
    mapSize.setWidth(mapSize.width() + margins.left() + margins.right());
    mapSize.setHeight(mapSize.height() + margins.top() + margins.bottom());

    mapSize.rwidth() *= xScale;
    mapSize.rheight() *= yScale;

    QImage image(mapSize, QImage::Format_ARGB32);
    image.fill(Qt::transparent);
    QPainter painter(&image);

    painter.setRenderHint(QPainter::Antialiasing, mUseAntiAliasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, mSmoothImages);
    painter.setTransform(QTransform::fromScale(xScale, yScale));

    painter.translate(margins.left(), margins.top());
    painter.translate(-mapOffset);

    // Perform a similar rendering than found in exportasimagedialog.cpp
    LayerIterator iterator(map.get());
    while (const Layer *layer = iterator.next()) {
        if (!shouldDrawLayer(layer))
            continue;

        const auto offset = layer->totalOffset();

        painter.setOpacity(layer->effectiveOpacity());
        painter.translate(offset);

        const TileLayer *tileLayer = dynamic_cast<const TileLayer*>(layer);
        const ImageLayer *imageLayer = dynamic_cast<const ImageLayer*>(layer);

        if (tileLayer) {
            renderer->drawTileLayer(&painter, tileLayer);
        } else if (imageLayer) {
            renderer->drawImageLayer(&painter, imageLayer);
        }

        painter.translate(-offset);
    }

    map.reset();

    // Save image
    QImageWriter imageWriter(imageFileName);

    if (!imageWriter.canWrite())
        imageWriter.setFormat("png");

    if (!imageWriter.write(image)) {
        qWarning("Error while writing \"%s\": %s",
                 qUtf8Printable(imageFileName),
                 qUtf8Printable(imageWriter.errorString()));
        return 1;
    }

    return 0;
}
Пример #3
0
void GameCore::initializeItems()
{
    if(mapMode)
    {
        MapReader* mapReader = mazeBuilder->getMapReader();
        int itemId = 0;
        if (mapReader != NULL)
        {
            float scaleFactor = mapReader->getScaleFactor();
            MapEntity2_t* ent;
            std::string meshName="LaserRifle.mesh";
            std::string materialName="LaserRifleItem";
            Ogre::Vector3 meshScale(2,2,2);
            while ((ent = mapReader->getItem()) != NULL)
            {
                if (ent->type == ItemType::LASER_MACHINE_GUN)
                {
                    meshName = "LaserRifle.mesh";
                    materialName = "LaserRifleItem";
                    meshScale=Ogre::Vector3(2,2,2);
                }
                else if(ent->type==ItemType::LASER_PISTOL)
                {
                    meshName="cube.mesh";
                    materialName="LaserPistolItem";
                    meshScale=Ogre::Vector3(.05,.05,.05);
                }
                else if(ent->type==ItemType::EAGLE_EYE)
                {
                    meshName="EagleEye.mesh";
                    materialName="NULL";
                    meshScale=Ogre::Vector3(4,4,4);
                }
                else if(ent->type==ItemType::EXTRA_HEALTH)
                {
                    meshName="Medkit.mesh";
                    materialName="NULL";
                    meshScale=Ogre::Vector3(12,12,12);
                }
				else if(ent->type==ItemType::IMMORTALITY)
				{
					meshName="Immortality.mesh";
					materialName="NULL";
					meshScale=Ogre::Vector3(10,10,10);
				}
				else if(ent->type==ItemType::ONE_SHOT)
				{
					meshName="OneShot.mesh";
					materialName="NULL";
					meshScale=Ogre::Vector3(15,15,15);
				}
                else
                {
                    Logger::getSingleton()->addLine("GameCore: unidentified item read", true);
                    continue;
                }
				Ogre::Vector3 itemPos(-ent->entityPosition.startX*scaleFactor,0,ent->entityPosition.startZ*scaleFactor);
				Ogre::Vector3 startPos=itemPos;
				Ogre::Vector3 endPos=itemPos;
				startPos.y=mazeBuilder->getWallHeight()-10;
				endPos.y=-100;
				btCollisionObject object;
				Ogre::Vector3 hitPos;
				if(PhysicsHandler::performRaycastTest(startPos,endPos,dynamics,&object,&hitPos))
				{
					CollisionObjectInfo* info=(CollisionObjectInfo*)object.getUserPointer();
					std::cout<<"type: "<<info->getObjectType()<<std::endl;
					if(info->getObjectType()==CollisionObjectTypes::GROUND || info->getObjectType()==CollisionObjectTypes::STATIC_OBJECT)
						itemPos.y=hitPos.y;
					else if(info->getObjectType()==CollisionObjectTypes::WALL)
					{
						Logger::getSingleton()->addLine("GameCoreInitializer: item-wall collision detected; item removed",true);
						continue;
					}
				}
				itemPos.y+=10;
                createItem(itemId++, (ItemType::ItemTypes)ent->type, meshName, materialName, meshScale, itemPos);
            }
        }
    }
}
Пример #4
0
// -----------------------------------------------------------------
// Name : autoStartGame
// -----------------------------------------------------------------
void DebugManager::autoStartGame()
{
    // Build client data
    int nbClients = 1;
    ClientData * clients = new ClientData[nbClients];
    int iClient = 0;
    clients[iClient].bLocal = true;

    // Re-init map data
    MapReader * pMapReader = new MapReader(m_pLocalClient);
    pMapReader->init("standard.lua");
    ObjectList * pMapParameters = new ObjectList(true);
    pMapReader->getMapParameters(pMapParameters, LABEL_MAX_CHARS);

    int * pCustomParams = NULL;
    if (pMapParameters->size > 0)
        pCustomParams = new int[pMapParameters->size];

    // Map custom parameters
    int i = 0;
    MapReader::MapParameters * pParam = (MapReader::MapParameters*) pMapParameters->getFirst(0);
    while (pParam != NULL)
    {
        pCustomParams[i++] = pParam->defaultValueIndex;
        pParam = (MapReader::MapParameters*) pMapParameters->getNext(0);
    }

    // Init map generator (we will not delete it here, as the pointer now belong to Server object)
    pMapReader->setMapParameters(pCustomParams, pMapParameters->size, 2);
    delete[] pCustomParams;
    MapReader::deleteMapParameters(pMapParameters);
    delete pMapParameters;

    // Init server
    Server * pServer = m_pLocalClient->initServer("", 1, clients, pMapReader, -1, -1);
    delete[] clients;
    if (pServer == NULL)
    {
        notifyErrorMessage("Error: server could not be initialized.");
        return;
    }

    // Build players data
    ObjectList * pServerPlayers = pServer->getSolver()->getPlayersList();
    // Create neutral player
    char sName[NAME_MAX_CHARS];
    i18n->getText("NEUTRA", sName, NAME_MAX_CHARS);
    Player * pPlayer = new Player(0, 0, pServer->getSolver()->getGlobalSpellsPtr());
    wsafecpy(pPlayer->m_sProfileName, NAME_MAX_CHARS, sName);
    pPlayer->m_Color = rgb(0.5, 0.5, 0.5);
    wsafecpy(pPlayer->m_sBanner, 64, "blason1");
    pServer->getSolver()->setNeutralPlayer(pPlayer);
    // Human players
    int playerId = 1;
    for (int fdfdf = 0; fdfdf < 2; fdfdf++)
    {
        // Create player object
        pPlayer = new Player(playerId, 0, pServer->getSolver()->getGlobalSpellsPtr());
        snprintf(pPlayer->m_sProfileName, NAME_MAX_CHARS, "test%d", playerId);
        Profile * pProfile = m_pLocalClient->getDataFactory()->findProfile(pPlayer->m_sProfileName);
        AvatarData * pAvatar = (AvatarData*) pProfile->getAvatarsList()->getFirst(0);
        pPlayer->m_Color = rgb(1, 1, 1);
        pAvatar->getBanner(pPlayer->m_sBanner, 64);
        pServerPlayers->addLast(pPlayer);
        // Set Avatar
        CoordsMap pos = pMapReader->getPlayerPosition(playerId-1);
        pServer->getSolver()->setInitialAvatar(pAvatar->clone(m_pLocalClient), pPlayer, pos);
        // Add spells that are equipped
        Profile::SpellData * pSpellDesc = (Profile::SpellData*) pProfile->getSpellsList()->getFirst(0);
        while (pSpellDesc != NULL)
        {
            AvatarData * pOwner = pSpellDesc->m_pOwner;
            if (pOwner != NULL && strcmp(pAvatar->m_sEdition, pOwner->m_sEdition) == 0
                    && strcmp(pAvatar->m_sObjectId, pOwner->m_sObjectId) == 0)
                pServer->getSolver()->addInitialPlayerSpell(pPlayer, pSpellDesc->m_sEdition, pSpellDesc->m_sName);
            pSpellDesc = (Profile::SpellData*) pProfile->getSpellsList()->getNext(0);
        }
        // Add equipped artifacts
        Artifact * pArtifact = (Artifact*) pProfile->getArtifactsList()->getFirst(0);
        while (pArtifact != NULL)
        {
            AvatarData * pOwner = pArtifact->m_pOwner;
            if (pOwner != NULL && strcmp(pAvatar->m_sEdition, pOwner->m_sEdition) == 0
                    && strcmp(pAvatar->m_sObjectId, pOwner->m_sObjectId) == 0)
            {
                Unit * pAvatarInGame = pPlayer->getAvatar();
                assert(pAvatarInGame != NULL);
                ArtifactEffect * pEffect = (ArtifactEffect*) pArtifact->getArtifactEffects()->getFirst(0);
                while (pEffect != NULL)
                {
                    switch (pEffect->getType())
                    {
                    case ARTIFACT_EFFECT_CHARAC:
                    {
                        bool bFound = true;
                        long val = pAvatarInGame->getValue(((ArtifactEffect_Charac*)pEffect)->m_sKey, false, &bFound);
                        if (bFound)
                            pAvatarInGame->setBaseValue(((ArtifactEffect_Charac*)pEffect)->m_sKey, max(0, val + ((ArtifactEffect_Charac*)pEffect)->m_iModifier));
                        else
                        {
                            char sError[1024];
                            snprintf(sError, 1024, "Warning: artifact %s tries to modify characteristic that doesn't exist (%s)", pArtifact->m_sObjectId, ((ArtifactEffect_Charac*)pEffect)->m_sKey);
                            m_pLocalClient->getDebug()->notifyErrorMessage(sError);
                        }
                        break;
                    }
                    case ARTIFACT_EFFECT_SPELL:
                    {
                        Spell * pSpell = m_pLocalClient->getDataFactory()->findSpell(((ArtifactEffect_Spell*)pEffect)->m_sSpellEdition, ((ArtifactEffect_Spell*)pEffect)->m_sSpellName);
                        if (pSpell != NULL)
                            pServer->getSolver()->addInitialPlayerSpell(pPlayer, ((ArtifactEffect_Spell*)pEffect)->m_sSpellEdition, ((ArtifactEffect_Spell*)pEffect)->m_sSpellName);
                        else
                        {
                            char sError[1024];
                            snprintf(sError, 1024, "Warning: artifact %s tries to add spell that doesn't exist (%s)", pArtifact->m_sObjectId, ((ArtifactEffect_Spell*)pEffect)->m_sSpellName);
                            m_pLocalClient->getDebug()->notifyErrorMessage(sError);
                        }
                        break;
                    }
                    case ARTIFACT_EFFECT_SKILL:
                    {
                        Skill * pSkill = new Skill(((ArtifactEffect_Skill*)pEffect)->m_sSkillEdition, ((ArtifactEffect_Skill*)pEffect)->m_sSkillName, ((ArtifactEffect_Skill*)pEffect)->m_sSkillParameters, pServer->getDebug());
                        if (pSkill != NULL && pSkill->isLoaded())
                            pAvatarInGame->addSkill(pSkill);
                        else
                        {
                            char sError[1024];
                            snprintf(sError, 1024, "Warning: artifact %s tries to add skill that doesn't exist or that can't be loaded (%s)", pArtifact->m_sObjectId, ((ArtifactEffect_Skill*)pEffect)->m_sSkillName);
                            m_pLocalClient->getDebug()->notifyErrorMessage(sError);
                        }
                        break;
                    }
                    }
                    pEffect = (ArtifactEffect*) pArtifact->getArtifactEffects()->getNext(0);
                }
            }
            pArtifact = (Artifact*) pProfile->getArtifactsList()->getNext(0);
        }
        playerId++;
    }
    delete pMapReader;
    pServer->onInitFinished();
}
Пример #5
0
int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	int timer = 0;

	MapReader mr = MapReader();

	//Map data
	string* map = nullptr;
	//map = mr.ReadMap("Maps/Randomized128x128-29-0.map");
	map = mr.ReadMap("Maps/maze512-1-1.map");
	//map = mr.ReadMap("Maps/adaptive-depth-1.map");
	//map = mr.ReadMap("Maps/32room_008.map");
	//map = GenerateMap(10, 10, 1.0f, mr);
	int width = mr.GetWidth();
	int height = mr.GetHeight();
	int nrOfWalls = mr.GetNrOfWalls(map);
	Vec2D startPos = {1, 1};
	Vec2D goalPos = {width-1, height-1};
	int clusterSize = 16;
	Vec2D* wallPos = new Vec2D[nrOfWalls];
	sf::RectangleShape* walls = new sf::RectangleShape[nrOfWalls];
	AStarNode** grid = nullptr;

	if (map != nullptr)
	{
		if (width > 0 && height > 0)
		{
			grid = new AStarNode*[width];

			//Initiate the grid** with walkable or non-walkable tiles
			int wallCounter = 0;
			for (int i = 0; i < width; i++)
			{
				grid[i] = new AStarNode[height];
				for (int j = 0; j < height; j++)
				{
					grid[i][j] = AStarNode(i, j);

					if (map[j*width + i] != "@")
					{
						grid[i][j]._traversable = true;
					}
					else
					{
						grid[i][j]._traversable = false;
						walls[wallCounter] = sf::RectangleShape(sf::Vector2f((float)tileWidth, (float)tileHeight));
						walls[wallCounter].setFillColor(sf::Color::White);
						walls[wallCounter].setPosition(sf::Vector2f(10.0f + (float)(tileWidth * i), 10.0f + (float)(tileHeight * j)));
						wallCounter++;
					}
				}
			}
		}
	}

	sf::View view;
	view.setCenter(0.5f * width * tileWidth, 0.5f * height * tileHeight);
	view.setSize(1.6f * width * tileWidth, 1.2f * height * tileHeight);
	sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "AI test");
	window.setFramerateLimit(60);
	window.setView(view);

	ImGui::SFML::SetRenderTarget(window);
	ImGui::SFML::InitImGuiRendering();
	ImGui::SFML::SetWindow(window);
	ImGui::SFML::InitImGuiEvents();

	sf::RectangleShape* openedTiles = nullptr;
	sf::RectangleShape* expandedTiles = nullptr;
	sf::Vertex* pathTiles = nullptr;
	
	//Mainly for the highlevel graph of HPA*
	sf::Vertex* abstractGraph = nullptr;
	sf::Vertex* openedGraph = nullptr;
	sf::Vertex* expandedGraph = nullptr;
	Metrics metrics;
	
	sf::CircleShape startNode = sf::CircleShape(0.4f*tileHeight);
	startNode.setPosition(sf::Vector2f(10.0f + startPos._x * (float)tileWidth, 10.0f + startPos._y * (float)tileHeight));
	startNode.setFillColor(sf::Color::Red);

	sf::CircleShape goalNode = sf::CircleShape(0.4f*tileHeight);;
	goalNode.setPosition(sf::Vector2f(10.0f + goalPos._x * (float)tileWidth, 10.0f + goalPos._y * (float)tileHeight));
	goalNode.setFillColor(sf::Color::Yellow);

	//Other variables
	bool calculatePaths = false;
	int choosePathfinding = 0;
	int chooseHeuristic = 0;

	//Movement variable
	int delta = width * 0.05f;
	float blockSize = 32.0f;

	//Randomize map variables
	bool randomizeMap = false;
	char widthBuffer[4] = "512";
	char heightBuffer[4] = "512";
	char densityBuffer[3] = "30";

	//Set start/goal position variables
	int startOrGoal = 0;   //0 == start pos, 1 == goal pos
	char xBuffer[4] = "0";
	char yBuffer[4] = "0";

	//What should be drawn?
	bool showWalls = false;
	bool showExpandedNodes = false;
	bool showOpenedNodes = false;

	while (window.isOpen())
	{
		ImGui::SFML::UpdateImGui();
		ImGui::SFML::UpdateImGuiRendering();
		sf::Event event;
		while (window.pollEvent(event))
		{
			ImGui::SFML::ProcessEvent(event);
			if (event.type == sf::Event::Closed)
			{
				window.close();
			}
		}

		ImGuiIO &io = ImGui::GetIO();
		//ImGui::ShowTestWindow();
		window.clear();

		/**************************************/
		/*          Start of GUI code         */
		/**************************************/
		if (ImGui::CollapsingHeader("Choose pathfinding"))
		{
			ImGui::RadioButton("A*", &choosePathfinding, 0);		ImGui::SameLine();
			ImGui::RadioButton("Theta*", &choosePathfinding, 1);	ImGui::SameLine();
			ImGui::RadioButton("HPA*", &choosePathfinding, 2);		ImGui::SameLine();
			ImGui::RadioButton("IDA*", &choosePathfinding, 3);		ImGui::SameLine();
			ImGui::RadioButton("Dijkstra", &choosePathfinding, 4);

			ImGui::RadioButton("Manhattan", &chooseHeuristic, 0);	ImGui::SameLine();
			ImGui::RadioButton("Chebyshev", &chooseHeuristic, 1);	ImGui::SameLine();
			ImGui::RadioButton("Octile", &chooseHeuristic, 2);		ImGui::SameLine();
			ImGui::RadioButton("Euclidean", &chooseHeuristic, 3);
		}
		if (ImGui::CollapsingHeader("Randomize a map"))
		{
			//Set width, height and obstacle density
			ImGui::InputText("Width", widthBuffer, IM_ARRAYSIZE(widthBuffer));
			ImGui::InputText("Height", heightBuffer, IM_ARRAYSIZE(heightBuffer));
			ImGui::InputText("Density (%)", densityBuffer, IM_ARRAYSIZE(densityBuffer));

			if (ImGui::SmallButton("Generate map"))
			{
				mr.GenerateRandomMap(stoi(string(widthBuffer)), stoi(string(heightBuffer)), 0.01f*stof(string(densityBuffer)));
			}
		}
		if (ImGui::CollapsingHeader("Set start/goal"))
		{
			ImGui::RadioButton("Set start position", &startOrGoal, 0); ImGui::SameLine();
			ImGui::RadioButton("Set goal position", &startOrGoal, 1);
			
			//Set xPos and yPos
			ImGui::InputText("X position", xBuffer, IM_ARRAYSIZE(xBuffer));
			ImGui::InputText("Y position", yBuffer, IM_ARRAYSIZE(yBuffer));

			if (ImGui::SmallButton("Set position"))
			{
				Vec2D pos = {stoi(string(xBuffer)), stoi(string(yBuffer))};
				if (startOrGoal == 0)  //Start pos
				{
					startPos = pos;
					startNode.setPosition(sf::Vector2f(10.0f + startPos._x * (float)tileWidth, 10.0f + startPos._y * (float)tileHeight));
				}
				else if (startOrGoal == 1)  //Goal pos
				{
					goalPos = pos;
					goalNode.setPosition(sf::Vector2f(10.0f + goalPos._x * (float)tileWidth, 10.0f + goalPos._y * (float)tileHeight));
				}
			}
		}
		if (ImGui::CollapsingHeader("Choose what will be drawn"))
		{
			ImGui::Checkbox("Walls", &showWalls);
			ImGui::Checkbox("Opened nodes", &showOpenedNodes);
			ImGui::Checkbox("Expanded nodes", &showExpandedNodes);
		}
		if (ImGui::SmallButton("Calculate paths"))
		{
			calculatePaths = !calculatePaths;
		}

		/**************************************/
		/*            End of GUI code         */
		/**************************************/

		//Moving of the camera
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))  //Move camera west
		{
			view.setCenter(view.getCenter().x, view.getCenter().y - delta);
		}
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))  //Move camera east
		{
			view.setCenter(view.getCenter().x - delta, view.getCenter().y);
		}
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))  //Move camera south
		{
			view.setCenter(view.getCenter().x, view.getCenter().y + delta);
		}
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))  //Move camera north
		{
			view.setCenter(view.getCenter().x + delta, view.getCenter().y);
		}

		//Zooming with the camera
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::PageUp) && blockSize <= 32.0f)  //Zoom out
		{
			view.setSize(sf::Vector2f(width * tileWidth * blockSize++ * 0.05f, height * tileHeight * blockSize++ * 0.0375f));
		}
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::PageDown) && blockSize >= 1.0f)  //Zoom in
		{
			view.setSize(sf::Vector2f(width * tileWidth * blockSize-- * 0.05f, height * tileHeight * blockSize-- * 0.0375f));
		}
		window.setView(view);


		//Calculate pathfinding
		if (calculatePaths)
		{
			metrics.clean();
			switch (choosePathfinding)
			{
			case 0:		//A*
				CalculateAStar(metrics, (Pathfinding::Heuristic)chooseHeuristic, width, height, startPos, goalPos, grid);
				break;
			case 1:		//Theta*
				CalculateThetaStar(metrics, (Pathfinding::Heuristic)chooseHeuristic, width, height, startPos, goalPos, grid);
				break;
			case 2:		//HPA*
				CalculateHPAStar(metrics, (Pathfinding::Heuristic)chooseHeuristic, width, height, startPos, goalPos, grid, clusterSize);
				break;
			case 3:		//IDA*
				CalculateIDAStar(metrics, (Pathfinding::Heuristic)chooseHeuristic, width, height, startPos, goalPos, grid);
				break;
			case 4:
				CalculateDijkstra(metrics, (Pathfinding::Heuristic)chooseHeuristic, width, height, startPos, goalPos, grid);
			default:
				break;
			}

			if (showOpenedNodes)
			{
				if (openedTiles != nullptr)
				{
					delete[] openedTiles;
				}
				openedTiles = new sf::RectangleShape[metrics.getNrOfOpenedNodes()];

				for (int i = 0; i < metrics.getNrOfOpenedNodes(); i++)
				{
					openedTiles[i] = sf::RectangleShape(sf::Vector2f((float)tileWidth, (float)tileHeight));
					openedTiles[i].setFillColor(sf::Color(0, 200, 200, 120));
					openedTiles[i].setPosition(sf::Vector2f(10.0f + (float)tileWidth * metrics.getOpenedNodes()[i]._x, 10.0f + (float)tileHeight * metrics.getOpenedNodes()[i]._y));
					window.draw(openedTiles[i]);
				}
			}

			if (showExpandedNodes)
			{
				if (expandedTiles != nullptr)
				{
					delete[] expandedTiles;
				}
				expandedTiles = new sf::RectangleShape[metrics.getNrOfExpandedNodes()];

				for (int i = 0; i < metrics.getNrOfExpandedNodes(); i++)
				{
					expandedTiles[i] = sf::RectangleShape(sf::Vector2f((float)tileWidth, (float)tileHeight));
					expandedTiles[i].setFillColor(sf::Color(200, 0, 0, 120));
					expandedTiles[i].setPosition(sf::Vector2f(10.0f + (float)tileWidth * metrics.getExpandedNodes()[i]._x, 10.0f + (float)tileHeight * metrics.getExpandedNodes()[i]._y));
					window.draw(expandedTiles[i]);
				}
			}

			if (pathTiles != nullptr)
			{
				delete[] pathTiles;
			}
			pathTiles = new sf::Vertex[metrics.getNrOfPathNodes() + 1];
			for (int i = 0; i < metrics.getNrOfPathNodes(); i++)
			{
				pathTiles[i] = sf::Vertex(sf::Vector2f(10.0f + (float)tileWidth * (metrics.getPathNodes()[i]._x + 0.5f), 10.0f + (float)tileHeight * (metrics.getPathNodes()[i]._y + 0.5f)));
				pathTiles[i].color = sf::Color(200, 0, 200, 255);
			}
			pathTiles[metrics.getNrOfPathNodes()] = sf::Vector2f(10.0f + (float)tileWidth * (startPos._x + 0.5f), 10.0f + (float)tileHeight * (startPos._y + 0.5f));
			
			SaveDataToFile(metrics, choosePathfinding, chooseHeuristic);
			calculatePaths = false;
		}

		//Draw the start and goal node(s)
		window.draw(startNode);
		window.draw(goalNode);

		if (choosePathfinding == 2)			//Special case for HPA*
		{
			window.draw(abstractGraph, metrics.getNrOfGraphNodes(), sf::Lines);

			if (showOpenedNodes)
			{
				window.draw(openedGraph, metrics.getNrOfOpenedNodes(), sf::Lines);
			}

			if (showExpandedNodes)
			{
				window.draw(expandedGraph, metrics.getNrOfExpandedNodes(), sf::Lines);
			}
		}
		else
		{
			if (showOpenedNodes && openedTiles != nullptr)
			{
				for (int i = 0; i < metrics.getNrOfOpenedNodes(); i++)
				{
					window.draw(openedTiles[i]);
				}
			}

			if (showExpandedNodes)
			{
				for (int i = 0; i < metrics.getNrOfExpandedNodes(); i++)
				{
					window.draw(expandedTiles[i]);
				}
			}
		}
		window.draw(pathTiles, metrics.getNrOfPathNodes() + 1, sf::LinesStrip);

		//Draw all the walls
		if (showWalls)
		{
			for (int i = 0; i < nrOfWalls; i++)
			{
				window.draw(walls[i]);
			}
		}

		ImGui::Render();
		window.display();
	}
	delete[] expandedTiles;
	delete[] openedTiles;
	delete[] pathTiles;
	delete[] walls;
	delete[] map;
	delete[] wallPos;
	for (__int16 i = 0; i < width; i++)
	{
		delete[] grid[i];
	}
	delete[] grid;
	ImGui::SFML::Shutdown();
	return 0;
}