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

Author Topic: [ODFAEG] (Open Source Development Framework Adapted for Every Game)  (Read 112664 times)

0 Members and 1 Guest are viewing this topic.

MorleyDev

  • Full Member
  • ***
  • Posts: 219
  • "It is not enough for code to work."
    • View Profile
    • http://www.morleydev.co.uk/
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #30 on: February 05, 2014, 06:24:14 am »
std::shared_ptr<void> voidPtr = std::make_shared<int>(10);
std::shared_ptr<int> intPtr = std::static_pointer_cast<int>(voidPtr);

std::shared_ptr<int> intPtr = std::make_shared<int>(10);
std::weak_ptr<void> voidPtr = intPtr;
std::shared_ptr<void> sharedVoidPtr = voidPtr.lock();
std::shared_ptr<int> otherIntrPtr = std::static_pointer_cast<int>(sharedVoidPtr);

As I understand the term, shared_ptr offers a fairly safe type-erasement, because the shared_ptr will pass the correct destructor functor to std::shared_ptr<void>, meaning if it falls out of scope everything will still get deconstructed safely. shared_ptr supports move semantics, and for avoiding circular references you can always weak_ptr.

A cache can nowadays just store the weak_ptrs, it then tried to lock the weak_ptr when someone requested the resource. If the lock returned a valid shared_ptr, just return that. If not, reacquire the resource.
« Last Edit: February 05, 2014, 06:34:54 am by MorleyDev »
UnitTest11 - A unit testing library in C++ written to take advantage of C++11.

All code is guilty until proven innocent, unworthy until tested, and pointless without singular and well-defined purpose.

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #31 on: February 05, 2014, 10:13:33 am »
Oki, I was just thinking of using something like this for loading the resource.

But I've a question, can I use a shared pointer and retrieve the pointer from the encapsulation objet ?

I don't really need it, I just need it to free the resource when the loading fails :

std::shared_ptr<void> resourcePtr = std::make_shared<sf::Texture>();
if (!resourcePtr.getPtr().loadFromFile(...))  {
    //We launch an exeption and delete the pointer.
   // (The shared pointer does it, it would be usefull if I've a lot of exceptions or return cases)
}
Resource *resource = new Resource(resourcePtr.getPtr());
 
And I remove all the resources in the destructor, when the ResourceManager is destroyed.

Most of all : my resources are stored in a map in the resource manager class who use any kind of identifiant type who's associate with the resource. (Because I can't pass 2 templates argument in the shared pointer)
So I think it's simplier to have a base class (ResourceManagerBase for exemple), and ResourceManager<R, I> inherit from ResourceManagerBase.
So I store pointers to ResourceManagerBase objects into the cache, it avoids me to have a more complex system.
template <typename R, typename I>
void ResourceCache::addResourceManager(ResourceManager<R, I>& rmi, std::string name) {
    ResourceManagerBase* rmb = &rmi;
    std::map<std::string, ResourceManagerBase*>::iterator it = resourceManagers.find(name);
    if (it != resourceManagers.end())
        resourceManager<R, I>(name) = rmi;
    resourceManagers.insert(std::pair<std::string, ResourceManagerBase*>(name, rmb));
}
template <typename R, typename I>
ResourceManager<R, I>& ResourceCache::resourceManager(std::string name) {
    std::map<std::string, ResourceManagerBase*>::iterator it = resourceManagers.find(name);
    if (it == resourceManagers.end())
        throw Erreur (12, "Resource manager not found!", 0);
    if (dynamic_cast<ResourceManager<R, I>*> (it->second) == nullptr)
        throw Erreur (13, "Bad cast!", 0);
    return dynamic_cast<ResourceManager<R, I>&> (*(it->second));
}
 

I used a dynamic_cast but we can use a static_cast too.

Of course if we want to retrieve the resource manager we have to specify the types of the resources and the type of the resources identifiers who are stored in the manager.

But it's not very a problem for me.



« Last Edit: February 05, 2014, 10:19:02 am by Lolilolight »

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #32 on: February 05, 2014, 10:24:33 am »
std::shared_ptr<void> resourcePtr = std::make_shared<sf::Texture>();
if (!resourcePtr.getPtr().loadFromFile(...))  {
    //We launch an exeption and delete the pointer.
   // (The shared pointer does it, it would be usefull if I've a lot of exceptions or return cases)
}
Resource *resource = new Resource(resourcePtr.getPtr());
 

Try this instead :

void YourObject::YourMethod()
{
     std::shared_ptr<sf::Texture> resourcePtr(new sf::Texture(...));
     if(!resourcePtr->loadFromFile(...)) {
          throw your::exception(...); // This will AUTOMAGICALLY delete the texture since it get out of scope
     }
}

Smart pointers are magic.

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #33 on: February 05, 2014, 10:40:33 am »
Ok, I'll try this, thanks!

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #34 on: February 12, 2014, 05:17:41 pm »
Big changements for the first release. (It'll be updated on the 1rst March)

-The cache'll be improved to  be able to store any kind of ResourceManager type.
-The entity class'll have a state, then you'll be able to redefine the entity class for common attributes (exemple : a class caracter) and add custom attributes to the entity's state. (exemple : if the caracter is a magician, you can add an attribute called mana for example)
To interact between the entities, you'll need to redefines two function of the abstract StateExecutor class (one to apply a special entity's state and the other to unapply a special entity's state), these functions take one parameter : the current entity state. (You can so retrieve and change the parameters of the current entity's state in the executor's functions)
And you have just to pass your state executor to the entity manager, if you want to change a special attribute of an entity.
This system was designed  to avoid you to have to do too much inheritance. (If you have a lot of different weapons types, skills, caracter classes, ... in your game, and some classe can equipe only one type of weapon, use only some skills, etc....)

This new feature'll also improve the moves storage for movement prediction in the next version. (When I'll introduce the network and physic aspects)

PS : I've also corrected some points.
« Last Edit: February 12, 2014, 05:36:10 pm by Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #35 on: February 13, 2014, 02:15:44 pm »
I forgot to mention it, but this should interest you, in the last chapter of the tutorials, they'll be an example small game which'll be created with ODFAEG, it'll not be an awesome game (just a caracter, a monster and an xp system) but it'll give the base to create a game with ODFAEG.
The tutorial and the small game example'll be integrated to the git-hub repositories, because I haven't the time to do a website for the moment, I'll probably create one later, when the sorrok project well be finished, but, I've also my own project (Sorrok) to finish so, I've a lot of work.

The last version (with will implement the 3D part) will only be coded when the first version of the Sorrok project will be released. (Because the second version of the Sorrok project'll be coded in full 3D)
The first version off Sorrok'll just be a test. (To know if I'm in the right way to add the 3D or if I've to review some points in the gameplay)
So the feedback'll always be appriciate. (But only feedback who have sense, and not messages only made to attack my own reputation and troll (like some members have tried to do in the past))
« Last Edit: February 13, 2014, 02:21:21 pm by Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #36 on: February 17, 2014, 12:09:20 pm »
Major optimisation, so I've updated the git-hub repositry  :

-The scene node : the combinaison of transformations are now made in the odfaeg::Transformable class instead of in the draw function. (So you can choose if you want to combine the transfation, rotation and scale when you're drawing the entity nodes and his children :

By default the transformations of the parent node and its children are combined but if you don't want to combine them you can redefines these functions and let them empty :

class ParentNode {
void onMove(Vec2f& t) {}
void onScale(Vec2f& s) {}
void onRotate(float angle) {}
};

If you have to update informations when your entity is transformed you can do this in these 3 functions, but, if you want to also combine transformations in the children nodes and other informations on theses functions you have to call the Entity::onMove(t), Entity::onRotate(angle) and Entity::onScale(s) functions in the function redefinitions like this :
class ParentNode {
void onMove(Vec2f& t) {Entity::onMove(t);}
void onScale(Vec2f& s) {Entity::onScale(s) ;}
void onRotate(float angle) {Entity::onRotate(angle);}
};

This'll pass the transformation at the children nodes and apply this transformation to the children nodes.

The same technique is used with the onDraw function.

I had to do this because the example shown in the SFML tutorials wasn't very practice in my case.

The entities have also two origin (the position for the translation) and the center for rotation and scale, instead of SFML which provides only one origin.

I've also optimised the entity manager (the class Map), the function containsVisibleEntity was too slow so I compared the pointer instead of the entities themself.
I think I'll delete the class tGround because it's quite uselless. (For the ground I  add now tiles directly in the entity manager in the generate_map function.)

I've also optimized animations. (and animations who have entity's which can move throw the screen like a caracter for exemple or a monster)
I've added a gravity center and the entity manager use it to check entities which are before or behind the movable animation, and so find the layer position of the movable entity automatically.)

You can change the gravity center of a model by calling the changeGravityCenter method.

An a lot of improvement are coming : (I wonder if I'll have finish it to the first March)

I've still a displaying bug with the current entity of the movable animation.(Sometimes it doen't display, sometimes it display 2 superposed entities of the animation)

I'll change the std::string to a void* in the entity manager to count how many time a resource is used in the entity manager. (To avoid to have to pass a template, I just need the adress of the resource in the entity manager to count how many time a resource is used)

And that's all, when I'll find this last bug with animations, I think I'll can launch the first release, and implement the network, the video of the Sorrok project shouldn't give a lag impression anymore.

But the optimisation is not an easy point, I've first to improve the entity system, and only after if it's enought fast, I can introduce the network and it must stay fast with a movement prediction system.

But event if an object isn't heavy like a view, when we have to retrieve it very often in the source code, I've noticed that returning a reference (even on a small object) is a important gain of performance in a big project.

So I've change some of my functions to return a reference.
I think I'll change it for the view in the source code of SFML.

I've also to do some changement in the Action class to perform the event correctly when a type of event is defined (PRESSED_ONCE or HELDOWN) and clear the event buffer of the action  in function of the type of the event.
I though to set -1 to the event type to clear the buffer but it result to a compilation error so I need to find another idea, I think I'll change the source of SFML to add a variable for an empty sf::Event.

So I shoudn't have optimisation and transformation computations of the entities problems with SFML anymore. (It was very paintefull)

PS 2 : I'll also improve the World class to store systems and entity managers.
Screen an movies are comming soon.
« Last Edit: February 17, 2014, 12:45:45 pm by Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #37 on: February 17, 2014, 03:31:27 pm »
I've fixed the bugs with the animations. (And I've updated them on the got-hub)

For the second one it wasn't a bug I've just forgot to replace the animation in the gridmap when the caracter moved.

But now everything is fine :
Here is an example of source code which moves a caracter accross the map.

#ifndef MY_APPLI
#define MY_APPLI
#include "ODFAEG/Core/application.h"
#include "ODFAEG/Graphics/2D/tile.h"
#include "ODFAEG/Graphics/2D/map.h"
#include "ODFAEG/Graphics/2D/world.h"
#include "ODFAEG/Graphics/2D/decor.h"
#include "ODFAEG/Graphics/2D/anim.h"
#include "ODFAEG/Graphics/2D/ambientLight.h"
#include "ODFAEG/Core/actionMap.h"
#include "ODFAEG/Core/system.h"
#include "ODFAEG/Core/entitiesUpdater.h"
#include "ODFAEG/Core/animationUpdater.h"
#include "caracter.h"
using namespace odfaeg;
using namespace sf;

class MyAppli : public Application {
    private :
    const int speed = 50;
    Map* theMap;
    Clock realTime;
    EntitiesUpdater *eu;
    RenderTexture *renderTextShadows, *renderTextLights;
    RectangleShape rect;
    AnimUpdater *au;
    bool running;
    ActionMap *closedAction;
    ActionMap *moveAction;
    Listener listener;
    TileGround *tg;
    Wall *w;
    Caracter* caracter;
    sf::Keyboard::Key actualKey, previousKey;
    enum TEXTURES {
        GRASS, WALLS, HOUSE, FIRE1, FIRE2, FIRE3
    };


    public :
    MyAppli(sf::RenderWindow &window) : Application (window) {
        running = false;
        actualKey = sf::Keyboard::Unknown;
        previousKey = sf::Keyboard::Unknown;
    }
    void close () {
        getWindow().close();

    }
    void keyHeldDown (sf::Keyboard::Key key, sf::Time elapsedTime) {
        sf::View view = getWindow().getView();
        float t = speed * elapsedTime.asSeconds();
        if (actualKey != sf::Keyboard::Key::Unknown && key == sf::Keyboard::Key::Z) {
            view.move (0, -t);
            if (!caracter->isMoving()) {
                if (actualKey != previousKey) {
                    Vec2f dir(0, -1);
                    caracter->setDir(dir);
                }
                caracter->setMoving(true);
            }
            theMap->moveEntity(caracter, caracter->getDir().x * t, caracter->getDir().y * t);
        } else if (actualKey != sf::Keyboard::Key::Unknown && key == sf::Keyboard::Key::Q) {
            view.move (-t, 0);
            if (!caracter->isMoving()) {
                if (actualKey != previousKey) {
                    Vec2f dir(-1, 0);
                    caracter->setDir(dir);
                }
                caracter->setMoving(true);
            }
            theMap->moveEntity(caracter, caracter->getDir().x * t, caracter->getDir().y * t);
        } else if (actualKey != sf::Keyboard::Key::Unknown && key == sf::Keyboard::Key::S) {
            view.move (0, t);
            if (!caracter->isMoving()) {
                if (actualKey != previousKey) {
                    Vec2f dir(0, 1);
                    caracter->setDir(dir);
                }
                caracter->setMoving(true);
            }
            theMap->moveEntity(caracter, caracter->getDir().x * t, caracter->getDir().y * t);
        } else if (actualKey != sf::Keyboard::Key::Unknown && key == sf::Keyboard::Key::D) {
            view.move (t, 0);
            if (!caracter->isMoving()) {
                if (actualKey != previousKey) {
                    Vec2f dir(1, 0);
                    caracter->setDir(dir);
                }
                caracter->setMoving(true);
            }
            theMap->moveEntity(caracter, caracter->getDir().x * t, caracter->getDir().y * t);
        }

        getWindow().setView(view);
        renderTextShadows->setView(view);
        renderTextLights->setView(view);
        BoundingRectangle br (view.getCenter().x - view.getSize().x * 0.5f, view.getCenter().y - view.getSize().y * 0.5f, view.getSize().x, view.getSize().y);

        eu->setViewRect(br);
        au->setViewRect(br);
        eu->update();
    }
    bool mouseInside (Vector2f mousePos) {
        BoundingRectangle br (0, 0, 100, 100);
        if (br.isPointInside(Vec2f(mousePos.x, mousePos.y))) {
            return true;
        }
        return false;
    }
    void onMouseInside (Vector2f mousePos) {
        std::cout<<"Mouse inside : "<<mousePos.x<<" "<<mousePos.y<<std::endl;
    }
    void load() {
        ResourceManager<sf::Texture, TEXTURES>* tm = new ResourceManager<sf::Texture, TEXTURES>();
        tm->fromFile("tilesets/herbe.png", GRASS);
        tm->fromFile("tilesets/murs.png",  WALLS);
        tm->fromFile("tilesets/maison.png", HOUSE);
        tm->fromFile("tilesets/flemmes1.png", FIRE1);
        tm->fromFile("tilesets/flemmes2.png", FIRE2);
        tm->fromFile("tilesets/flemmes3.png", FIRE3);
        getCache().addResourceManager(*tm, "TextureManager");
    }
    void init () {
        addClock(realTime, "RealTime");
        TextureManager<TEXTURES> &tm = getCache().resourceManager<sf::Texture, TEXTURES>("TextureManager");
        View view = getWindow().getDefaultView();
        view.setCenter(0, 0);
        Vec2f pos (view.getCenter().x - view.getSize().x * 0.5f, view.getCenter().y - view.getSize().y * 0.5f);
        BoundingRectangle rect (pos.x, pos.y, view.getSize().x, view.getSize().y);
        theMap = new Map (100, 50, 30, "Map test");
        eu = new EntitiesUpdater(theMap, rect);
        eu->launch();
        au = new AnimUpdater(theMap, rect);
        au->setInterval(seconds(0.01f));
        au->start();
        std::vector<Tile*> tiles;
        std::vector<Tile*> walls;
        tiles.push_back(new Tile(tm.getResourceByAlias(GRASS), Vec2f(0, 0), Vec2f(120, 60),IntRect(0, 0, 100, 50), 0));
        walls.push_back(new Tile(tm.getResourceByAlias(WALLS), Vec2f(0, 0), Vec2f(100, 100), IntRect(100, 0, 100, 100), 1));
        walls.push_back(new Tile(tm.getResourceByAlias(WALLS), Vec2f(0, 0), Vec2f(100, 100), IntRect(100, 100, 100, 100), 1));
        walls.push_back(new Tile(tm.getResourceByAlias(WALLS), Vec2f(0, 0), Vec2f(100, 100), IntRect(100, 200, 100, 100), 1));
        walls.push_back(new Tile(tm.getResourceByAlias(WALLS), Vec2f(0, 0), Vec2f(100, 100), IntRect(100, 300, 100, 100), 1));
        walls.push_back(new Tile(tm.getResourceByAlias(WALLS), Vec2f(0, 0), Vec2f(100, 100), IntRect(100, 400, 100, 100), 1));
        walls.push_back(new Tile(tm.getResourceByAlias(WALLS), Vec2f(0, 0), Vec2f(100, 100), IntRect(100, 500, 100, 100), 1));
        BoundingRectangle mapZone(0, 0, 1000, 1000);
        theMap->generate_map<TEXTURES>(tiles, walls, mapZone);
        Decor* decor = new Decor(new Tile(tm.getResourceByAlias(HOUSE), Vec2f(0, 0), Vec2f(250, 300), IntRect(0, 0, 250, 300), 2), AmbientLight::getAmbientLight());
        decor->setPosition(Vec2f(100, 100));
        decor->setShadowCenter(Vec2f(0, 60));
        decor->changeGravityCenter(Vec2f(50, 50));
        theMap->addEntity<TEXTURES>(decor);
        PonctualLight* light = new PonctualLight(Vec2f(50, 150),100,50,0,200,sf::Color(255,255,0),16,0);
        theMap->addEntity<TEXTURES>(light);
        Anim* fire = new Anim(0.1f, Vec2f(0, 100), Vec2f(100, 100), 2);
        Decor *fire1 = new Decor(new Tile(tm.getResourceByAlias(FIRE1), Vec2f(0, 100), Vec2f(100, 100), IntRect(0, 0, 150, 200), 2), AmbientLight::getAmbientLight());
        Decor *fire2 = new Decor(new Tile(tm.getResourceByAlias(FIRE2), Vec2f(0, 100), Vec2f(100, 100), IntRect(0, 0, 150, 200), 2), AmbientLight::getAmbientLight());
        Decor *fire3 = new Decor(new Tile(tm.getResourceByAlias(FIRE3), Vec2f(0, 100), Vec2f(100, 100), IntRect(0, 0, 150, 200), 2), AmbientLight::getAmbientLight());
        fire1->setShadowCenter(Vec2f(80, 100));
        fire2->setShadowCenter(Vec2f(80, 100));
        fire3->setShadowCenter(Vec2f(80, 100));
        fire1->changeGravityCenter(Vec2f(50, 50));
        fire2->changeGravityCenter(Vec2f(50, 50));
        fire3->changeGravityCenter(Vec2f(50, 50));
        fire->addEntity(fire1);
        fire->addEntity(fire2);
        fire->addEntity(fire3);
        fire->play(true);
        theMap->addEntity<TEXTURES>(fire);
        au->addAnim(fire);
        Tile *t = new Tile(walls[3]->getTexture(), walls[3]->getPosition(), walls[3]->getSize(), walls[3]->getTextureRect(),3);
        w = new Wall(3, 80, t,AmbientLight::getAmbientLight());
        w->setPosition (Vec2f (0, 130));

        theMap->addEntity<TEXTURES>(w);
        caracter = new Caracter("Sorrok", "Nagi", "M", "Map test", "Brain", "Green", "White","Normal","Novice", 1);
        std::string path = "tilesets/tilesetnovice.png";
        getCache().resourceManager<sf::Texture, TEXTURES>("TextureManager").fromFile(path);
        const Texture *text = getCache().resourceManager<sf::Texture, TEXTURES>("TextureManager").getResourceByPath(path);
        int textRectX = 0, textRectY = 0, textRectWidth = 50, textRectHeight = 100;
        int textWidth = text->getSize().x;
        int textHeight = text->getSize().y;
        for (unsigned int i = 0; i < 24; i+=3) {
            Anim* animation = new Anim(0.1f, Vec2f(0, 0), Vec2f(50, 100), 0);
            for (unsigned int  j = 0; j < 3; j++) {
                IntRect textRect (textRectX, textRectY, textRectWidth, textRectHeight);
                Tile *tile = new Tile(text, Vec2f(0, 0), Vec2f(textRectWidth, textRectHeight), textRect, 0);
                Decor *decor = new Decor(tile, odfaeg::AmbientLight::getAmbientLight());
                decor->setShadowCenter(Vec2f(80, 130));
                decor->changeGravityCenter(Vec2f(50, 50));
                textRectX += textRectWidth;
                if (textRectX + textRectWidth > textWidth) {
                    textRectX = 0;
                    textRectY += textRectHeight;
                }
                animation->addEntity(decor);
            }
            caracter->addAnimation(animation);
            au->addAnim(animation);
        }
        theMap->addEntity<TEXTURES>(caracter);
        theMap->computeIntersectionsWithWalls();
        renderTextShadows = new RenderTexture();
        renderTextShadows->create(view.getSize().x, view.getSize().y);
        renderTextLights = new RenderTexture();
        renderTextLights->create(view.getSize().x, view.getSize().y);
        renderTextShadows->setView(view);
        renderTextLights->setView(view);
        MemberFunction<void(MyAppli*)> f1 (&MyAppli::close);
        closedAction = new ActionMap(f1, this);
        Action *a = new Action(Action::EVENT_TYPE::CLOSED);
        closedAction->addAction(a);
        MemberFunction<void(MyAppli*, sf::Keyboard::Key, sf::Time)> b2 (&MyAppli::keyHeldDown);
        moveAction = new ActionMap(b2, this, sf::Keyboard::Key::Unknown, realTime.restart());
        Action *a1 = new Action (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::Z);
        Action *a2 = new Action (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::Q);
        Action *a3 = new Action (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::S);
        Action *a4 = new Action (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::D);
        Action *combined = new Action(*a1 || *a2 || *a3 || *a4);
        moveAction->addAction(combined);
        MemberFunction<bool(MyAppli*, sf::Vector2f)> trigFunc (&MyAppli::mouseInside);
        MemberFunction<void(MyAppli*, sf::Vector2f)> onTrigFunc(&MyAppli::onMouseInside);
        listener.connect("MouseInside", this, trigFunc, this, onTrigFunc, Vector2f(-1, -1));
        listener.connectAction("CloseAction", closedAction);
        listener.connectAction("MoveAction", moveAction);
        listener.listen();
        getWindow().setView(view);
        eu->update();
    }
    void render() {
        if (getWindow().isOpen())
        {
            // clear the window with black color
            getWindow().clear(sf::Color::Black);
            std::vector<Entity*> entities = theMap->getVisibleEntities("E_TILE");// draw everything here...

            for (unsigned int i = 0; i < entities.size(); i++) {
                    getWindow().draw(*entities[i]);
            }
            entities = theMap->getVisibleEntities("E_WALL+E_DECOR+E_ANIMATION+E_CARACTER");
            renderTextShadows->clear(Color::White);
            for (unsigned int i = 0; i < entities.size(); i++) {
                if (entities[i]->getType() == "E_SHADOW_WALL" || entities[i]->getType() == "E_SHADOW_TILE") {
                    renderTextShadows->draw(*entities[i]);
                }
            }
            View view = getWindow().getView();
            Vector2f v2 (view.getCenter().x - view.getSize().x * 0.5f, view.getCenter().y - view.getSize().y * 0.5f);
            rect.setPosition(Vector2f(v2.x, v2.y));
            rect.setFillColor((Color(100, 100, 100, 128)));
            rect.setSize(Vector2f (view.getSize().x, view.getSize().y));
            renderTextShadows->draw(rect, RenderStates(BlendAdd));
            renderTextShadows->display();
            Sprite shadows (renderTextShadows->getTexture());
            shadows.setPosition(v2.x, v2.y);
            getWindow().draw (shadows, RenderStates(BlendMultiply));
            for (unsigned int i = 0; i < entities.size(); i++) {
                if (entities[i]->getType() == "E_TILE")
                    getWindow().draw(*entities[i]);
            }
            for (int n = 0; n < w->getSegments().size(); n++) {
                 Segment *s = w->getSegments()[n];
                 VertexArray line(Lines, 2);
                 Vertex origin, ext;
                 origin.position = Vector2f (s->getOrig().x, s->getOrig().y);
                 ext.position = Vector2f(s->getExt().x, s->getExt().y);
                 origin.color = Color(255,0,0);
                 ext.color = Color(255, 0, 0);
                 line.append(origin);
                 line.append(ext);
                 getWindow().draw(line);
            }
            AmbientLight::getAmbientLight()->setColor(Color(255, 255, 255));
            Color ambientColor = AmbientLight::getAmbientLight()->getColor();
            renderTextLights->clear(ambientColor);
            entities = theMap->getVisibleEntities("E_PONCTUAL_LIGHT");
            for (unsigned int i = 0; i < entities.size(); i++) {
                renderTextLights->draw(*entities[i], BlendAdd);
            }
            renderTextLights->display();
            Sprite lights (renderTextLights->getTexture());
            lights.setPosition(v2.x, v2.y);
            getWindow().draw(lights, BlendMultiply);
            // end the current frame
            getWindow().display();
        }
        realTime.restart();
    }
    void update () {
        // check all the window's events that were triggered since the last iteration of the loop

        sf::Event event;
        if (getWindow().pollEvent(event))
        {
            listener.pushEvent(event);
            if (event.type == sf::Event::Closed) {

                running =false;
            }
            if (event.type == sf::Event::KeyPressed) {
                previousKey = actualKey;
                actualKey = event.key.code;
                listener.setActionParams<MyAppli, sf::Keyboard::Key, sf::Time>("MoveAction", this, event.key.code,realTime.restart());

            }
            if (event.type == sf::Event::KeyReleased) {
                caracter->setMoving(false);
                previousKey = event.key.code;
                actualKey = sf::Keyboard::Key::Unknown;
            }
            if (event.type == sf::Event::MouseMoved) {
                Vector2f mousePos = Vector2f(event.mouseMove.x, event.mouseMove.y);
                listener.setParams<MyAppli, MyAppli, Vector2f> ("MouseInside", this, this, mousePos);

            }
        }
    }
    void stop() {
        running = false;
    }
    int exec () {
        load();
        init();
        running = true;
        while (running) {
            render();
            update();
        }
        return EXIT_SUCCESS;
    }

    ~MyAppli () {

    }

};

#endif // MY_APPLI
 

And the carater which is a custom entity :
#include "caracter.h"

using namespace std;
using namespace sf;
Caracter::Caracter (string factionName, string pseudo, string sex, string currentMapName, string hairColor,
                  string eyesColor, string skinColor, string faceType, string classs, int level) : AnimatedEntity (Vec2f(-50, -25), Vec2f (100, 50), Vec2f(50, 25), 0, "E_CARACTER") {
    currentAnimIndex = 0;
    this->factionName = factionName;
    this->pseudo = pseudo;
    this->sex = sex;
    this->currentMapName = currentMapName;
    this->hairColor = hairColor;
    this->eyesColor = eyesColor;
    this->faceType = faceType;
    this->skinColor = skinColor;
    this->classs = classs;
    this->level = level;
    currentPointIndex = 0;
    speed = 100;
    moving = false;
    dir = Vec2f(0, 1);
    this->life = 100;
    this->maxLife = 100;
    range = 50;
    attackSpeed = 1.f;
    attack = 10;
    fightingMode = attacking = false;
    alive = true;
    xp = 0;
    xpReqForNextLevel = 1500;
    regenHpSpeed = 1.f;
    regenHpAmount = 1;
}
void Caracter::onMove(Vec2f& d) {
    for (unsigned int i = 0; i < anims.size(); i++) {
        anims[i]->move(d);
    }
}
float Caracter::getRegenHpSpeed () {
    return regenHpSpeed;
}
void Caracter::setRegenHpSpeed(float regenHpSpeed) {
    this->regenHpSpeed = regenHpSpeed;
}
Time Caracter::getTimeOfLastHpRegen() {
    return clockRegenHp.getElapsedTime();
}
void Caracter::setLevel(int level) {
    this->level = level;
}
void Caracter::setCurrentXp(int xp) {
    this->xp = xp;
}
void Caracter::setXpReqForNextLevel(int xpReqForNextLevel) {
    this->xpReqForNextLevel = xpReqForNextLevel;
}
void Caracter::up (int xp) {
    this->xp += xp;
    if (this->xp >= xpReqForNextLevel) {
        level++;
        this->xp = this->xp - xpReqForNextLevel;
        xpReqForNextLevel *= 2;
    }
}
int Caracter::getCurrentXp () {
    return xp;
}
int Caracter::getXpReqForNextLevel () {
    return xpReqForNextLevel;
}
void Caracter::setSpeed(int speed) {
    this->speed;
}
int Caracter::getSpeed() {
    return speed;
}
int Caracter::getRegenHpAmount() {
    return regenHpAmount;
}
void Caracter::setRegenHpAmount(int regenHpAmount) {
    this->regenHpAmount = regenHpAmount;
}
void Caracter::setLife(int life) {
    this->life = life;
    clockRegenHp.restart();
}
int Caracter::getLife() {
    return life;
}
void Caracter::setRange(int range) {
    this->range = range;
}
int Caracter::getRange() {
    return range;
}
void Caracter::setAttackSpeed (float attackSpeed) {
    this->attackSpeed = attackSpeed;
}
float Caracter::getAttackSpeed () {
    return attackSpeed;
}
void Caracter::setAttacking(bool b) {

    this->attacking = b;
}
void Caracter::setAlive(bool b) {
    alive = b;
}
bool Caracter::isAlive () {
    return alive;
}
bool Caracter::isAttacking() {
    return attacking;
}
void Caracter::setFightingMode(bool b) {
    this->fightingMode = b;
}
bool Caracter::operator== (Entity &other) {
    if (getType() != other.getType())
        return false;
    Caracter& caracter = static_cast<Caracter&>(other);
    if (anims.size() != caracter.anims.size())
        return false;
    for (unsigned int i = 0; i < anims.size(); i++) {
        if (anims[i] != caracter.anims[i])
            return false;
    }
    return true;
}
bool Caracter::isInFightingMode() {
    return fightingMode;
}
void Caracter::setAttack(int attack) {
    this->attack = attack;
}
int Caracter::getAttack() {
    return attack;
}

Time Caracter::getTimeOfLastAttack() {
    return clockAtkSpeed.getElapsedTime();
}

void Caracter::setDir (Vec2f dir) {
    anims[currentAnimIndex]->setCurrentTile(0);
    float angleRadians = const_cast<Vec2f&>(Vec2f::yAxis).getAngleBetween(dir);
    int angle = Math::toDegrees(angleRadians);
    //Sud
    if (angle >= -10 && angle <= 10)
        currentAnimIndex = 0;
    //Sud ouest
    else if (angle > -80 && angle < -10)
        currentAnimIndex = 3;
    //Ouest
    else if (angle >= -100 && angle <= -80)
        currentAnimIndex = 6;
    //Nord ouest
    else if (angle > -170 && angle < -100)
        currentAnimIndex = 1;
    //Nors est
    else if (angle > 100 && angle < 170)
        currentAnimIndex = 7;
    //Est
    else if (angle >= 80 && angle <= 100)
        currentAnimIndex = 2;
    //Sud est
    else if (angle > 10 && angle < 80)
        currentAnimIndex = 5;
    else
        currentAnimIndex = 4;

    if (attacking)
        currentAnimIndex += 8;
    this->dir = dir;
}

Vec2f Caracter::getDir () {
    return dir;
}
void Caracter::setMoving (bool b) {
    this->moving = b;
    if (moving) {
        anims[currentAnimIndex]->play(true);
    } else {
        anims[currentAnimIndex]->stop();
        anims[currentAnimIndex]->setCurrentTile(0);
    }

}
bool Caracter::isMoving () {
    return moving;
}

Vec2f Caracter::getPosition () {
    return anims[currentAnimIndex]->getPosition();
}

void Caracter::setPath(vector<Vec2f> path) {
    this->path = path;
}
vector<Vec2f> Caracter::getPath() {
    return path;
}
void Caracter::addAnimation (Anim *anim) {
    anims.push_back(anim);
}
Anim* Caracter::getAnimation(int index) {
    if (index >= 0 && index < anims.size())
        return anims[index];
    return NULL;
}
unsigned int Caracter::getCurrentPathIndex() {
    return currentPointIndex;
}
void Caracter::setCurrentPathIndex (unsigned int currentPointIndex) {
    this->currentPointIndex = currentPointIndex;
}

void Caracter::setMaxLife(int life) {
    this->maxLife = maxLife;
}

int Caracter::getMaxLife() {
    return maxLife;
}
int Caracter::getLevel() {
    return level;
}
string Caracter::getClass () {
    return classs;
}
void Caracter::onDraw(sf::RenderTarget &target, sf::RenderStates states) const {
    target.draw(*getCurrentEntity(), states);
}
Entity* Caracter::getCurrentEntity() {
    return anims[currentAnimIndex]->getCurrentEntity();
}
Caracter::~Caracter() {

}

 

In the main we just have to do this :
#include <iostream>
#include "myApplication.h"
using namespace odfaeg;
using namespace sf;
int main () {
    sf::RenderWindow window (sf::VideoMode(800, 600), "ODFAEG DEMO");
    MyAppli appli (window);
    return appli.exec();
}
 

Screenshot and movies are coming! (I'll include some tilesets and a demo on the git-hub repository as soon as possible)



Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #38 on: February 18, 2014, 12:43:50 pm »
Finally, the first release'll be probably for april, I've still a lot of thing to do before launching a real optimized framework :


-The main is that I've to change the signal class to support also std::functions and I'll try to make only one class to store every type of functions so the signal class'll be renamed as "delegate".

Because it's exactly what I'm trying to do.

The delegate class'll store the right pointer to the object (if it's a member function), and function parameters.

I'll improve it to store also an object of type std::function.

And when we'll invoke the function it'll invoke the right function pointer.

I've read this article and it's seems to be a very interessant article! (More interessant than the std::function mechanism execpts that I've to depend on std::function if I want to store pointer to lambda functions, I don't know how to alocate a function pointer with c++ I even don't know if it's possible to do something like this :

Function<void()> ptreFunc(new void(){});
 

But apparently it isn't possible so I checked this article :

http://msdn.microsoft.com/en-us/library/c320cx3h.aspx

And I had a new idea.

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #39 on: February 18, 2014, 07:02:08 pm »
And another article which explain why deleguates rocks and why using them instead of std::function.
I mention that because many of you adviced me to use std::function.

http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible

And curiously I had the same idea, but I had to reimplement that which variadic templates. (because he didn't use them)

The heavy part is that we must define a template specialisation for each type of function :

-Non member function. (With and without return type)
-Normal or static function.(With and without return type)

It makes already 4 specialisations.

And there are of course other specialisation for lambda functions. (If I want that my delegate system support them...)

It makes 8 differents template specialisations...

If everyone have the same source code but with varaidic template and whiwh support also lamba functions, I'm very interested!

therocode

  • Full Member
  • ***
  • Posts: 125
    • View Profile
    • Development blog
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #40 on: February 19, 2014, 07:58:13 am »
That seems to include a lot of complications and workarounds for just the tradeoffs of a bit of performance over the otherwise very flexible std::function.

Sure, in certain cases where performance is very crucial, such approaches can be worth it, but have you actually measured the std::function solution to be a bad performance bottleneck in your project? If not (and I doubt it would be) then it seems to me like a bad approach to introduce that complexity for practically not really any gain.

What you are trying to achieve kind of sounds like a messaging system and if that is what you want to do, then you can also get away by having pointers not to functions, but to objects, and then call a method on them directly which depending on what you want to do, might be more reasonable.

But key point is: Never sacrifice simplicity over complexity for performance reasons that are not measured or known from experience.

panithadrum

  • Sr. Member
  • ****
  • Posts: 304
    • View Profile
    • Skyrpex@Github
    • Email
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #41 on: February 19, 2014, 08:40:07 am »
Totally agree with the user above. Always go for simplicity unless you can't for crucial reasons.

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #42 on: February 19, 2014, 11:14:57 am »
Yeah this code seems to be ve very complex, I've downloaded the source because it's a bit project and I really need performance.

I use this for a messaging system. (When a function (a signal) return true I call another function (a slot) and I store signal and slot parameters into the delegate class. (Later I eventwould like to have a place holder system with the tuples)

But I want to do this with any kind of function (std::function, ...) so i've created a template class with encapsulate all function type and an object if they are member functions, and I store them into a class wich call a callback function to invoke each type of functions.
#ifndef PLACE_HOLDERS_H
#define PLACE_HOLDERS_H
#include <functional>
#include "function.h"
namespace odfaeg {

template <typename R, typename O, typename ...A> R callback (MemberFunction<R(O*, A...)> func, O* object, A... args) {
    return func(object, args...);
}
template <typename R, typename ...A> R callback(Function<R(A...)> func, A... args) {
    return func(args...);
}
template <typename R, typename O, typename ...A> R callback (std::function<R(O*, A...)> func, O* object, A... args) {
    return func(object, args...);
}
template <typename R, typename ...A> R callback(std::function<R(A...)> func, A... args) {
    return func(args...);
}
template <class T> class DelegatePrototype {
    public :
    virtual bool operator== (T& other) const = 0;
};
class Delegate : public DelegatePrototype<Delegate> {
    public :
    virtual void operator()() = 0;
    virtual bool hasReturn() const = 0;
};
template <typename R, typename O, typename ...A> class FastDelegate3 : public Delegate {
        friend class FastDelegate;
        FastDelegate3 (R(O::*func)(A...) ,O* object) {
            typedef R(*CB)(MemberFunction<R(O*, A...)>, O*, A...);
            CB cb = &callback;
            funct = new Functor<R(MemberFunction<R(O*, A...)>, O*, A...)> (cb, MemberFunction<R(O*, A...)>(func), object);
        }
        void setParams (A... args) {

            params = std::make_tuple (args...);
        }
        void operator()() {
             ret = (*funct)(params);
        }
        R getReturn () {
            return ret;
        }
        bool operator== (Delegate& other) const {

            if (&dynamic_cast<FastDelegate3<R, O, A...>&>(other) == nullptr) {
                return false;
            }
            FastDelegate3<R, O, A...>& delegate3 = dynamic_cast<FastDelegate3<R, O, A...>&>(other);
            return *funct == *(delegate3.funct);
        }
        bool hasReturn() const {
            return true;
        }
        std::tuple<A&&...> params;
        Functor<R(MemberFunction<R(O*, A...)>, O*, A...)> *funct;
        R ret;
};
template <typename O, typename ...A> class  FastDelegate2 : public Delegate {
        friend class FastDelegate;
        FastDelegate2 (void(O::*func)(A...), O* object)  {
            typedef void(*CB)(MemberFunction<void(O*, A...)>, O*, A...);
            CB cb = &callback;
            funct = new Functor<void(MemberFunction<void(O*, A...)>, O*, A...)> (cb, MemberFunction<void(O*, A...)>(func), object);

        }
        void setParams (A&&... args) {
            params = std::make_tuple (args...);
        }
        void operator()() {
            (*funct)(params);
        }
        bool operator== (Delegate& other) const {
            if (&dynamic_cast<FastDelegate2<O, A...>&>(other) == nullptr) {
                return false;
            }
            FastDelegate2<O, A...>& delegate2 = dynamic_cast<FastDelegate2<O, A...>&>(other);
            return *funct == *(delegate2.funct);
        }
        bool hasReturn() const {
            return false;
        }
        std::tuple<A...> params;
        Functor<void(MemberFunction<void(O*, A...)>, O*, A...)> *funct;
};
template <typename ...A> class FastDelegate0 : public Delegate {
        friend class FastDelegate;
        FastDelegate0 (void(*f)(A...), A... args) {
            typedef void(*CB)(Function<void(A...)>, A...);
            CB cb = &callback;
            funct = new Functor<void(Function<void(A...)>, A...)> (cb, Function<void(A...)>(f), args...);
            params = std::make_tuple (args...);
        }
        void setParams (A... args) {

            params = std::make_tuple (args...);
        }
        void operator()() {
             (*funct)(params);
        }
        bool operator== (Delegate& other) const {

            if (&dynamic_cast<FastDelegate0<A...>&>(other) == nullptr) {
                return false;
            }
            FastDelegate0<A...>& delegate0 = dynamic_cast<FastDelegate0<A...>&>(other);
            return *funct == *(delegate0.funct);
        }
        bool hasReturn() const {
            return false;
        }

        std::tuple<A...> params;
        Functor<void(Function<void(A...)>, A...)> *funct;
};
template <typename R, typename ...A> class FastDelegate1 : public Delegate {
        friend class FastDelegate;
        FastDelegate1 (Function<R(A...)> func, A... args) {
            typedef R(*CB)(Function<R(A...)>, A...);
            CB cb = &callback;
            funct = new Functor<R(Function<R(A...)>, A...)> (cb, func);
            params = std::make_tuple (args...);
        }
        void setParams (A... args) {

            params = std::make_tuple (args...);
        }
        void operator()() {
             ret = (*funct)(params);
        }
        R getReturn () {
            return ret;
        }
        bool operator== (Delegate& other) const {

            if (&dynamic_cast<FastDelegate1<R, A...>&>(other) == nullptr) {
                return false;
            }
            FastDelegate0<R, A...>& delegate1 = dynamic_cast<FastDelegate1<R, A...>&>(other);
            return *funct == *(delegate1.funct);
        }
        bool hasReturn() const {
            return true;
        }

        std::tuple<A&&...> params;
        Functor<R(Function<R(A...)>, A...)> *funct;
        R ret;
};
class FastDelegate {
    public :
    FastDelegate () {

    }
    template <typename R, typename O, typename ...A> FastDelegate(R(O::*f)(A...), O* object) {
        delegate = new FastDelegate3<R, O, A...>(f, object);
    }
    template <typename O, typename ...A> FastDelegate(void(O::*f)(A...), O* object) {
        delegate = new FastDelegate2<O, A...>(f, object);
    }
    template <typename R, typename ...A> FastDelegate(void(*f)(A...)) {
        delegate = new FastDelegate1<R , A...>(f);
    }

    template <typename ...A> FastDelegate(void(*f)(A...), A... args) {
        delegate = new FastDelegate0<A...>(f,args...);
    }
    template<typename ...A> void* operator()(A... args) {
        if (static_cast<FastDelegate0<A...>*>(delegate)) {
            static_cast<FastDelegate0<A...>*>(delegate)->setParams(args...);
        }
        return (*delegate)();
    }
    template<typename R, typename ...A> R operator()(A... args) {
        if (static_cast<FastDelegate1<R, A...>*>(delegate)) {
            static_cast<FastDelegate1<R, A...>*>(delegate)->setParams(args...);
        }
        (*delegate)();
        return static_cast<FastDelegate1<R, A...>*>(delegate)->getReturn();
    }
    template<typename O, typename ...A> void* operator()(O* object, A... args) {
        if (static_cast<FastDelegate2<O, A...>*>(delegate)) {
            static_cast<FastDelegate2<O, A...>*>(delegate)->setParams(object, args...);
        }
        (*delegate)();
    }
    template<typename R, typename O, typename ...A> R operator()(O* object, A... args) {
        if (static_cast<FastDelegate3<R, O, A...>*>(delegate)) {
            static_cast<FastDelegate3<R, O, A...>*>(delegate)->setParams(object, args...);
        }
        (*delegate)();
        return static_cast<FastDelegate3<R, O, A...>*>(delegate)->getReturn();
    }
    template<typename R> R operator()() {
        return (*delegate)();
    }
    void* operator()() {
        (*delegate)();
    }
    template<typename ...A> void setParams(A... args) {
        if (static_cast<FastDelegate0<A...>*>(delegate)) {
            static_cast<FastDelegate0<A...>*>(delegate)->setParams(args...);
        }
    }
    template<typename R, typename ...A> void setParams(A... args) {
        if (static_cast<FastDelegate1<R, A...>*>(delegate)) {
            static_cast<FastDelegate1<R, A...>*>(delegate)->setParams(args...);
        }
    }
    template<typename O, typename ...A> void setParams(O* object, A... args) {
        if (static_cast<FastDelegate2<O, A...>*>(delegate)) {
            static_cast<FastDelegate2<O, A...>*>(delegate)->setParams(object, args...);
        }
    }
    template<typename R, typename O, typename ...A> void setParams(O* object, A... args) {
        if (static_cast<FastDelegate3<R, O, A...>*>(delegate)) {
            static_cast<FastDelegate3<R, O, A...>*>(delegate)->setParams(object, args...);
        }
    }
    bool operator==(FastDelegate &other) {
        return *delegate == *other.delegate;
    }
private :
    Delegate* delegate;
};
}
#endif // PLACE_HOLDERS_H

 


I looked for this article to do do it work with inheritance, if I've a base class and derivated components for exemple. (Because it doens't work in this case)

funclist[6] = FastDelegate(&CBaseClass::SimpleVirtualFunction, &d);
 

Because CBaseClasse::SimpleVirtualFunction and d aren't in the same class, d is an objectwhiwh derive from the CBaseClass.
But this forum is certainly no appropriate to discuss about low level programming so I think I'll check for another one.




Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #43 on: February 19, 2014, 11:58:32 am »
My game/lib developer point of view :

I really need performance.

I highly doubt you need such things... If your framework make the game to drop below 60fps, that's not std::function fault. If it does not, then you don't need to worry about optimisations and performances (well, not too much)

Plus, let me doubt that you own implementation of std::function is so much better than a feature that has been developped by the best C++ programmerS across the world for many years now (because it was in gestation in boost for years before being added to c++, just as well as nearly all other c++ features that were added in c++11).

I agree with my mates above that said you're not looking for the simplest way to do your messaging system or whatever your doing.


My lib user point of view :

Your example code looks too massive. It doesn't make me feel comfortable in using your framework. Indeed if I use a lib I like to do minimal things. Here you have 25 lines of code to init/declare things at the same place, you are handling events at the same place, etc.
I would like to have actions, just like Thor, that are linked to some kind of event/messaging system and are triggered automatically. I don't want to make my movements actions in raw in the handleEvents(), imagine the size it will be when I will have to handle at least 50 different entities ? (I don't even see how that's possible).

You tend to present the code inside the black box, but what the user want to see is the exposed API. He generally doesn't care how things are implemented. Try to present some more things about the API, that we can have an idea about what your framework look/will look like.

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #44 on: February 19, 2014, 01:02:59 pm »
I've find a solution which works and which is less complex, you can so define every type of pointer to functions (and it works also if you pass derived objects to a pointer to a function member. ;))

#include <stdio.h>
#include "ODFAEG/Core/signal.h"
// Demonstrate the syntax for FastDelegates.
//                              -Don Clugston, May 2004.
// It's a really boring example, but it shows the most important cases.

// Declare some functions of varying complexity...
using namespace odfaeg;
void SimpleStaticFunction(int num, char *str) {
        printf("In SimpleStaticFunction. Num=%d, str = %s\n", num, str);
}

void SimpleVoidFunction() {
        printf("In SimpleVoidFunction with no parameters.\n");
}

class CBaseClass {
protected:
        char *m_name;
public:
        CBaseClass(char *name) : m_name(name) {};
        void SimpleMemberFunction(int num, char *str) {
                printf("In SimpleMemberFunction in %s. Num=%d, str = %s\n", m_name, num, str);  }
        int SimpleMemberFunctionReturnsInt(int num, char *str) {
                printf("In SimpleMemberFunction in %s. Num=%d, str = %s\n", m_name, num, str); return -1;       }
        void ConstMemberFunction(int num, char *str) const {
                printf("In ConstMemberFunction in %s. Num=%d, str = %s\n", m_name, num, str);   }
        virtual void SimpleVirtualFunction(int num, char *str) {
                printf("In SimpleVirtualFunction in %s. Num=%d, str = %s\n", m_name, num, str); }
        static void StaticMemberFunction(int num, char *str) {
                printf("In StaticMemberFunction. Num=%d, str =%s\n", num, str); }
};

class COtherClass {
        double rubbish; // to ensure this class has non-zero size.
public:
        virtual void UnusedVirtualFunction(void) { }
        virtual void TrickyVirtualFunction(int num, char *str)=0;
};

class VeryBigClass {
        int letsMakeThingsComplicated[400];
};

// This declaration ensures that we get a convoluted class heirarchy.
class CDerivedClass : public VeryBigClass, virtual public COtherClass, virtual public CBaseClass
{
        double m_somemember[8];
public:
        CDerivedClass() : CBaseClass("Base of Derived") { m_somemember[0]=1.2345; }
        void SimpleDerivedFunction(int num, char *str) { printf("In SimpleDerived. num=%d\n", num); }
        virtual void AnotherUnusedVirtualFunction(int num, char *str) {}
        virtual void TrickyVirtualFunction(int num, char *str) {
                printf("In Derived TrickyMemberFunction. Num=%d, str = %s\n", num, str);
        }
};



int main(void)
{
        // Delegates with up to 8 parameters are supported.
        // Here's the case for a void function.
        // We declare a delegate and attach it to SimpleVoidFunction()
        printf("-- FastDelegate demo --\nA no-parameter delegate is declared using FastDelegate0\n\n");

        FastDelegate noparameterdelegate(&SimpleVoidFunction);

        noparameterdelegate(); // invoke the delegate - this calls SimpleVoidFunction()

        printf("\n-- Examples using two-parameter delegates (int, char *) --\n\n");

    // By default, the return value is void.
    FastDelegate MyDelegate;

        // If you want to have a non-void return value, put it at the end.
    FastDelegate newdeleg;


        FastDelegate funclist[12]; // delegates are initialized to empty
        CBaseClass a("Base A");
        CBaseClass b("Base B");
        CDerivedClass d;
        CDerivedClass c;

        newdeleg = FastDelegate(&CBaseClass::SimpleMemberFunctionReturnsInt, &a);

        // Binding a simple member function
        funclist[0] = FastDelegate(&CBaseClass::SimpleMemberFunction, &a);

        // You can also bind static (free) functions
        funclist[1] = FastDelegate (&SimpleStaticFunction);
        // and static member functions
        funclist[2] = FastDelegate (&CBaseClass::StaticMemberFunction);
        // and const member functions (these only need a const class pointer).
        //funclist[11] = FastDelegate (&CBaseClass::ConstMemberFunction, (const CBaseClass *)&a);
        funclist[3] = FastDelegate( &CBaseClass::ConstMemberFunction, &a);
        // and virtual member functions
        funclist[4] = FastDelegate(&CBaseClass::SimpleVirtualFunction, &b);

        // You can also use the = operator. For static functions, a fastdelegate
        // looks identical to a simple function pointer.
        funclist[5] = FastDelegate(&CBaseClass::StaticMemberFunction);

        // The weird rule about the class of derived member function pointers is avoided.
        // For MSVC, you can use &CDerivedClass::SimpleVirtualFunction here, but DMC will complain.
        // Note that as well as .bind(), you can also use the MakeDelegate()
        // global function.
        funclist[6] = FastDelegate(&CBaseClass::SimpleVirtualFunction, &d);

        // The worst case is an abstract virtual function of a virtually-derived class
        // with at least one non-virtual base class. This is a VERY obscure situation,
        // which you're unlikely to encounter in the real world.
        // FastDelegate versions prior to 1.3 had problems with this case on VC6.
        // Now, it works without problems on all compilers.
       funclist[7] = FastDelegate(&CDerivedClass::TrickyVirtualFunction, &c);
        // BUT... in such cases you should be using the base class as an
        // interface, anyway.
       funclist[8] = FastDelegate(&COtherClass::TrickyVirtualFunction, &c);
        // Calling a function that was first declared in the derived class is straightforward
        funclist[9] = FastDelegate(&CDerivedClass::SimpleDerivedFunction, &c);

        // You can also bind directly using the constructor
        FastDelegate dg = FastDelegate(&CBaseClass::SimpleVirtualFunction, &b);

        char *msg = "Looking for equal delegate";
        for (int i=0; i<12; i++) {
                printf("%d :", i);
                // The == and != operators are provided
                // Note that they work even for inline functions.
                if (funclist[i]==dg) { msg = "Found equal delegate"; };
                // operator ! can be used to test for an empty delegate
                // You can also use the .empty() member function.
                if (!funclist[i]) {
                        printf("Delegate is empty\n");
                } else {
                        // Invocation generates optimal assembly code.
                        funclist[i](i, msg);
                };
        }
        return 0;
}

 

So know you'll be able to connect every kind of function pointers to an action. :) (Static/normal function or members function (even const member function) or lamba expressions, and pass the object and the arguments at different execution times to call the function)

You just need to instanciate an object of type FastDelegate and pass it a pointer to a function (or a lambda expression) and the parameters. (And there is only one object type to build every kind of function and later you'll also be able to pass placeholders at the FastDelegate object initialisation)
This make the code very more simple to use. (And you don't have to worry about the type of the function pointer and you can strore everything because the type isn't unspecified like the std::bind class.

You talek about the thor::action system but the thor::action system of thor is not sufficient, imagine that you have to click in a button you'll have to define a thor::action for each pixel of the button.

So you need to define a trigger function which'll return true if the mouse is in the button. (when the left mouse button is pressed)
So you need to connect a trigger function with'll invoke a slot when an sf::Event is generated.

This is exactly why I need this system. :)

I'm sure that recent language like java are using a trick like this to call the functions of their interfaces when an event is triggered.








« Last Edit: February 19, 2014, 01:04:46 pm by Lolilolight »