The way my engine works makes it hard for the rendering and the simulation to be separated.
Here are the basics my engine:
- It's a class hierarchy of CObject->CEventHandler->CObjectHandler
- CObject controls position, dimensions, visibility, and a parent object
- Objects that only want the basic necessities to draw to a parent inherit from here
- All CObjects must have a drawTo( CCanvas* ); function.
- CEventHandler, for the moment, handles mouse events tied to the object
- Objects that also want to be considered in the event poll inherit from here
- CObjectHandler handles the drawing of child objects to itself
- Objects that also want to render a scene on themselves inherit from here
- includes a drawChildren( CCanvas*, CRect ); function.
- CParent_Interface - all parent objects must inherit from this interface as well
- CWindow - a class outside the hierarchy, inherits from CParent_Interface, and controls the window related functions.
So, here is what a basic program might look like:
int main() { CWindow *window = new CWindow( 800, 600, e_bpp::BPP_32 ); window->setClearColor( 0, 0, 255 ); CImage *image = new CImage( window ); // image is set to render on the window image->setW( 100 ); // width is set image->setH( 100 ); // height is set //etc. CPanel *panel = new CPanel( window ); // panel is set to render on the window panel->setX( 200 ); // x is set panel->setY( 200 ); // y is set panel->setW( 200 ); // width is set panel->setH( 200 ); // height is set CUnit *player = new CUnit( panel ); // player is set to render on the panel while( !quit ) { window->clear(); // move objects and do other stuff ... window->drawChildren(); window->flip(); } delete( window ); //handles shutdown and deletion of surfaces and objects }
Now, heres what's going on behind the scenes:
// CWindow::drawChildren() calls all its children's drawTo( CCanvas* ) functions.// The drawTo function is responsible for updating the object, then drawing it void CWindow::drawChildren() { CRect draw_rect = (CRect){0, 0, getW(), getH()}; for( unsigned int x = 0; x < numChildren(); ++x ) { if( Overlaps( draw_rect, getChild(x)->getRect() ) ) { getChild(x)->drawTo( canvas_ ); } }}// CPanel updates by filling a the rect, drawing bevels and then drawing children// to itself, then drawing itself to the destination canvasint CPanel::drawTo( CCanvas *canvas ) { if( isVisible() && canvas != NULL && canvas_ != NULL ) { canvas_->fillRect( NULL, fill_color_ ); if( bevel_outer_ == LOWERED ) { canvas_->drawBevelLowered(); } else if( bevel_outer_ == RAISED ) { canvas_->drawBevelRaised(); } if( bevel_inner_ == LOWERED ) { canvas_->drawBevelLowered(1, 1); } else if( bevel_inner_ == RAISED ) { canvas_->drawBevelRaised(1, 1); } //draw children CRect draw_rect = (CRect){0, 0, getW(), getH()}; drawChildren( canvas_, draw_rect ); return canvas->blit( getX(), getY(), canvas_ ); } return 0;}
Those two examples only deal with updating the graphics, but I also wanted to tie in the unit mechanic closely with the graphics pipeline for improved performance:
int CUnit::drawTo( CCanvas* canvas ) { //update CUnit, meaning its states, inventory, etc, and draw it to the canvas.}
My thinking is that if I already have one giant for loop that loops through all possible objects that are going to be rendered, why not include the game logic in there so I don't have to create a second giant loop to process game logic, slowing the engine down? Am I thinking about this wrong?
Above all else, I want my rendering engine to be a union of performance and quality. My engine can render over 10000 10x10 SDL_Surfaces without dropping below 30 fps, doesn't take much memory to run, and is simple to use. The only thing that really bothers me is this damn stuttering problem ><...