Skip to content

Tutorial: Drawable Group

eXpl0it3r edited this page Oct 18, 2012 · 1 revision

Grouping your Drawable in a Group class

This page lacks examples and images.

This tutorial has been written because of this thread.

Introduction

Drawable's children cover a wide range of uses: Shapes, Sprites, Texts, etc. but the "family" lacks one member: Group, so we'll create it there. Indeed, the class exists in well-known libraries such as Pygame.

Utility

Inheritance from std::vector

Why are Groups useful? Basically, you can store your game objects in them so that they don't "swim" in a big "pool", and apply precise calculations on a specified part of them easily.

  • You can make a "backgrounds" Group, followed by a "Level" one, and then a "Foreground" One, for example. This, way, backgrounds will always be drawn before the level tiles which will also be drawn before the foreground elements, even if you had backgrounds, tiles, or foregrounds, which would have otherwise been on the top. Imagine you add a background without using Groups: it covers everything and you can't see behind it!
  • You can make a traditionnal 2D game with depth, where there are two parallels level. The character must only be on one of the layers, and change by jumping. Each "layer" can be implemented as a Group, and the one where the player stands is used for collisions, while the other can be tinted in grey (Group.SetColor(sf::Color(100, 100, 100))) to show that the player is standing on the other side.
  • You'll find many others.

Inheritance from Drawable

Group would behave like a simple std::vector, but would also be drawable itself. There are two main reasons for this:

  • simplicity: it's easier to type Group.Draw() than for(int i = 0; ...) { Group[i].Draw() }. It also makes Groups storable in other Groups, like other Drawables, which ables to process the whole very easily ;
  • sharing of properties for the membres of a Group. For example, if you want all the Sprites stored in a Group to move at the same time, you can just update the coordinates of the Group. This is very useful if you make an articulated body made of sprites. You can also separate objects around a single point: the origin of the Group, just by using Group.SetCenter(..., ...)!

Suggested implementation (using SFML 2.0)

Here's what I use. The SFML doesn't implement a Group class for ownership reasons: should the Group destroy its elements when it is destroyed? etc.

Group.hpp

#ifndef GROUP_INCLUDED_HPP
#define GROUP_INCLUDED_HPP

#include <SFML/Graphics.hpp>

class Group : public sf::Drawable, public std::vector<sf::Drawable*> {
	public:
		Group();
		~Group();

		void render(sf::RenderTarget&) const;
};

#endif

Group.cpp

#include "group.hpp"

Group::Group() :
	sf::Drawable(),
	std::vector<sf::Drawable*>() {
}
Group::~Group() {
	for(std::vector<sf::Drawable*>::iterator i = begin(); i != end(); ++i) {
		delete *i;
	}
}

// This is what ables you to do Group.Draw() to draw all the Drawable inside of a Group,
// and to apply common settings such as position, color, ... to its elements.
void Group::render(sf::RenderTarget& Tar) const {
	for(std::vector<sf::Drawable*>::iterator i = begin(); i != end(); ++i) {
		Tar.draw(*i);
	}
}

You can even add namespace sf { ... } if you think that Group should belong to the SFML ;).

Examples

It would be a good idea to use the "reasons" said above and make code snippets out of them

Clone this wiki locally