Hi all, I recently decided I want to learn sfml, since I heard some good things about it. I haven't used c++ before, but I know C and C# relatively okay.
I decided I want to learn how to make a game so I figured first thing first; make an engine, and make a map, then add on top of it.
So this project is hence kind of like that. It will eventually become an in game level maker, using the game engine to render everything, etc.
Here's a video of how it's coming along:
The minimap down the bottom right is going the be the box that holds the tileset, I just made it a minimap to test it was working functionally. I'm going to read in one big image; this image will be then split up in to many smaller images within the code. I'm not sure how to do that. Does anyone have any idea?
I absolutely know it sucks... I only just started the other day and I'm probably 5 or 10% finished.
I was hoping someone could give me some feedback on my code, etc, since I'm not very fluent in sfml, quite yet. One thing I've noticed is that the program uses 10% CPU, which I guess is okay; however, it uses
300 MB Ram!. I don't see how it can use that much memory... It's really high usage for what I'm doing. Does anyone know why my code is causing so much ram to be used?
Anyway, here's the code: If you notice anything you think I'm doing badly/inefficiently/should be doing different, can you please tell me
#include <SFML/Window.hpp>
#include <SFGUI/SFGUI.hpp>
#include <SFML/Graphics.hpp>
#include <cmath>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "Windows.h"
using namespace std;
const int tileSize = 40;
#define SIZE 1000
typedef struct {
sf::Sprite sprite;
bool changed;
} grid;
bool SpriteDown(sf::Sprite &sprite, sf::RenderWindow &window, int buttonNum, sf::Event &evt)
{
if (evt.type == sf::Event::MouseButtonReleased)
{
#pragma region Left Click
if (buttonNum == 0)
{
if (evt.mouseButton.button == sf::Mouse::Left)
{
sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
sf::FloatRect bounds = sprite.getGlobalBounds();
if (bounds.contains(mouse))
return true;
}
return false;
}
#pragma endregion
#pragma region Right Click
else if (buttonNum == 1)
{
{
if (evt.mouseButton.button == sf::Mouse::Right)
{
sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
sf::FloatRect bounds = sprite.getGlobalBounds();
if (bounds.contains(mouse))
{
return true;
}
}
}
}
#pragma endregion
}
return false;
}
bool SpriteClicked(sf::Sprite &sprite, sf::RenderWindow &window, int buttonNum)
{
#pragma region Left Click
if (buttonNum == 0)
{
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
// transform the mouse position from window coordinates to world coordinates
sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
// retrieve the bounding box of the sprite
sf::FloatRect bounds = sprite.getGlobalBounds();
// hit test
if (bounds.contains(mouse))
return true;
}
return false;
}
#pragma endregion
#pragma region Right Click
else if (buttonNum == 1)
{
{
if(sf::Mouse::isButtonPressed(sf::Mouse::Right))
{
// transform the mouse position from window coordinates to world coordinates
sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
// retrieve the bounding box of the sprite
sf::FloatRect bounds = sprite.getGlobalBounds();
// hit test
if (bounds.contains(mouse))
{
return true;
}
return false;
}
}
}
return false;
#pragma endregion
}
void InitButtons(sf::Sprite & okBtn, sf::Sprite &zoomBtn, sf::Sprite &unzoomBtn, sf::Sprite &refreshBtn, sf::Texture & texture, sf::Texture &zoomTex, sf::Texture &unZoomTex, sf::Texture &refreshTex)
{
//load textures
texture.loadFromFile("C:\\Users\\Kevin Mallinson\\Documents\\Visual Studio 2012\\Projects\\MapMaker\\MapMaker\\btn.png");
zoomTex.loadFromFile("C:\\Users\\Kevin Mallinson\\Documents\\Visual Studio 2012\\Projects\\MapMaker\\MapMaker\\zoom.png");
unZoomTex.loadFromFile("C:\\Users\\Kevin Mallinson\\Documents\\Visual Studio 2012\\Projects\\MapMaker\\MapMaker\\unzoom.png");
refreshTex.loadFromFile("C:\\Users\\Kevin Mallinson\\Documents\\Visual Studio 2012\\Projects\\MapMaker\\MapMaker\\refresh.png");
//ok button
okBtn.setTexture(texture);
okBtn.setScale(sf::Vector2f(0.2f, 0.2f)); // absolute scale factor
okBtn.setPosition(sf::Vector2f(1450, 815));
//zoom button
zoomBtn.setTexture(zoomTex);
zoomBtn.setPosition(sf::Vector2f(1550, 15));
//unzoom button
unzoomBtn.setTexture(unZoomTex);
unzoomBtn.setPosition(sf::Vector2f(1450, 15));
//refresh button
//refreshBtn.setTexture(refreshTex);
//refreshBtn.setPosition(sf::Vector2f(1450, 515));
}
void MoveView(sf::View &view, sf::RenderWindow &window, sf::FloatRect &screenRect)
{
int a = view.getCenter().y + view.getSize().y / 2;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
if (SIZE * tileSize > view.getCenter().x + view.getSize().x / 2)
view.move(5, 0);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
if ((view.getCenter().x - view.getSize().x/ 2) - 40 > 0) //since im rendering an extra tile, minus 40 to take that in to consideration
view.move(-5, 0);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
if (SIZE * tileSize > view.getCenter().y + view.getSize().y / 2)
view.move(0, 5);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
if ((view.getCenter().y - view.getSize().y / 2) - 40 > 0)
view.move(0, -5);
}
void RenderMap(int & startX, int & startY, int & endX, int & endY, grid gridArray[][SIZE], sf::RenderWindow & window, sf::View & view, sf::Event & event, sf::Vector2f & worldPos)
{
for (int i = startX; i < endX; i++)
{
for (int j = startY; j < endY; j++)
{
window.draw(gridArray[i][j].sprite);
if (worldPos.x < view.getCenter().x + view.getSize().x / 2
&& worldPos.x > view.getCenter().x - view.getSize().x/ 2
&& worldPos.y > view.getCenter().y - view.getSize().y / 2
&& worldPos.y < view.getCenter().y + view.getSize().y / 2)
{
if (SpriteClicked(gridArray[i][j].sprite, window, 0) && gridArray[i][j].changed == false)
{
gridArray[i][j].sprite.setColor(sf::Color(0, 255, 0));
gridArray[i][j].changed = true;
}
else if (SpriteDown(gridArray[i][j].sprite, window, 1, event) && gridArray[i][j].changed == true)
{
gridArray[i][j].sprite.setColor(sf::Color(255, 255, 255));
gridArray[i][j].changed = false;
}
}
}
}
}
void FindIndexCollider(int & startX, int & startY, int & endX, int & endY, sf::FloatRect & screenRect)
{
startX = floor(screenRect.left / tileSize - 1);
startY = floor(screenRect.top / tileSize - 1);
//bounds checking
if (startX < 0)
startX = 0;
if (startY < 0)
startY = 0;
if (startX > SIZE)
startX = SIZE;
if (startY > SIZE)
startY = SIZE;
//end variables
endX = startX + 50;
endY = startY + 50;
//bounds checking
if (endX < 0)
endX = 0;
if (endY < 0)
endY = 0;
if (endX > SIZE)
endX = SIZE;
if (endY > SIZE)
endY = SIZE;
}
int main()
{
#pragma region Variable Declarations
//Variable Declarations
int startX = 0, endX = 0, startY = 0, endY = 0;
static float FPS;
static float nextSecond;
static float prevSecond;
auto gridArray = new grid[SIZE][SIZE]();
sf::Text atext;
sf::Font MyFont;
sf::Clock clock;
sf::Texture texture, gridTex, zoomTex, unZoomTex, refreshTex;
sf::Sprite okBtn, zoomBtn, unzoomBtn, refreshBtn;
sf::Vector2f worldPos;
gridTex.loadFromFile("grid.png");
InitButtons(okBtn, zoomBtn, unzoomBtn, refreshBtn, texture, zoomTex, unZoomTex, refreshTex);
#pragma endregion
#pragma region Initialize the grid array
//I start at 1 simply so i can use these variables in my arithmatic, as something * 0 is 0
for (int i = 1; i <= SIZE; i++)
{
for (int j = 1; j <= SIZE; j++)
{
gridArray[i-1][j-1].sprite.setTexture(gridTex);
gridArray[i-1][j-1].sprite.setPosition(sf::Vector2f(i*tileSize, j*tileSize));
gridArray[i-1][j-1].changed = false;
}
}
#pragma endregion
#pragma region Window initialization
//Initiate the SFML window
sf::RenderWindow window(sf::VideoMode(1600, 900), "Level Editor", sf::Style::Titlebar | sf::Style::Close );
sf::Vector2i pixelPos = sf::Mouse::getPosition(window);
window.setFramerateLimit(60);
window.setVerticalSyncEnabled(true);
//Create the views
sf::View gridView(sf::Vector2f(1400, 440), sf::Vector2f(1160, 880));
gridView.setViewport(sf::FloatRect(0.027f, 0.047f, 0.7f, 0.91f));
sf::View tileSetView(sf::Vector2f(1400, 440), sf::Vector2f(1160, 880));
tileSetView.setViewport(sf::FloatRect(0.74f, 0.404f, 0.25f, 0.55f));
sf::View defaultView(sf::Vector2f(1600, 900), sf::Vector2f(800, 450));
//loop to reset the views position at top left. figure out an programmatic way to do this with an algorithm
gridView.move(0, 100);
while ((gridView.getCenter().x - gridView.getSize().x/ 2) - 40 > 0)
gridView.move(-5, 0);
while ((gridView.getCenter().y - gridView.getSize().y / 2) - 40 > 0)
gridView.move(0, -5);
sf::Vector2f defaultSize = gridView.getSize();
#pragma endregion
#pragma region Container Stuff
//Create the containers for the GUI
sfg::SFGUI sfgui;
sfg::Window::Ptr window2, window3;
window2 = sfg::Window::Create();
window3 = sfg::Window::Create();
//Set style, position and size for the virtual windows
window2->SetStyle(sfg::Window::Style::BACKGROUND && sfg::Window::Style::NO_STYLE );
window2->SetRequisition(sf::Vector2f(1144,50));
window2->SetPosition(sf::Vector2f(31,850.5));
window3->SetStyle(sfg::Window::Style::BACKGROUND && sfg::Window::Style::NO_STYLE );
window3->SetRequisition(sf::Vector2f(50, 871));
window3->SetPosition(sf::Vector2f(2.5f, 30));
//Create two boxes to hold each scroll bar
sfg::Box::Ptr box, box2;
box = sfg::Box::Create( sfg::Box::VERTICAL );
box2 = sfg::Box::Create( sfg::Box::VERTICAL );
//Horizontal and vertical scroll bars for the main grid
sfg::Scrollbar::Ptr scrollX = sfg::Scrollbar::Create(sfg::Scrollbar::HORIZONTAL);
sfg::Scrollbar::Ptr scrollY = sfg::Scrollbar::Create(sfg::Scrollbar::VERTICAL);
box->Pack(scrollX);
box2->Pack(scrollY);
box->SetSpacing( 5.f );
box2->SetSpacing( 5.f );
window2->Add( box );
window3->Add( box2 );
#pragma endregion
#pragma region Main Loop
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
window2->HandleEvent( event );
window3->HandleEvent( event );
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
//Clear the screen
window.clear(sf::Color::White);
//Move the main View when pressing arrow keys
sf::FloatRect screenRect(sf::Vector2f(gridView.getCenter().x - (gridView.getSize().x)/2, gridView.getCenter().y - (gridView.getSize().y)/2) , gridView.getSize());
sf::FloatRect screenRect2(sf::Vector2f(tileSetView.getCenter().x - (tileSetView.getSize().x)/2, tileSetView.getCenter().y - (tileSetView.getSize().y)/2) , tileSetView.getSize());
MoveView(gridView, window, screenRect);
//Render the main grid
window.setView(gridView);
pixelPos = sf::Mouse::getPosition(window);
FindIndexCollider(startX, startY, endX, endY, screenRect);
RenderMap(startX, startY, endX, endY, gridArray, window, gridView, event, window.mapPixelToCoords(pixelPos));
//Render the tileset grid
window.setView(tileSetView);
pixelPos = sf::Mouse::getPosition(window);
FindIndexCollider(startX, startY, endX, endY, screenRect2);
RenderMap(startX, startY, endX, endY, gridArray, window, tileSetView, event, window.mapPixelToCoords(pixelPos));
//NOTE: SFGUI IS BUGGY; you must render at least ONE thing AFTER setting the new view,
//in order for SFGUI to KNOW that you set the view, otherwise it will use the old view.
window.setView(window.getDefaultView());
//Draw buttons from sprites
window.draw(zoomBtn);
window.draw(unzoomBtn);
//Button clicked events
if (SpriteClicked(unzoomBtn, window, 0))
if (defaultSize.x >= gridView.getSize().x)
gridView.zoom(1.02f);
if (SpriteClicked(zoomBtn, window, 0))
gridView.zoom(0.98f);
//Finally, draw everything.
window2->Update(60);
window3->Update (60);
sfgui.Display( window );
window.display();
}
#pragma endregion
}