Hello, BFWK is my rather miniscule project that I started working on a little while ago now.
TLDR;
https://bitbucket.org/bucket-jesus/bfwkBrief HistoryOver time, I came to realise that I am making code in little testing projects that are essentially copied and pasted from one to another. Thus, I started making this. It is modular to fit my needs as I work on completely random minor projects constantly. I came up with the name "basicFramework", and thought that it was far too long, so I shortened it to "BFWK".
Brief OverviewBFWK allows for an "easier" (opinions may vary) experience when working with a project. It encapsulates the processing of sf::Event's, sf::RenderTarget::draw()'s, and its own bfwk::BaseObject::update()'s, and pushes them to the currently active bfwk::BaseFrame. BFWK allows for the ability to let it call the update/draw cycles via another thread (default), or to use the main one.
Specific Breakdownbfwk::WindowThe Window class of this framework essentially owns the sf::RenderWindow and FrameHandler, forwards events to the FrameHandler, as well as dispatching update/draw calls to the FrameHandler (
only in monothreaded mode).
The usual usage scenarios of Window is:
bfwk::Window window;
window.getRenderWindow()->create(sf::VideoMode(800, 600), "Example");
window.launch();
bfwk::FrameHandlerThe FrameHandler ("Frame" in the context of this framework is meant as a verb, the objects you make and attach to it are "framed" together in the Window) controls the updating/drawing of the currently selected BaseFrame. It also forwards events to the currently selected BaseFrame and controls the refresh rate of the update/draw cycles.
Typical usage scenario's of FrameHandler are:
getFrameHandler()->setFrame<TestFrame>("Additional params");
getFrameHandler()->setRefreshTime( sf::seconds( 1.f / 60.f ) );
bfwk::BaseFrameBaseFrame is the abstract base class that all frames must inherit from if they are to work within the FrameHandler. This class receives the forwarded update/draw/event calls from the FrameHandler.
A good example of inheriting from this and handling all of the functionality required is in the Frame class.
bfwk::FrameThe Frame class is a typical abstract implementation of the BaseFrame class. It allows for the addition and removal of multiple BaseObjects from it's internal containers, custom background colour, dispatching of events/updates/draws to the current BaseObjects, as well as allows the modularity of its own internal pure virtual draw/update/event calls (
after all of the objects).
A Frame is typically inherited as follows:
class MyFrame : public bfwk::Frame {
public:
FirstFrame( bfwk::FrameHandler* parent );
~FirstFrame();
private:
void update();
void draw();
void initial();
void handleEvents( sf::Event const* event );
};
The initial() function is called via the FrameHandler in the event that the Frame has been selected. Some calculations require the sf::RenderWindow to be opened, so this function was created. The sf::RenderWindow is guaranteed to be open at the beginning of this call (under typical usage).
bfwk::BaseObjectBaseObject is an abstract class that is inherited to any "object" that you wish to add the the Frame class provided by BFWK. A class made from BaseObject that is non-abstract should be a leaf object in this train of calls (Window (Event) -> FrameHandler (Event, Update, Draw) -> BaseFrame (Event, Update, Draw) -> Frame (Event, Update, Draw) -> BaseObject (Event, Update, Draw*)).
*the BaseObject will only get the draw call if it inherits from sf::Drawable.
Classes that inherit from BaseObject that also inherit from sf::Drawable will get drawn to the sf::RenderWindow via a draw call. If your object is only logical, or if for some other reason doesn't require to ever be drawn, then simply do not inherit from sf::Drawable.
An example of a possible leaf Object:
class MyObject : public bfwk::BaseObject {
public:
MyObject( bfwk::BaseFrame* parent );
~MyObject();
private:
void update();
void handleEvents( sf::Event const* event );
bool const getActive();
};
The getActive() function is to tell the parent Frame whether there should be events forwarded, or not.
Okay, cool... where is it?BFWK was uploaded to
Bitbucket (it was on Github, but since I mostly use Bitbucket for everything else, I pulled it over there and now I only maintain it on Bitbucket.)
To re-enforce the prerequisites that are
clearly states in the
README.md file:
- SFML 2.3 (or later; may work for previous versions, but not tested)
- SFML_ROOT environment variable pointing to the root of the SFML folder (there is an option in CMake to set this if you do not want to have an environment variable)
- For examples, you must have the graphics, window, and system components of SFML built
- A compiler with C++14 support (due to the use of std::make_unique<T>( args ... ))
My UsesAs I previously said, I started working on this to more easily make small projects more quickly and test things out. Though, currently I am working on a more serious project with modularity in mind, but I do not have enough information gathered to discuss much of that.
In the mean time, finding bugs and suggesting good places for optimisation will be greatly appreciated. I am relatively new to making CMake projects, but I
think it should work on Windows and Linux. I am uncertain about Mac, as I have heard people say things tend to not work the best in such a case.
ExampleWhen working with BFWK, you must design your own frame class, that is based off of the bfwk::Frame class, one possible implementation is:
class ExampleFrame final : public bfwk::Frame {
private:
sf::VertexArray va; //simple vertex array that gets drawn via this frame
public:
ExampleFrame( bfwk::FrameHandler* parent )
: bfwk::Frame( parent ) {
va.resize( 4 );
va.setPrimitiveType( sf::Quads );
va[0].color = sf::Color::Red; //change all colours to red
va[1].color = sf::Color::Red;
va[2].color = sf::Color::Red;
va[3].color = sf::Color::Red;
}
void handleEvents( sf::Event const * event ) {
switch( event->type ) {
case sf::Event::Closed:
getRenderWindow()->close();
break;
default:
break;
}
}
void update( sf::Time const& time ) {
sf::Vector2f boxPosition( getRenderWindow()->getView().getCenter() + getRenderWindow()->getView().getSize() / 2.f - sf::Vector2f( 50.f, 50.f ) );
va[0].position = boxPosition - sf::Vector2f( 20, 20 );
va[1].position = {boxPosition.x + 20, boxPosition.y - 20};
va[2].position = boxPosition + sf::Vector2f( 20, 20 );
va[3].position = {boxPosition.x - 20, boxPosition.y + 20};
}
void draw() {
getRenderWindow()->draw( va );
}
void initial() {
std::cout << "Resize the window to see the object move!" << std::endl;
}
};
Then, of course, you must call the setFrame<T>() function of the FrameHandler for the Window, supplying your class as the template:
int main( int argc, char **argv ) {
try {
bfwk::Window window; //create the window
window.getFrameHandler()->setFrame<ExampleFrame>(); //set the initial frame
window.getRenderWindow()->create( sf::VideoMode( 800, 600 ), "bfwk Example!" ); //create the render window
window.launch(); //then launch the window
} catch( std::runtime_error e ) {
std::cout << "Runtime Error! : " << e.what() << std::endl;
}
return 0;
}
Due to the use of exceptions (primarily for me testing the framework on different machines, whereas some don't like the use of multiple threads for drawing), it is recommended to embed at least the bfwk::Window::launch() call within a try/catch. Also, when designing your bfwk::Frame class, you
must let bfwk::FrameHandler access it in some way, because it instantiates it on its own.
Edit: included a small example of bfwk::Frame usage. If you wish to see how bfwk::BaseObjects are used and get added to it, simply look at the
examples directory of the Bitbucket repository.