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

Author Topic: State Machine and Engine problem  (Read 8659 times)

0 Members and 1 Guest are viewing this topic.

The Terminator

  • Full Member
  • ***
  • Posts: 224
  • Windows and Mac C++ Developer
    • View Profile
State Machine and Engine problem
« on: August 03, 2012, 11:30:06 pm »
I'm having some issues with calling a function through an object pointer in my game state class:

    class GameState {
    public:
        virtual void init(Engine*) = 0;
        virtual void cleanUp() = 0;
       
        virtual void pause(Engine*) = 0;
        virtual void resume(Engine*) = 0;
       
        virtual void handleEvents(Engine*) = 0;
        virtual void update(Engine*) = 0;
        virtual void draw(Engine*) = 0;
       
        void changeEvent(Engine* game, GameState* state) {
           
        }
    };

Every single line gives me errors, because of the Engine pointers I'm trying to make. (and yes I have included the Engine.h file) But, when in my Engine.h file when I use the GameState pointers, they work fine:

    class Engine {
    private:
        sf::RenderWindow window;
        sf::Event event;
       
        std::vector<GameState*> states;
       
    public:
        void init();
        void start();
        void cleanUp();
       
        void changeState(GameState*);
        void pushState(GameState*);
        void popState();
       
        void handleEvents();
        void update();
        void draw();
    };

I think it's some sort of initialization problem, once class getting defined before the first, but I don't know how to fix it. Any help is appreciated, thank you for your time.
Current Projects:
Technoport

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: State Machine and Engine problem
« Reply #1 on: August 04, 2012, 12:59:29 am »
This looks suspiciously like the code from Game Dev Geek... ;)
I advice against the use of the code, because it's not proper C++ and has also a few down sides (singletone states, breaking the handel events-update-draw circle, miss using vector as a stack ...).
Instead you're free to use my rewrite of the engine (SmallGameEngine). I've changed things quite a bit so you might get a bit confused. Unfortunatly I haven't had time to write a tutorial on it, but feel free to ask me anything. I'll probably change a few other things in the near futur, since a few parts are still not very practical. ;)
« Last Edit: August 04, 2012, 01:02:17 am by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

The Terminator

  • Full Member
  • ***
  • Posts: 224
  • Windows and Mac C++ Developer
    • View Profile
Re: State Machine and Engine problem
« Reply #2 on: August 04, 2012, 02:28:55 pm »
Yeah I was taking some concepts from Game Dev Geek, but the code was really weird and didn't make much sense in some places. I really like how you manage game states, I will probably take the concept of yours and modify it to how I like. Thanks a lot!
Current Projects:
Technoport

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: State Machine and Engine problem
« Reply #3 on: August 04, 2012, 02:38:42 pm »
I really like how you manage game states, I will probably take the concept of yours and modify it to how I like.
Thanks!
Feel free to do so! :)
If you'll get to a finished product, I could also mention it in the readme if you want me to. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

mateandmetal

  • Full Member
  • ***
  • Posts: 171
  • The bird is the word
    • View Profile
    • my blog
Re: State Machine and Engine problem
« Reply #4 on: August 06, 2012, 04:44:42 am »
it's not proper C++ and has also a few down sides (singletone states, ...

what´s wrong with singletons?


miss using vector as a stack ...

misusing?  ???

Quote
In order to allow states to exist on top of one another, we will need a “stack of states”. I will use an STL vector to implement this stack. In addition we will need methods to change states, as well as push and pop states on the stack.


by using std::vector he can push a state on top of other... imagine a "mini menu" that appears when you press Escape on the Play state... then he can easily pop the last state and back to the prior .. so he has 1 paused state in the background and another one active on top...

can you do that with std::stack?
- Mate (beverage) addict
- Heavy metal addict _lml
- SFML 2 addict
- My first (and free) game: BichingISH!

lrx

  • Newbie
  • *
  • Posts: 29
    • View Profile
Re: State Machine and Engine problem
« Reply #5 on: August 06, 2012, 06:44:22 am »
by using std::vector he can push a state on top of other... imagine a "mini menu" that appears when you press Escape on the Play state... then he can easily pop the last state and back to the prior .. so he has 1 paused state in the background and another one active on top...

can you do that with std::stack?

Stack by definition is data structure following principle "first in last out" meaning that you can only add and remove things only from one, the same end. It's exactly the same as your real life stack of books, you can't pick book on bottom, without destroying stack, unless you remove all books from top first. I am not sure if that's how std::stack works since I've never used it myself, but I don't think they would name "stack" something that works differently then stack generally known in computer science :)

Correct me if I'm wrong
« Last Edit: August 06, 2012, 06:46:07 am by lrx »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: State Machine and Engine problem
« Reply #6 on: August 06, 2012, 11:05:03 am »
what´s wrong with singletons?
There are scenarios where singletones hace their proper place (although you can always design your engine diffrently and not use them), but the states are defenetly not the right place for that. If you look at the code from dev geek you'll notice that all the state classes will be initialized in the beginning although they maybe will never be used. Next you'll have to manually call init() and cleanup() which is against RAII and can very well lead to inconsistant class object, which is very bad and shows the poor design. For example if you push twice the same state on the stack cleanup() would've not be called for the first state while for the second state already init() is being call. If you'd use some new and delete in the state you'll automatically create memory leaks (allocating the state members twice without releasing them twice).

Quote
by using std::vector he can push a state on top of other... imagine a "mini menu" that appears when you press Escape on the Play state... then he can easily pop the last state and back to the prior .. so he has 1 paused state in the background and another one active on top...

can you do that with std::stack?
Yes that's exactly what the main task of a stack is.
Sure avector could theoretically allow you to sneak a state behind another one, but he doesn't do that in the tutorial and doesn't leave space so you could do that. He only calls push_back and pop_back, which are the fujctions a stack has. You can go and replace the vector with a stack in his code and everything will work fine.
So missusing is quite right. When there's a comtainer for a specific task and one uses a more generic one the this is wrong. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

mateandmetal

  • Full Member
  • ***
  • Posts: 171
  • The bird is the word
    • View Profile
    • my blog
Re: State Machine and Engine problem
« Reply #7 on: August 07, 2012, 07:26:54 am »
Stack by definition is data structure following principle "first in last out"

I know a stack is a LIFO structure.

For example if you push twice the same state on the stack cleanup() would've not be called for the first state while for the second state already init() is being call

Can be easily fixed. If state to change == actual state, do nothing

If you'd use some new and delete in the state you'll automatically create memory leaks (allocating the state members twice without releasing them twice).

If you are careful with your pointers, you don´t have any memory leaks problem

he doesn't do that in the tutorial and doesn't leave space so you could do that

One doesn´t need to follow a tutorial strictly. The purpose of a tutorial is to illustrate something, IMO. The author is declaring this functions:

  void ChangeState(CGameState* state);
  void PushState(CGameState* state);
  void PopState();
 

That´s why he is using std::vector. If you only use the first one, of course you can use std::stack instead.
- Mate (beverage) addict
- Heavy metal addict _lml
- SFML 2 addict
- My first (and free) game: BichingISH!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: State Machine and Engine problem
« Reply #8 on: August 07, 2012, 04:16:36 pm »
Note that we're discussing code design questions, so it's not really about being right or wrong, but it's about what's recommended from experienced programmers and what has more pro than contra arguments. ;)

I know a stack is a LIFO structure.

The author is declaring this functions:

  void ChangeState(CGameState* state);
  void PushState(CGameState* state);
  void PopState();
 

That´s why he is using std::vector. If you only use the first one, of course you can use std::stack instead.
Could you then please enlight me where the vector does not get used in a LIFO manner?
The ChangeState function calls pop_back and push_back on the vector, where as the PushState calls push_back and the PopState calls pop_back. So all the operations happen on the last element of the vector and thus everything works with the LIFO principle.
Also keep in mind that the other of the tutorial stated himself, that he'll use the vector as a stack, so his idea and intend was to use the vector as a stack (LIFO) and not as something else. IMO he just didn't know the std::stack structur and thus didn't use it.

One doesn´t need to follow a tutorial strictly. The purpose of a tutorial is to illustrate something, IMO.
This counts for all tutorials, they are just there to help you understand a principle. But if you're intend is to use a stack, then don't use something else. Just providing a more generic structure, because maybe someone will want to use that isn't good and for beginners this can be quite confusing.
Not to forget that a stack is layed out for pushing and poping where as the vector isn't as efficent (as regarding memory) on such a task; of course it doesn't matter for this case, but it should just show that the decision of the right structur is very important and that one should not abuse other structurs for a diffrent task, if there's an existing one.

For example if you push twice the same state on the stack cleanup() would've not be called for the first state while for the second state already init() is being call
Can be easily fixed. If state to change == actual state, do nothing
If you mean by 'actual' 'current', then no you can't do that, because the state doesn't have to be the current state, but it could be paused deeper down in the stack. Of course you then could add a member to each state that tells if it's active or not, but this is then just a very bad design.

If you are careful with your pointers, you don´t have any memory leaks problem
This is actually just an excuse and a bad one too. ;)
Memory management should, in most cases, be banned and one should make use of RAII with e.g. std::share_ptr. Of course you don't have to take my word for that, but I think you could take Bjarne Stroustrups' or Herb Sutter's or any other's developer that likes to concentrate on safe code and good code design.
Additionally you can take care of your pointers as much as you want, but you'll never get the guarantee RAII gives you, since there are numerous ways to skip the cleanup code. For example a break statement, a return statement or a unexpected/unhandled exception, can easily jump over your cleanup code, where as objects with RAII get cleaned up as soon as it gets out of scope.

As an example take the render window, if you had to manually clean up the window the following code (as seen in many examples, but not very recommended for real applications) could create memory leaks:
#include <SFML/Graphics.hpp>
int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "Leaky");
    // window.init();
    sf::Texture tex;
    if(!tex.loadFromFile("test.png"))
        return -1;

    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type = sf::Event::Closed)
                window.close()
        }
        window.clear();
        window.display();
    }
    // window.cleanup();
}
I've commented two possible function calls you could have for manual memory management. As you see if the texture couldn't be loaded the application would automatically close (return -1;) without calling window.cleanup() which will create memory leaks. Of course you then wouldn't use return -1 but one of the common design guidlines is to design your code so that it's very hard for the user to do things wrong and manual memory management certaintly doesn't follow this rule. ;)
This is also why SFML is so awesome and other libraries like SDL, Allegro, etc. have some bad design issues. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

mateandmetal

  • Full Member
  • ***
  • Posts: 171
  • The bird is the word
    • View Profile
    • my blog
Re: State Machine and Engine problem
« Reply #9 on: August 09, 2012, 02:14:05 am »
from http://www.cplusplus.com

Quote
By default, if no container class is specified for a particular stack class, the standard container class template deque is used.

Quote
deque (usually pronounced like "deck") is an irregular acronym of double-ended queue. Double-ended queues are a kind of sequence container. As such, their elements are ordered following a strict linear sequence.

Maybe one doesn´t need the linear sequence order (and usually doesn´t). Plus, the elements of a std::vector are guaranteed to be contiguous. And yes, he is using push_back, but previously he is pausing the current state (in the PushState function), not calling state->clear(). Also you may want to loop through the contents of the "stack" and std::stack doesn't allow that.

Ok, shared pointers are nice, but what if one can´t/doesn´t want to use C++11/boost?
Use auto_ptr, yes, but it is also risky... that´s why it is now deprecated..  :-\
- Mate (beverage) addict
- Heavy metal addict _lml
- SFML 2 addict
- My first (and free) game: BichingISH!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: State Machine and Engine problem
« Reply #10 on: August 09, 2012, 08:30:48 am »
Maybe one doesn´t need the linear sequence order (and usually doesn´t). Plus, the elements of a std::vector are guaranteed to be contiguous.
What does it matter how it's implemented behind the scences? If you want a stack then use a std::stack. It's like refusing to use any STL container and implement everything on your own with arrays. The containers hace their task and if one uses a vector as a stack then the vector is being missused.
And yes, he is using push_back, but previously he is pausing the current state (in the PushState function), not calling state->clear().
This doesn't violate the stack. Call pause push_back new state, I don't see a problem. Like I already said just go ahead, take the original source and replace the vector with a stack and change push_back to push and pop_back to pop and it will work without any further change.

Also you may want to loop through the contents of the "stack" and std::stack doesn't allow that.
One may want to do alot, that's why source code can be changed. But as I already said he doesn't do anything like this and his intend was to use a stack and not to iterate through the states, so leave those possible changes to the user and dob't just implement things because someday someone maybe wants to iterate through state. Also note that with a good design one can doesn't need to iterate. (Do you have a use case.)
And if you look at quite a lot of other state machine implementation, you'll very very very often find a std::stack, so it's no uncommon nor stupid.

Ok, shared pointers are nice, but what if one can´t/doesn´t want to use C++11/boost?
Use auto_ptr, yes, but it is also risky... that´s why it is now deprecated..  :-\
Tbh I don't care for the people that don't want to use C++11 features that are already well supported by all the big compilers. It's the way to go and if people don't want to jump on that train, they will soon be stuck with very few libraries. ;)
If one wants to stick with C++03 the use of auto_ptr is legit.
As for shared_ptr they are already a feature of the TR1, which is C++03 so one change the std:: to std::tr1::
« Last Edit: August 09, 2012, 08:41:48 am by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

mateandmetal

  • Full Member
  • ***
  • Posts: 171
  • The bird is the word
    • View Profile
    • my blog
Re: State Machine and Engine problem
« Reply #11 on: August 10, 2012, 01:18:52 am »
What does it matter how it's implemented behind the scences?

:facepalm:
What does it matter? REALLY?

so leave those possible changes to the user and dob't just implement things because someday someone maybe wants to iterate through state

It´s called "flexible code", btw

And if you look at quite a lot of other state machine implementation, you'll very very very often find a std::stack, so it's no uncommon nor stupid.

I have a very good AI Programming book, covering state machines and other topics. I think the author of this book never used a std::stack on any source code file

I don't care for the people that don't want to use C++11 features that are already well supported by all the big compilers. It's the way to go and if people don't want to jump on that train, they will soon be stuck with very few libraries. ;)

Ok.. good luck
And you are right... this is a "design" discussion. Maybe not proper for this forum
- Mate (beverage) addict
- Heavy metal addict _lml
- SFML 2 addict
- My first (and free) game: BichingISH!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: State Machine and Engine problem
« Reply #12 on: August 10, 2012, 03:11:45 am »
:facepalm:
What does it matter? REALLY?
Yes why is it soooo important that all the states have to be layed out contiguously? For that one jump it has to make once doesn't matter if it has to jump one adress further or to a adress futher away.

It´s called "flexible code", btw
And I repeate again, his intend was to use a stack and not a vector. Implementing it as a vector and talking about stacks doesn't fit. If he wants the code to be flexible then he should write what this flexibility holds.

I have a very good AI Programming book, covering state machines and other topics. I think the author of this book never used a std::stack on any source code file
Is the book and author so bad that you couldn't tell us which one and who, so we could check his work and see if it holds up your claims about beeing very good?
Also if the book is written by one person, then part of it represent his ideas and preferences, so if he doesn't like stacks (like you) then he probably won't use them. On the other hand there are numberous examples on the internet and I also bet in many books that use stacks. (I can't give you sources for my claims because I'm too lazy to google from them ;))

One more thing to add to you arguments why it's better to use a vector, if you use this code
std::stack<T, std::vector<T> >
your runtime for stack and vector will be the same, so it doesn't matter which one you choose. Which again shows that everything is about design.

In short: If you implement B and say A but don't explain why you use B, then there's no reason to use B, because it contradicts your actions.

And you are right... this is a "design" discussion. Maybe not proper for this forum
Why shouldn't that be right for this forum? I hope this isn't a sacastic comment to point out that SFML has design issues... ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

The Terminator

  • Full Member
  • ***
  • Posts: 224
  • Windows and Mac C++ Developer
    • View Profile
Re: State Machine and Engine problem
« Reply #13 on: August 10, 2012, 08:42:48 pm »
Sorry to break up you guys's "discussion"  ;) but when I was trying out your code eXpl0it3r, I get 2 errors from the screen.create and the texture loadfromFile. It says this for screen.create:

"sf::Texture::loadFromFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, sf::Rect<int> const&)", referenced from:
      ShockEngine::SplashScreenState::SplashScreenState(bool) in SplashScreenState.o

And loadFromFile:

"sf::Window::create(sf::VideoMode, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned int, sf::ContextSettings const&)", referenced from:
      ShockEngine::GameEngine::GameEngine(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned int, unsigned int, unsigned int, bool) in Engine.o

I triple checked all your code, and everything is matching, but the problem persists. Any idea what the problem could be? I am using Xcode if that matters at all.
Current Projects:
Technoport

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: State Machine and Engine problem
« Reply #14 on: August 10, 2012, 08:58:50 pm »
Have you left out the error itself? I mean it only describes what symbol it fails on but it doesn't say what the problem is. Please post the full error message.
Also since it's happening in the .o files, have you cleaned and rebuild everything, maybe the object files are outdated.
Do the SFML examples work?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/