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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Indorile

Pages: [1]
1
SFML projects / Re: Game Development Design articles
« on: April 01, 2013, 07:18:11 pm »
Now that I think of it, is there some way to differentiate components that require same attributes? For example both PlayerController and AIController require Position and Velocity, how should system know if it should attach one or another? I could solve it by using different names like PC_Position and NPC_Position, but then Collision that requires Position wouldn't know about them...

2
SFML projects / Re: Game Development Design articles
« on: March 28, 2013, 07:10:09 pm »
Yeah, I went with the BaseFactory/Factory<T> approach and I have renamed GameObjectFactory to GameObjectSystem, so in the constructor now I do this:

m_Factories.push_back(std::unique_ptr<Factory<ScrollingBackgroundComponent>>(new Factory<ScrollingBackgroundComponent>()));

I'll have some more questions later on when I progress with my game's development :) Thanks for the help.

3
SFML projects / Re: Game Development Design articles
« on: March 24, 2013, 07:18:04 pm »
Hey there.
I started writing my platformer game in C++/SFML and inspired by your article I went with the self-attached component system route. So I started implementing and came with a working solution. Thing is its a "working solution", my C++ skills are rusty as hell after spending about 6+ years with C# and NeoAxis engine, so code could use some refactoring even at this early stage. So here are some relevant parts of the code:

BaseAttribute:
// HPP
#ifndef BASE_ATTRIBUTE_HPP_INCLUDED
#define BASE_ATTRIBUTE_HPP_INCLUDED

#include <string>

namespace ksg
{
    class BaseAttribute
    {
    public:
        virtual ~BaseAttribute() = 0;

        const std::string& getName() { return m_Name; }

    protected:
        std::string m_Name;
    };
}

#endif // BASE_ATTRIBUTE_HPP_INCLUDED

// CPP
#include "../include/BaseAttribute.hpp"

namespace ksg
{
    BaseAttribute::~BaseAttribute()
    {
    }
}

Attribute:
#ifndef ATTRIBUTE_HPP
#define ATTRIBUTE_HPP

#include <string>
#include <memory>

namespace ksg
{
    template <typename T>
    class Attribute : public BaseAttribute
    {
    public:
        Attribute(T value, const std::string& name)
        {
            m_Value = value;
            m_Name = name;
        }

        T& getValue() { return m_Value; }

    protected:
        T m_Value;
    };
}

#endif // ATTRIBUTE_HPP

BaseComponent:
//HPP
#ifndef BASE_COMPONENT_HPP
#define BASE_COMPONENT_HPP

#include "BaseAttribute.hpp"
#include <vector>
#include <memory>

namespace ksg
{
    class GameObject;

    class BaseComponent
    {
    public:
        BaseComponent(std::shared_ptr<GameObject> parent);
        virtual ~BaseComponent();

        virtual std::unique_ptr<BaseComponent> clone(std::shared_ptr<GameObject> parent) = 0;
        virtual void update(float dt) = 0;

        bool checkRequiredAttributes(std::shared_ptr<GameObject> obj);

    protected:
        static std::vector<std::string> m_RequiredAttributes;
        std::shared_ptr<GameObject> m_Parent;
    };
}

#include "GameObject.hpp"

#endif // BASE_COMPONENT_HPP

//CPP
#include "../include/BaseComponent.hpp"

namespace ksg
{
    std::vector<std::string> BaseComponent::m_RequiredAttributes;

    BaseComponent::BaseComponent(std::shared_ptr<GameObject> parent)
    {
        m_Parent = parent;
    }

    BaseComponent::~BaseComponent()
    {
    }

    bool BaseComponent::checkRequiredAttributes(std::shared_ptr<GameObject> obj)
    {
        if(!obj)
            return false;

        std::vector<std::string>::const_iterator iter;
        for(iter = m_RequiredAttributes.begin(); iter != m_RequiredAttributes.end(); ++iter)
            if(!obj->getAttribute(*iter))
                return false;

        return true;
    }
}

GameObject:
//HPP
#ifndef GAME_OBJECT_HPP_INCLUDED
#define GAME_OBJECT_HPP_INCLUDED

#include "BaseAttribute.hpp"
#include "BaseComponent.hpp"
#include <unordered_map>
#include <vector>
#include <memory>

namespace ksg
{
    class GameObjectFactory;

    class GameObject
    {
    friend class GameObjectFactory;

    public:
        void update(float dt);

        std::shared_ptr<BaseAttribute> getAttribute(std::string name) { return m_Attributes[name]; }

    private:
        std::unordered_map<std::string, std::shared_ptr<BaseAttribute>> m_Attributes;
        std::vector<std::unique_ptr<BaseComponent>> m_Components;
    };
}

#include "GameObjectFactory.hpp"

#endif // GAME_OBJECT_HPP_INCLUDED

//CPP
#include "../include/GameObject.hpp"

namespace ksg
{
    void GameObject::update(float dt)
    {
        std::vector<std::unique_ptr<BaseComponent>>::const_iterator iter;
        for(iter = m_Components.begin(); iter != m_Components.end(); ++iter)
            (*iter)->update(dt);
    }
}

GameObjectFactory:
//HPP
#ifndef GAME_OBJECT_FACTORY_HPP
#define GAME_OBJECT_FACTORY_HPP

#include "GameObject.hpp"
#include "BaseAttribute.hpp"
#include "BaseComponent.hpp"
#include <vector>
#include <memory>

namespace ksg
{
    class GameObjectFactory
    {
    public:
        GameObjectFactory();
        ~GameObjectFactory();

        static bool initialize();
        static std::unique_ptr<GameObjectFactory>& getInstance() { return m_Instance; }

        void createGameObject(const std::vector<BaseAttribute*>& attributes);
        void update(float dt);

    private:
        static std::unique_ptr<GameObjectFactory> m_Instance;

        std::vector<std::unique_ptr<BaseComponent>> m_Components;
        std::vector<std::shared_ptr<GameObject>> m_GameObjects;
    };
}

#endif // GAME_OBJECT_FACTORY_HPP

//CPP
#include "../include/GameObjectFactory.hpp"
#include "../include/ScrollingBackgroundComponent.hpp"

namespace ksg
{
    std::unique_ptr<GameObjectFactory> GameObjectFactory::m_Instance;

    GameObjectFactory::GameObjectFactory()
    {
        ScrollingBackgroundComponent::initRequiredAttributes();
        m_Components.push_back(std::unique_ptr<ScrollingBackgroundComponent>(new ScrollingBackgroundComponent(nullptr)));
    }

    GameObjectFactory::~GameObjectFactory()
    {

    }

    bool GameObjectFactory::initialize()
    {
        m_Instance.reset();
        m_Instance = std::unique_ptr<GameObjectFactory>(new GameObjectFactory());

        if(!m_Instance)
            return false;

        return true;
    }

    void GameObjectFactory::createGameObject(const std::vector<BaseAttribute*>& attributes)
    {
        std::shared_ptr<GameObject> gameObject = std::shared_ptr<GameObject>(new GameObject);

        for(std::vector<BaseAttribute*>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
            gameObject->m_Attributes.insert(std::make_pair((*iter)->getName(), std::shared_ptr<BaseAttribute>(*iter)));

        for(std::vector<std::unique_ptr<BaseComponent>>::const_iterator iter = m_Components.begin(); iter != m_Components.end(); ++iter)
            if((*iter)->checkRequiredAttributes(gameObject))
                gameObject->m_Components.push_back(std::unique_ptr<BaseComponent>((*iter)->clone(gameObject)));

        m_GameObjects.push_back(gameObject);
    }

    void GameObjectFactory::update(float dt)
    {
        std::vector<std::shared_ptr<GameObject>>::iterator iter;

        for(iter = m_GameObjects.begin(); iter != m_GameObjects.end(); ++iter)
            (*iter)->update(dt);
    }
}

And finally something more specific - ScrollingBackgroundComponent:
//HPP
#ifndef SCROLLING_BACKGROUND_COMPONENT_HPP
#define SCROLLING_BACKGROUND_COMPONENT_HPP

#include "BaseComponent.hpp"
#include "Attribute.hpp"
#include "ScrollingBackground.hpp"
#include <SFML/Graphics.hpp>
#include <memory>

namespace ksg
{
    class ScrollingBackgroundComponent : public BaseComponent
    {
    public:
        ScrollingBackgroundComponent(std::shared_ptr<GameObject> parent);
        ~ScrollingBackgroundComponent();

        std::unique_ptr<BaseComponent> clone(std::shared_ptr<GameObject> parent) { return std::unique_ptr<BaseComponent>(new ScrollingBackgroundComponent(parent)); }
        void update(float dt);

        static void initRequiredAttributes();

    private:
        std::shared_ptr<Attribute<ScrollingBackground*>> m_Visual;
    };
}

#endif // SCROLLING_BACKGROUND_COMPONENT_HPP

//CPP
#include "../include/ScrollingBackgroundComponent.hpp"

namespace ksg
{
    ScrollingBackgroundComponent::ScrollingBackgroundComponent(std::shared_ptr<GameObject> parent) : BaseComponent(parent)
    {
        if(parent)
        {
            m_Visual = std::dynamic_pointer_cast<Attribute<ScrollingBackground*>>(parent->getAttribute("sb_visual"));
            std::shared_ptr<Attribute<sf::Vector2i>> position = std::dynamic_pointer_cast<Attribute<sf::Vector2i>>(parent->getAttribute("sb_position"));
            std::shared_ptr<Attribute<sf::Vector2f>> scrollSpeed = std::dynamic_pointer_cast<Attribute<sf::Vector2f>>(parent->getAttribute("sb_scroll_speed"));
            std::shared_ptr<Attribute<bool>> autoScroll = std::dynamic_pointer_cast<Attribute<bool>>(parent->getAttribute("sb_auto_scroll"));

            if(position)
                m_Visual->getValue()->setPosition(position->getValue());

            if(scrollSpeed)
                m_Visual->getValue()->setScrollSpeed(scrollSpeed->getValue());

            if(autoScroll)
                m_Visual->getValue()->setAutoScroll(autoScroll->getValue());
        }
    }

    ScrollingBackgroundComponent::~ScrollingBackgroundComponent()
    {

    }

    void ScrollingBackgroundComponent::update(float dt)
    {
        m_Visual->getValue()->update(dt);
    }

    void ScrollingBackgroundComponent::initRequiredAttributes()
    {
        m_RequiredAttributes.push_back("sb_visual");
    }
}
 

Somewhere in the Game.cpp:
std::vector<BaseAttribute*> attr;
attr.push_back(new Attribute<ScrollingBackground*>(&back1, "sb_visual"));
attr.push_back(new Attribute<sf::Vector2f>(sf::Vector2f(1, .25f), "sb_scroll_speed"));
GameObjectFactory::getInstance()->createGameObject(attr);

attr.clear();
attr.push_back(new Attribute<ScrollingBackground*>(&back2, "sb_visual"));
attr.push_back(new Attribute<sf::Vector2i>(sf::Vector2i(0, 32), "sb_position"));
attr.push_back(new Attribute<sf::Vector2f>(sf::Vector2f(16, .5f), "sb_scroll_speed"));
attr.push_back(new Attribute<bool>(true, "sb_auto_scroll"));
GameObjectFactory::getInstance()->createGameObject(attr);
       
attr.clear();
attr.push_back(new Attribute<ScrollingBackground*>(&back3, "sb_visual"));
attr.push_back(new Attribute<sf::Vector2f>(sf::Vector2f(1.5f, .75f), "sb_scroll_speed"));
GameObjectFactory::getInstance()->createGameObject(attr);
attr.clear();

All runs fine so far, though as I said my C++ skills are rusty and I need code revision badly :)
For start I would like to change the way of storing available components into the game factory, having empty components for the sake of it is just meh to me.

Anyway thanks in advance for help, and thanks for your game design articles :)

P.S. Two links I found during my research that could be of some use:
Pitfalls of Object Oriented Programming
Theory and Practice of Game Object Component Architecture

EDIT: Is there like some spoiler tag or show hide code option? Too much code = unnecessary lengthy post  :-\

Pages: [1]