Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: 2D RPG  (Read 7095 times)

0 Members and 1 Guest are viewing this topic.

Akaras

  • Newbie
  • *
  • Posts: 12
    • View Profile
2D RPG
« on: January 25, 2014, 02:59:05 pm »
I'm trying to develope a little RPG with a friend.
The first thing I did was displaying a view, creting a view and make it movable with keyboard.
I'm using this Code to move the view:
Quote
f (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
   {
      view_left -= 0.1 * elapsedTime.asMicroseconds();
      std::cout << "Left, " << view_left << std::endl;
   }

Then I use this Code to update the window:
Quote
view.reset(sf::FloatRect(view_left, view_top, view_width, view_height));

   window.setView(view);
   window.draw(sprite);

The problem is that the programm sometimes has laggs.
For example the value, which I also display in my console when changed, increases by 20-30 every time.
But sometimes it also increases by 200 and more..

Another problem is the performance.
I have six-core 4,2 Ghz CPU and if I start the programm my CPU usage increses to 50 up to 70%  :o

I only have the view and 1 image which I display and move..

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: 2D RPG
« Reply #1 on: January 25, 2014, 03:23:33 pm »
Well std::cout can be a slow operation. However from this code it is difficult to say if you are doing anything else wrong. Could you please post a complete and minimal example that we can copy and paste to test with?
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Akaras

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: 2D RPG
« Reply #2 on: January 25, 2014, 03:33:40 pm »
main.cpp
Quote
#include "game.h"

int main()
{
    Game *game = new Game();
   sf::Clock clock;

   game->LoadContent();

   // Gameloop
    while (game->window.isOpen())
    {
      sf::Time elapsed = clock.restart();

        sf::Event event;
        while (game->window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                game->window.close();

         game->Update(elapsed, event);
        }

      game->Draw(elapsed);
    }

   game->UnloadContent();

   delete(game);

    return 0;
}

game.h
Quote
//==========================================================//
// CLASS: Game                                              //
// DESC: Used to manage gameloop in different procedures    //
//==========================================================//
#ifndef __GAME_H__
#define __GAME_H__

//=================================
// included dependencies
#include <iostream>
#include <SFML/Graphics.hpp>

//=================================
// class
class Game
{
public:
   sf::RenderWindow window;      // Needed to display Window

   Game();                     // Constructor
   ~Game();                  // Destructor

   void Initialize();                           // Initialize game
   void LoadContent();                           // Loading the needed content
   void UnloadContent();                        // Unload all content
   void Update(sf::Time elapsedTime, sf::Event event);   // Check Events
   void Draw(sf::Time elapsedTime);               // Redraw screen

private:
   /* JUST TEST!! REMOVE!! */
   sf::Texture texture;
   sf::Sprite sprite;
   sf::View view;
   float view_left;
   float view_top;
   float view_width;
   float view_height;
};

#endif // __GAME_H__

game.cpp
Quote
#include "game.h"

Game::Game()
{
   Game::Initialize(); // Initialize game when class is created
}

Game::~Game()
{

}

void Game::Initialize()
{
   window.create(sf::VideoMode(800, 600), "2D RGP");

   view_left = 200;
   view_top = 200;
   view_width = 200;
   view_height = 200;
}

void Game::LoadContent()
{
   texture.loadFromFile("C:\\Users\\alexander\\Documents\\Visual Studio 2010\\Projects\\2D RPG\\Debug\\data\\rpg.jpg");
   sprite.setTexture(texture);

   view.reset(sf::FloatRect(view_left, view_top, view_width, view_height));
}

void Game::UnloadContent()
{

}

void Game::Update(sf::Time elapsedTime, sf::Event event)
{
   if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
   {
      view_left -= 0.1 * elapsedTime.asMicroseconds();
      std::cout << "Left, " << view_left << std::endl;
   }

   if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
   {
      view_left += 0.1 * elapsedTime.asMicroseconds();
      std::cout << "Right, " << view_left << std::endl;
   }

   if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
   {
      view_top -= 0.1 * elapsedTime.asMicroseconds();
      std::cout << "Up, " << view_top << std::endl;
   }

   if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
   {
      view_top += 0.1 * elapsedTime.asMicroseconds();
      std::cout << "Down, " << view_top << std::endl;
   }


   if (sf::Keyboard::isKeyPressed(sf::Keyboard::PageUp))
   {
      view_width -= 0.1 * elapsedTime.asMicroseconds();
      view_height -= 0.1 * elapsedTime.asMicroseconds();

      std::cout << "Zoom in, " << view_width << std::endl;
   }

   if (sf::Keyboard::isKeyPressed(sf::Keyboard::PageDown))
   {
      view_width += 0.1 * elapsedTime.asMicroseconds();
      view_height += 0.1 * elapsedTime.asMicroseconds();

      std::cout << "Zoom out, " << view_width << std::endl;
   }
}

void Game::Draw(sf::Time elapsedTime)
{
   window.clear();

   view.reset(sf::FloatRect(view_left, view_top, view_width, view_height));

   window.setView(view);
   window.draw(sprite);

   window.display();
}

Lignum

  • Newbie
  • *
  • Posts: 20
    • View Profile
Re: 2D RPG
« Reply #3 on: January 25, 2014, 04:23:05 pm »
Some things that might cause lag is that you're calling setView every frame, I'm not too familiar with views but I don't think you need to do that. After you've done that, try removing all std::couts by commenting them out and see if it still occurs.

As for the CPU usage, you're drawing as many frames as possible in a second. Limiting them should fix it.
Use setVerticalSyncEnabled(true), which limits the FPS to your monitor's max refresh rate (usually 60fps) or use setFramerateLimit(framerate). I suggest using 30 fps for regular games and 60 fps for fast-paced games.

Also some things I've noticed about your code are:
  • Why is your instance of Game a pointer? Just create it on the stack, it'll delete itself and it's much safer.
  • Don't use absolute paths for filenames unless you want the game for yourself only. Use a relative path.

Xornand

  • Jr. Member
  • **
  • Posts: 78
  • C++ / Python
    • View Profile
Re: 2D RPG
« Reply #4 on: January 25, 2014, 05:12:14 pm »
Some things that might cause lag is that you're calling setView every frame, I'm not too familiar with views but I don't think you need to do that.
Don't worry about that. Setting a View every frame is not the bottleneck here. In fact, that's how it should be done if the View changes on every loop iteration.

As already mentioned before, limiting the refresh rate and getting std::cout out of the loop should fix the problem.

Also, you don't need to call reset() on the View if you only want to change either its size or position. The methods setCenter() and setSize() were designed just for that. Moreover, if you're moving the View just by an offset (as it's seen in your key handling method), you can just call the move() method instead. Besides, it seems that your implementation of the "zoom" functionality relies on changing the View's dimensions. I don't know if you're aware but there already is a method called zoom() that you can call directly on the View.
« Last Edit: January 25, 2014, 05:18:06 pm by Xornand »

Akaras

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: 2D RPG
« Reply #5 on: January 25, 2014, 05:14:32 pm »
Some things that might cause lag is that you're calling setView every frame, I'm not too familiar with views but I don't think you need to do that.
I need to update the View because it may change every frame if you press a key..

Why is your instance of Game a pointer? Just create it on the stack, it'll delete itself and it's much safer.
Id didn't programm for a long time and if don't use a pointer it throws errors..

Don't use absolute paths for filenames unless you want the game for yourself only. Use a relative path.
I know. But if I don't use an absolute path in this case he is "unable to open file".
I don't know why but if I put the project in another folder it works.
But Visual Studio compiles to %Documents%\Visual Studio 2010\Projects\[Project name]
and I want my projects there.
It also works if I manually start the exe file with admin permissions.

Lignum

  • Newbie
  • *
  • Posts: 20
    • View Profile
Re: 2D RPG
« Reply #6 on: January 25, 2014, 05:35:11 pm »
Id didn't programm for a long time and if don't use a pointer it throws errors..
That's very strange. Are you sure you're doing this?:

Game game;

because this won't work:

Game game = new Game;

I know. But if I don't use an absolute path in this case he is "unable to open file".
I don't know why but if I put the project in another folder it works.
But Visual Studio compiles to %Documents%\Visual Studio 2010\Projects\[Project name]
and I want my projects there.
It also works if I manually start the exe file with admin permissions.

You need to put your files in %Documents%\Visual Studio 2010\Projects\[Project name]\[Project name] to use relative paths in Visual Studio (you can also set the working directory in your project settings under Debugging->Working Directory, but this is the default one). While for the standalone .exe the files just need to be in the same place as the .exe.

--

Don't worry about that. Setting a View every frame is not the bottleneck here. In fact, that's how it should be done if the View changes on every loop iteration.

Ah okay, thanks for clearing that up!


Akaras

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: 2D RPG
« Reply #7 on: January 25, 2014, 05:42:34 pm »
I've now set VSync(true) and removed the couts.
Now I have a constant framerate and it works without laggs.

I still have another question:
I want to build my RPG out of many rectangles and I will save them in a 2D Array.
How should I structure the data in the file? And which file format would you recommend me to use?

Another problem is that I want to expand and update the Map sometimes.
So if I save the users last position, how can I place his character on the same position after the map update?

The best solution would be to just use tilemaps of maybe 255x255 rectangles and a 4D Array.
The first two dimension would specify the position of the tilemap and the second two the content of the tilemap.

Also each rectangle should be filled with a sprite for the surface.
So should I just use an Array of Sprites and use a switch case to load the textures into each rectangle(sprite)?

There also must be a value for each rectangle whether clipping is enables for it or not.
I also need to save the height because I have at least 2 terrain levels.
The ground and objects that shoud be drawn over it, like houses, trees etc.

Has anyone a better idea how to do this?

Akaras

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: 2D RPG
« Reply #8 on: January 25, 2014, 05:48:26 pm »
That's very strange. Are you sure you're doing this?:
Didn't work(German translation):
Quote
InelliSense: No "="-Operator is matching this operand.

You need to put your files in %Documents%\Visual Studio 2010\Projects\[Project name]\[Project name] to use relative paths in Visual Studio (you can also set the working directory in your project settings under Debugging->Working Directory, but this is the default one).

I changed it to the follwing and it works :D
Quote
texture.loadFromFile("data\\rpg.jpg");

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: 2D RPG
« Reply #9 on: January 25, 2014, 05:59:16 pm »
IntelliSense is not a reliable source for the syntactical correctness of your code. It's just a tool to assist you, but you should really compile the code to get more certainity. Even then you can't be 100% sure, in case of doubt you have to lookup the C++ standard.

By the way, use forward slashes, they are portable.
texture.loadFromFile("data/rpg.jpg");

And here
Game *game = new Game();
it's not necessary to use dynamic memory,
Game game;
would work as well. See also the article I recently wrote about why you should avoid new and delete.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Akaras

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: 2D RPG
« Reply #10 on: January 25, 2014, 06:07:20 pm »
I've removed the pointer..
After these changes the programm still need constantly 33% of my CPU?!
And sometimes, instead of making big jumps like before, it still scrolls faster?!

Lignum

  • Newbie
  • *
  • Posts: 20
    • View Profile
Re: 2D RPG
« Reply #11 on: January 25, 2014, 06:22:05 pm »
I've now set VSync(true) and removed the couts.
Now I have a constant framerate and it works without laggs.

I still have another question:
I want to build my RPG out of many rectangles and I will save them in a 2D Array.
How should I structure the data in the file? And which file format would you recommend me to use?

...

Good to hear that it works! :)

Assuming you're going to have pre-built maps you should have a look at the Tiled map editor. It uses XML as a format.

If you're going to have generated maps though and you want to save them to a file... you would probably still be best off using XML. Although it's not going to be much use to you for just tiles, you're going to love it later on when you're saving enemies, sprites etc.

Another problem is that I want to expand and update the Map sometimes.
So if I save the users last position, how can I place his character on the same position after the map update?

I don't quite understand what you mean. Do you mean that you're going to update the map at runtime? (e.g. secret passageway opens up by removing a tile). Or do you mean you're going to update the map via a map editor?

For both cases you shouldn't need to worry. However do keep in mind that moving objects shouldn't be tiles.
You're going to have some trouble with transparency and many other things otherwise.

The best solution would be to just use tilemaps of maybe 255x255 rectangles and a 4D Array.
The first two dimension would specify the position of the tilemap and the second two the content of the tilemap.

A 4D array? You should only need 2 dimensions. If you wanted to you could even make a 1D array.

Here's an example for a 1D array which uses numbers to represent different types of tiles:

const int map[16] =
{
     2, 2, 2, 2,
     2, 1, 1, 2,
     2, 2, 1, 2,
     2, 2, 2, 2
};

To get a tile you would do this:map[x * mapWidth + y];
An example for this case would be: map[3 * 4 + 2]; (coordinates start at 0)
which would return '2' because the tile at [3, 2] has the ID 2.

Also each rectangle should be filled with a sprite for the surface.
So should I just use an Array of Sprites and use a switch case to load the textures into each rectangle(sprite)?

Kind of. Use an std::vector<sf::Texture>.
Here's an example:
std::vector<sf::Texture> textureMap;
textureMap.push_back(...); // Texture for Tile ID 1
textureMap.push_back(...); // Texture for Tile ID 2
// and so on...

Here's an example for drawing with the above setup:
sf::Sprite tileSprite; // This should preferrably be a class member.

for (unsigned int x = 0; x < mapWidth; ++x)
{
     for (unsigned int y = 0, y < mapHeight; ++y)
     {
           int id = map[x * mapWidth + y]; // Get the ID at [x, y] from the map.
           tileSprite.setTexture(textureMap[id - 1]); // - 1 since id #1 is #0 in the vector.
           window.draw(tileSprite); // Draw it.
     }
}

There also must be a value for each rectangle whether clipping is enables for it or not.
I also need to save the height because I have at least 2 terrain levels.
The ground and objects that shoud be drawn over it, like houses, trees etc.

You could use a seperate array just for the collision map. But that's pretty inefficient, I advise against it.
So instead what you should do is make a vector like above that stores bools rather than textures.
For the layers, you would add another dimension to the array.

I've removed the pointer..
After these changes the programm still need constantly 33% of my CPU?!
And sometimes, instead of making big jumps like before, it still scrolls faster?!

Have you tried a release build? From my experience a debug build with a framelimit of 60fps will take up to 10-40% CPU. While a release build produces a mere 03-10%.
« Last Edit: January 25, 2014, 06:26:06 pm by Lignum »

Raincode

  • Full Member
  • ***
  • Posts: 118
    • View Profile
Re: 2D RPG
« Reply #12 on: January 25, 2014, 06:46:50 pm »
use '\n' instead of std::endl, unless you are really sure you need std::endl, e.g. for flushing

Kind Regards

Akaras

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: 2D RPG
« Reply #13 on: January 25, 2014, 11:30:30 pm »
I wanted to expand my programm to implement your code, but an error appeared..

Error(translation):
Quote
1>------ Constructing started: Project: 2D RPG, Configuration: Debug Win32 ------
1>The building process was started 25.01.2014 23:07:11.
1>InitializeBuildStatus:
1>  Updating the timestamp of "Debug\2D RPG.unsuccessfulbuild".
1>ClCompile:
1>  menu.cpp
1>c:\sfml\include\sfml\window\window.hpp(477): error C2248: "sf::NonCopyable::operator =": No access to private members, which declaration is done in sf::NonCopyable-Class.
1>          c:\sfml\include\sfml\system\noncopyable.hpp(79): See declaration of 'sf::NonCopyable::operator ='
1>          c:\sfml\include\sfml\system\noncopyable.hpp(42): See declaration of 'sf::NonCopyable'
1>          This diagnostic occurred in the compiler generated function "sf::Window &sf::Window::operator =(const sf::Window &)".
1>c:\sfml\include\sfml\graphics\rendertarget.hpp(419): error C2248: "sf::NonCopyable::operator =": No access to private members, which declaration is done in sf::NonCopyable-Class.
1>          c:\sfml\include\sfml\system\noncopyable.hpp(79): See declaration of 'sf::NonCopyable::operator ='
1>          c:\sfml\include\sfml\system\noncopyable.hpp(42): See declaration of 'sf::NonCopyable'
1>          This diagnostic occurred in the compiler generated function "sf::RenderTarget &sf::RenderTarget::operator =(const sf::RenderTarget &)".
1>  gui.cpp
1>c:\sfml\include\sfml\window\window.hpp(477): error C2248: "sf::NonCopyable::operator =": No access to private members, which declaration is done in sf::NonCopyable-Class.
1>          c:\sfml\include\sfml\system\noncopyable.hpp(79): See declaration of 'sf::NonCopyable::operator ='
1>          c:\sfml\include\sfml\system\noncopyable.hpp(42): See declaration of 'sf::NonCopyable'
1>          This diagnostic occurred in the compiler generated function "sf::Window &sf::Window::operator =(const sf::Window &)".
1>c:\sfml\include\sfml\graphics\rendertarget.hpp(419): error C2248: "sf::NonCopyable::operator =": No access to private members, which declaration is done in sf::NonCopyable-Class.
1>          c:\sfml\include\sfml\system\noncopyable.hpp(79): See declaration of 'sf::NonCopyable::operator ='
1>          c:\sfml\include\sfml\system\noncopyable.hpp(42): See declaration of 'sf::NonCopyable'
1>          This diagnostic occurred in the compiler generated function "sf::RenderTarget &sf::RenderTarget::operator =(const sf::RenderTarget &)".
1>  button.cpp
1>  Code is generated...
1>
1>Failed to create
1>
1>Elapsed time 00:00:01.93
========== Create: 0 successful, Skipped error at 1, 0 current, 0 skipped ==========

gui.h
//==========================================================//
// CLASS: GUI                                               //
// DESC: Manages GUI                                        //
//==========================================================//
#ifndef __GUI_H__
#define __GUI_H__

//=================================
// included dependencies
#include "menu.h"
#include <SFML/Graphics.hpp>

//=================================
// class
class GUI
{
public:
        GUI();                                                  // Constructor
        ~GUI();                                                 // Destructor

        sf::RenderWindow window;                // Needed to display graphics

        enum menus { main, game, options, credits };            // Enum of menus

        void Initialize(sf::RenderWindow _window);                      // Initialize
        void LoadContent();                                                                     // Loading the needed content
        void UnloadContent();                                                           // Unload all content
        void Update(sf::Time elapsedTime, sf::Event event);     // Check Events
        void Draw(sf::Time elapsedTime);                                        // Redraw screen
};

#endif // __GUI_H__
 

gui.cpp
#include "gui.h"

GUI::GUI()
{
       
}

GUI::~GUI()
{

}

void GUI::Initialize(sf::RenderWindow _window)
{
        window = _window;
}

void GUI::LoadContent()
{
       
}

void GUI::UnloadContent()
{

}

void GUI::Update(sf::Time elapsedTime, sf::Event event)
{
       
}

void GUI::Draw(sf::Time elapsedTime)
{
        window.clear();



        window.display();
}
 

menu.h
//==========================================================//
// CLASS: MENU                                              //
// DESC: Menu prototype                                     //
//==========================================================//
#ifndef __MENU_H__
#define __MENU_H__

//=================================
// included dependencies
#include <SFML/Graphics.hpp>

//=================================
// class
class Menu
{
public:
        Menu();                                                 // Constructor
        ~Menu();                                                // Destructor

        sf::RenderWindow window;                // Needed to display graphics

        void Initialize(sf::RenderWindow _window);                      // Initialize
        void LoadContent();                                                                     // Loading the needed content
        void UnloadContent();                                                           // Unload all content
        void Update(sf::Time elapsedTime, sf::Event event);     // Check Events
        void Draw(sf::Time elapsedTime);                                        // Redraw screen
};

#endif // __MENU_H__
 

menu.cpp
#include "menu.h"

Menu::Menu()
{
       
}

Menu::~Menu()
{

}

void Menu::Initialize(sf::RenderWindow _window)
{
        window = _window;
}

void Menu::LoadContent()
{
       
}

void Menu::UnloadContent()
{

}

void Menu::Update(sf::Time elapsedTime, sf::Event event)
{
       
}

void Menu::Draw(sf::Time elapsedTime)
{
       
}
 

element.h
//==========================================================//
// CLASS: ELEMENT                                           //
// DESC: Base class for all UI Elements (e.g. Button)       //
//==========================================================//
#ifndef __ELEMENT_H__
#define __ELEMENT_H__

//=================================
// included dependencies
#include <SFML/Graphics.hpp>

//=================================
// class
class Element
{
public:
        sf::RenderWindow window;                // Needed to display graphics

        virtual void Initialize(sf::RenderWindow _window);                                                                      // Initialize
        virtual void LoadContent();                                                                     // Loading the needed content
        virtual void UnloadContent();                                                           // Unload all content
        virtual void Update(sf::Time elapsedTime, sf::Event event);     // Check Events
        virtual void Draw(sf::Time elapsedTime);                                        // Redraw screen
};

#endif // __ELEMENT_H__
 

button.h
//==========================================================//
// CLASS: GUI                                               //
// DESC: Manages GUI                                        //
//==========================================================//
#ifndef __BUTTON_H__
#define __BUTTON_H__

//=================================
// included dependencies
#include "element.h"

//=================================
// class
class Button : public Element
{
public:
        Button();                                                       // Constructor
        ~Button();                                                      // Destructor

        void Initialize();                                                                      // Initialize
        void LoadContent();                                                                     // Loading the needed content
        void UnloadContent();                                                           // Unload all content
        void Update(sf::Time elapsedTime, sf::Event event);     // Check Events
        void Draw(sf::Time elapsedTime);                                        // Redraw screen

private:
       
};

#endif // __BUTTON_H__
 

button.cpp
#include "button.h"

Button::Button()
{
       
}

Button::~Button()
{

}

void Button::Initialize()
{
       
}

void Button::LoadContent()
{
       
}

void Button::UnloadContent()
{

}

void Button::Update(sf::Time elapsedTime, sf::Event event)
{
       
}

void Button::Draw(sf::Time elapsedTime)
{
       
}
 

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: 2D RPG
« Reply #14 on: January 25, 2014, 11:52:09 pm »
Maybe you should learn C++ before trying to use SFML.... Anyways atleast try to read the error. It says exactly what is wrong. You cannot copy sf::Window (use a reference instead) ;)
« Last Edit: January 26, 2014, 12:00:50 am by zsbzsb »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

 

anything