Attention!!!Les liens vers les tutoriels ne sont plus à jour, donc, je fournirai un tutoriel au format word que j'inclurer dans le git-hub. (Je pense que tout le monde peut lire se format le cas échéant merci de me le signaler avant le 1er mars)
En effet, désormais, pour les entités animées, il ne sera plus nécessaire de faire autant de tests dans la boucle d'affichage ce qui alourdissait trop le code source, donc, j'ai optimisé le tout et désormais, seuls l'entité courante de l'animation est insérée dans le std::vector d'entités visible.
Et lorsque l'entité courante de l'animation change, l'entity system remets à jour l'entité courante visible de l'animation dans l'entity manager.
Ce qui permet de simplifier le code source :
getWindow().clear(sf::Color::Black);
std::vector<Entity*> entities = theMap->getVisibleEntities("E_GROUND");// draw the ground.
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]);
}
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();
Désormais dans la boucle d'évènement, on est plus obligé d'attendre que tout les événements SFML aient été traité avant de mettre à jour l'affichage grâce au listener, et grâce au entity system, la frame suivante est préparée dans un thread pendant que la frame courante s'affiche ce qui optimise le temps d'exécution :
sf::Event event;
if (getWindow().pollEvent(event))
{
listener.pushEvent(event);
if (event.type == sf::Event::Closed) {
running =false;
}
if (event.type == sf::Event::KeyPressed || event.type == sf::Event::KeyReleased) {
listener.setActionParams<MyAppli, sf::Keyboard::Key, sf::Time>("MoveAction", this, event.key.code,realTime.restart());
}
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 keyHeldDown (sf::Keyboard::Key key, sf::Time elapsedTime) {
sf::View view = getWindow().getView();
if (key == sf::Keyboard::Key::Z) {
view.move (0, -speed * elapsedTime.asSeconds());
} else if (key == sf::Keyboard::Key::Q) {
view.move (-speed* elapsedTime.asSeconds(), 0);
} else if (key == sf::Keyboard::Key::S) {
view.move (0, speed * elapsedTime.asSeconds());
} else if (key == sf::Keyboard::Key::D) {
view.move (speed * elapsedTime.asSeconds(), 0);
}
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();
}
Si la frame courante n'est pas prête à être affichée alors le thread courant est mis en pause jusqu'à ce que l'entity system aie fini d'update la frame courante ensuite a frame courante est affichée et la frame suivante se prépare en même temps.
Les entity system se charge de mettre tout à jour pour vous donc (les animations, et les entité visible pour la frame suivante à chaque fois que l'on déplace la vue), et le listener se charge de traiter les événements à chaque tour.
Désormais les entités animées peuvent être définie comme étant "movable" en redéfinissant la fonction isMovable de la classe AnimatedEntity.
Si l'entité est movable elle sera insérée dans le std::vector des entités visible de l'entity manager à chaque fois que l'on rendra la frame courante et non pas à chaque fois que l'entity system remettra à jour le std::vector des entités visible de l'entity manager.
En effet, contrairement aux animations statiques (C'est à dire les animations dont les entités ne bouge pas et ne font que de s'afficher les unes après les autres), la position en z des entités des animations dynamique tel que un personnage ou un monstre n'est pas connue à l'avance.(Les entités des animations d'un personnage peuvent être soit devant ou derrière un mur par exemple)
ODFAEG recherche donc toutes les entités qui sont derrière et devant l'entité movable, et l'insère au bonne endroit dans le std::vector juste avant que l'on veuille l'affiché l'entité movable. (Et donc précisément au moment ou l'on appelle la méthode getVisibleEntity de l'entity manager.)
Cette recherche est effectuée en fonction du centre de gravité de l'entité, par défaut c'est le centre des segments des entités, on peut le changer avec la fonction changeGravityCenter.
(Bien sûr le sol ne possède pas de centre de gravité, donc, cette recherche n'est pas faîtes pour les entités qui composent le sol)
Bref du lourd donc de prévu pour le 1er mars avec un premier système d'intelligence artificielle et d'xp.