5
\$\begingroup\$

I know this has been asked before but I would like some things cleared up.

I understand that game logic and rendering should be separated but my problem is more or less how? For instance, should the renderer get ALL info from the sprite/object and use that to draw? Also should the renderer be a seperate class or member function. If it's a separate class should it be able to get the necessary info via public functions or should it be a friend of the class to draw it?

Also some clarification as to what the main object should contain, e.g, is it okay for the main class to have other sprites, shapes, fonts, and effect data? Or, should the renderer somehow contain or produce that data?

I'm asking this because I'm making a menu list class in SFML. And, although it technically works, I'm confused because it's implemented in a way that is considered by many to be bad. Thus, I would like to know as to how to implement it and fix it correctly because I have currently blended both the logic and rendering together.

class MenuList {
    private:
        bool m_visibility{ true };
        std::vector<std::pair<MenuItem, sf::Text>> m_items;
        sf::RenderWindow& m_window;
        SEL::EventManager& m_manager;
        sf::Font m_font;

        sf::RectangleShape m_highlighter;
        sf::Color m_highlightColor;

        sf::RectangleShape m_box;

        size_t m_size{ 0 };
        size_t m_rowSpacing;

        static const uint16_t indent;
    public:
        MenuList(sf::RenderWindow& window, SEL::EventManager& manager);
        ~MenuList();
        // get a certain option, no range checking
        MenuItem& operator[](size_t index);

        // get a certain option, with range checking
        // will report an error to the console if range is out of bounds
        MenuItem& getOption(size_t index);

        // update the menu
        void Update();

        // set the visibility of the menu
        void setVisibility(bool value);

        // get the visibility of the menu
        bool getVisibility() const;

        // add another option
        void addOption(const MenuItem& item);

        // add multiple options via a list { }
        void addOption(std::initializer_list<MenuItem> items);

        // remove an options index
        void removeOption(size_t index);

        // remove an option by name
        void removeOption(const sf::String& name);

        // resize the amount of submenus
        void resize(size_t size);

        // get the local position of the menubox
        sf::FloatRect getLocalBounds();

        // set the amount of spacing between each menu in pixels
        void setRowSpacing(size_t rowSpacing);

        // get the amount of spacing is in between each menu in pixels
        size_t getRowSpacing() const;

        //void addSeperator(size_t index, sf::PrimitiveType Type = sf::PrimitiveType::LinesStrip);

        // get the amount of sub menus
        size_t getMenuCount() const noexcept;

        // get the position of the menu, the top left
        const sf::Vector2f& getPosition() const noexcept;

        // move the menu to a completely new position, overides the previous position
        void setPosition(float x, float y);

        // move the menu to a completely new position, overides the previous position
        void setPosition(const sf::Vector2f& pos);

        void setOutlineThickness(size_t thickness);

        size_t getOutlineThickness() const;

        // reset the menu such as the size, menus, and box
        void reset();
    };
\$\endgroup\$
  • 1
    \$\begingroup\$ A MenuList is not a typical game objects. The advice we might give for making a character or whatever is almost completely irrelevant for UI widgets. You can still separate logic from presentation and from rendering (e.g., separate the controller from the layout and from theme rendering) but the approach there is usually not the same as for game objects. In this day and age, I'd probably recommend you to model your UI code more after the Web (DOM, CSS, box model, etc.) than a game engine (in fact, just use the Web and embed CEF or something for your menu UI). \$\endgroup\$ – Sean Middleditch Jul 11 '16 at 16:03
  • \$\begingroup\$ @Sean Middleditch that's kind of why I was getting confused mainly since what I was making was kind of different from the usual. Thanks for the advice! \$\endgroup\$ – Rabster Jul 12 '16 at 0:09
2
\$\begingroup\$

The idea is simple. You need to have a way to define an object on the screen. It should contain the information for the rendering (like textures, effects, etc.) and for the game logic (velocity, acceleration, etc.). The main game logic shouldn't touch the rendering parts and vice-versa. There are variables, which needs to be used by both systems (like the position of the object).

Your main class should not contain anything. Each part of the game should be isolated from each other. Sometimes a messaging system is used to let these parts communicate with each other.

In the updater method you should update the game logic variables. Move the character, do the path finding, etc. In the rendering method you need to use the textures and effects to render the character on the screen.

\$\endgroup\$
  • 1
    \$\begingroup\$ Agreed though in my experience, a bit of compromise is often required. \$\endgroup\$ – Pikalek Jul 11 '16 at 14:46
  • \$\begingroup\$ @Pikalek The compromise is the variables used by both sides. If you think it trough, there's no reason for the different systems to communicate with each other \$\endgroup\$ – Bálint Jul 11 '16 at 14:47
  • 1
    \$\begingroup\$ The clinically clean situation. However, there are often cases where you do calculations and want to get rid of the result quickly (ie. paint it), instead of storing it as data to later on use for painting (naturally assuming it is not re-usable result data, cached). Logic and paint are separated between 0...1 (messy...separared) and i say nobody sits at 1 :-). Also to note, there are a million other reasons that enforce mixing, for example pre-rendering surfaces. Housekeeping is the #1 challenge for everyone. Ofc the goal is beautiful, manageable code, so yeah, separate'em reasonably! :-) \$\endgroup\$ – Stormwind Jul 11 '16 at 15:29
1
\$\begingroup\$

EDIT: @Bálint made a great point about my answer. This works best for 2D rendering frameworks (SDL, XNA, etc) and less so with working directly with things like DirectX/OpenGL, which require a much closer coupling of the WHAT, WHERE, and HOW that I list below.

Here is the paradigm I follow with how I organize my classes and what responsibilities each has:

  • Renderer class
    • Static class that can be called by anyone
    • Has Render() method that given a texture and a set of parameters, will render the texture (X & Y coordinates, rotation, etc)
  • Texture classes
    • WHAT you want to render (EX: The actual image data for a tree)
    • Has Render() method that will render the texture given a set of parameters (X & Y coordinates, rotation, etc)
  • Sprite classes
    • Contains the Texture you wish to render for the Sprite
    • WHERE and HOW you want to render that texture (EX: The X & Y locations, rotation, etc)
    • Has Update() method to update the sprite's WHERE and HOW
    • Has Render() method to render the texture using the WHERE and HOW stored in the sprite

Here's an example of what your typical frame would look like:

  • Sprite->Update()

    .. .. ..

  • Sprite->Render()

    • Texture->Render(this->x, this->y, this->rotation)
      • Renderer->Render(this->texture, x, y, rotation)

Although some might view this as over complication, it helps separate out the logic and responsibilities of each class:

  • Renderer knows how to render things given to it
  • Texture knows how to render itself given location parameters
  • Sprite knows how to update its state and how to render its texture using its state
\$\endgroup\$
  • 2
    \$\begingroup\$ This is all nice if you use a framework to render stuff, but fails if you use OpenGL or DirectX. With those, you usually need to couple together objects/sprites using the same texture/model to optimize rendering \$\endgroup\$ – Bálint Jul 12 '16 at 9:18
  • \$\begingroup\$ A very fair point. I focus more primarily on 2D-based frameworks (SDL, XNA, etc), so this paradigm works very well for that. I'll caveat my answer with it, thanks! \$\endgroup\$ – SaviorXTanren Jul 12 '16 at 21:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.