arczi14 Temat założony przez niniejszego użytkownika |
[SFML] Dziedziczenie polimorficznej funkcji draw » 2015-07-17 19:29:03 Witam, (kod poniżej) Jak widać klasa SpriteEffect działa na zasadzie że dziedziczy funkcje wirtualną, która odpowiedzialna jest za aktualizacje stanu obiektu. Wszystko ładnie dodaje w klasie engine, która w pętli pobiera z kontenera kolejno obiekty i aktualizuje. Problem w tym, że nie mogę sobie poradzić aby w ten sam sposób utworzyć rysowanie. aby w main nie pisać osobno draw dla każdego obiektu tylko engine.draw(); który sam w pętli pobierze i wyświetli obiekty. Niestety nie wiem jak się za to zabrać w SFML funkcję wirtualną draw dziedziczy się z klasy sf::Drawable i sf::Transformable, niestety nie mam pojęcia w jaki sposób to połączyć w spójną całość. main: headers... sf::Vector2i size( 128, 128 ); SpriteEffect fire( "fire.png", size, sf::Vector2f( 100, 200 ), 27, SpriteEffect::Repeat, true ); SpriteEffect blood( "blood.png", size, sf::Vector2f( 500, 200 ), 24, SpriteEffect::Repeat, false );
System sys;
float accumulator = 0.0f; const float TIME_STEP = 0.016;
if( !sys.create() ) cout << "Something went wrong!";
sf::RenderWindow * WindowApp = sys.getHandle();
sf::Vector2i mouse; sf::Clock clock; Engine engine( * WindowApp );
engine.addObject( fire ); engine.addObject( light );
while( WindowApp->isOpen() ) { sf::Event event; mouse = sf::Mouse::getPosition( * WindowApp ); while( WindowApp->pollEvent( event ) ) { if( event.type == sf::Event::Closed ) WindowApp->close(); } accumulator += clock.restart().asSeconds(); while( accumulator >= TIME_STEP ) { engine.Update( TIME_STEP ); accumulator -= TIME_STEP; } WindowApp->clear( sf::Color::Black ); WindowApp->draw( fire ); WindowApp->draw( blood ); WindowApp->display(); }
return EXIT_SUCCESS; }
Updateable.h #include <SFML/Graphics.hpp>
#ifndef UPDATEABLE_H #define UPDATEABLE_H
using namespace std; class Updateable { public: virtual void Update( float DeltaInSeconds ) = 0; virtual bool Destroy() const = 0; };
#endif
SpriteEffect.h #include <SFML/Graphics.hpp> #include <iostream> #include "Updateable.h"
#define PATH "system\\data\\effects\\"
using namespace std;
class SpriteEffect : public Updateable , public sf::Drawable , public sf::Transformable { public: enum STATUS { Once = 0x10A, Twice = 0x20A, Repeat = 0xA0A }; enum Activity { Active = 0x21D, Disactive = 0x21C }; SpriteEffect( string , sf::Vector2i , sf::Vector2f , int , int , bool ); public: void setActive( int ); void outOfContrainet(); sf::Sprite * getElement(); protected: virtual void Update( float ); private: virtual bool Destroy() const; virtual void draw( sf::RenderTarget & target, sf::RenderStates states ) const; private: int status; int frame; float FPS_PER_SEC; bool autoDelete; bool destroyQueue; int activity; sf::Texture Texture; sf::Vector2i spriteSize; sf::Vector2f lengthOfTexture; sf::Sprite drawableSprite; sf::Time time; };
SpriteEffect.cpp #include "../../headers/SpriteEffect.h"
using namespace std;
SpriteEffect::SpriteEffect( string path, sf::Vector2i _spriteSize, sf::Vector2f _position, int _FPS_limit, int _status, bool _autoDelete ) : spriteSize( _spriteSize ) , status( _status ) , autoDelete( _autoDelete ) { if( !Texture.loadFromFile( PATH + path ) ) { cout << "Texture missing! " << endl; exit( 0 ); } FPS_PER_SEC = 1 / float( _FPS_limit ); frame = 0; activity = Activity::Active; destroyQueue = false; lengthOfTexture.x =( Texture.getSize().x / spriteSize.x ); lengthOfTexture.y =( Texture.getSize().y / spriteSize.y ); drawableSprite.setTexture( Texture ); drawableSprite.setTextureRect( sf::IntRect( 0, 0, spriteSize.x, spriteSize.y ) ); drawableSprite.setPosition( _position ); }
void SpriteEffect::Update( float dT ) { if( activity != Activity::Active ) return void(); time += sf::seconds( dT ); int x, y; if( time.asSeconds() >= FPS_PER_SEC ) { time = sf::seconds( 0 ); y = int( frame / lengthOfTexture.y ); x = frame % int( lengthOfTexture.x ); drawableSprite.setTextureRect( sf::IntRect( x * spriteSize.x, y * spriteSize.y, spriteSize.x, spriteSize.y ) ); if(( lengthOfTexture.y * lengthOfTexture.x ) - 1 <= frame ) { switch( status ) { case STATUS::Repeat: { frame = 0; } break; case STATUS::Once: { activity = Activity::Disactive; frame = 0; time = sf::seconds( 0 ); if( autoDelete ) destroyQueue = true; } break; } } frame++; } }
void SpriteEffect::draw( sf::RenderTarget & target, sf::RenderStates states ) const { if( activity == Activity::Active ) target.draw( drawableSprite ); }
bool SpriteEffect::Destroy() const { return destroyQueue; }
void SpriteEffect::setActive( int _activity ) { if( _activity == Activity::Active ) { activity = _activity; return; } if( _activity == Activity::Disactive ) activity = _activity; }
sf::Sprite * SpriteEffect::getElement() { return & drawableSprite; }
void SpriteEffect::outOfContrainet() { destroyQueue = true; }
engine.cpp #include "..\headers\Engine.h"
using namespace std;
Engine::Engine( sf::RenderWindow & win ) { WindowApp = & win; }
void Engine::Update( float deltaInSeconds ) { for( auto It = allObjectsContainer.begin(); It != allObjectsContainer.end(); It++ ) { ( * It )->Update( deltaInSeconds ); if(( * It )->Destroy() ) allObjectsContainer.erase( It ); } }
void Engine::addObject( Updateable & object ) { allObjectsContainer.push_back( & object ); }
engine.h #include <SFML/Graphics.hpp> #include "Updateable.h" #include "SpriteEffect.h" #include <vector>
using namespace std;
class Engine { public: Engine( sf::RenderWindow & win ); void Update( float ); void addObject( Updateable & object ); void draw(); private: vector < Updateable *> allObjectsContainer; sf::RenderWindow * WindowApp; };
|
|
Patrycjerz |
» 2015-07-17 22:30:07 Nie za bardzo chce mi się analizować ten kod :(, ale spróbuję odpowiedzieć. Stwórz sobie klasę abstrakcyjną dla wszystkich obiektów w grze i zaimplementuj w niej metody update, draw itp. Potem z klasy Engine wywołasz np. draw bez problemu. I jeszcze jedno. Nie rozumiem m.in. tego: ( * It )->Update( deltaInSeconds );
Przecież tą gwiazdką wyłuskałeś obiekt z wskaźnika i możesz używać normalnie: ( * It ).Update( deltaInSeconds );
It->Update( deltaInSeconds );
PS: Jeśli bredzę, to proszę o poprawę, też się uczę :) |
|
arczi14 Temat założony przez niniejszego użytkownika |
» 2015-07-17 22:44:41 Można by tak zrobić ale co by miało być elemtem przekazywamym w draw gdyż sfml ma.wiele obiektów do wyświetlenia. Trzeba funkcje draw rozwiązać Przy pomocy wbudowanej w sfml klasy drawable która daje wirtualna funkcje draw. I na.tym polega problem |
|
Patrycjerz |
» 2015-07-17 23:29:32 Jeśli chcesz użyć dziedziczenia dla użycia tej metody draw z SFML, to możesz stworzyć w klasie Engine wektor obiektów twojej gry oraz metodę do rysowania jego elementów. Po prostu we wnętrzu tej metody będzie jedna pętla for, która będzie wywoływać wielokrotnie metodę draw dla okna i przypisująca do argumentu twoje obiekty. Oczywiście to są moje luźne przemyślenia, może można to zrobić lepiej :) Oto przykładowy kod: void Engine::draw( sf::RenderWindow & WindowApp ) { for( auto It = allObjectsContainer.begin(); It != allObjectsContainer.end(); It++ ) { WindowApp.draw( * It ); } }
|
|
« 1 » |