Box2D Debug-Draw

Aus Spieleprogrammierer-Wiki
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

Box2D

Box2D ist eine Physik-Engine, die feste Körper in zwei Dimensionen simulieren kann. Sie ist dabei unabhängig von der eigentlichen grafischen Darstellung. Die Körper werden mittels geometrischen Formen, wie Rechtecke, Kreise oder beliebige konvexe Polygone angenähert. Wenn man mit Box2D arbeitet, ist es sehr hilfreich, wenn man die Formen auch angezeigt bekommt. Box2D bietet hierfür die b2Draw-Klasse, die man mit eigenen Zeichenbefehlen erweitern kann.

Die b2Draw-Klasse

Die b2Draw-Klasse ist eine teilweise abstrakte Klasse, die der b2World über SetDebugDraw() übergeben werden kann. Sie wird dann von innerhalb der b2World aufgerufen und dient zum Zeichnen von Debug-Informationen, beispielsweise die einzelnen Formen, die zu einem Körper gehören. Box2D hat keinen grafischen Teil, deshalb muss das Zeichnen selbst implementiert werden. Dieses Interface ist gegeben:

/// Draw a closed polygon provided in CCW order.
virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
 
/// Draw a solid closed polygon provided in CCW order.
virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
 
/// Draw a circle.
virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
 
/// Draw a solid circle.
virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
 
/// Draw a line segment.
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
 
/// Draw a transform. Choose your own length scale.
/// @param xf a transform.
virtual void DrawTransform(const b2Transform& xf) = 0;

Source Code

Dies ist eine Beispielimplementierung für die 2D Grafikbibliothek SFML.

Header

#pragma once
#include <SFML/Graphics.hpp>
#include <Box2D/Box2D.h>
class SFMLDebugDraw :
	public b2Draw
{
public:
	SFMLDebugDraw(sf::RenderWindow& window, const float& scale);
	virtual void DrawPolygon( const b2Vec2* vertices, int32 vertexCount, const b2Color& color );
	virtual void DrawSolidPolygon( const b2Vec2* vertices, int32 vertexCount, const b2Color& color );
	virtual void DrawCircle( const b2Vec2& center, float32 radius, const b2Color& color );
	virtual void DrawSolidCircle( const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color );
	virtual void DrawSegment( const b2Vec2& p1, const b2Vec2& p2, const b2Color& color );
	virtual void DrawTransform( const b2Transform& xf );
 
private:
	sf::RenderWindow& m_window;
	float SCALE;
 
private:
	sf::Color b2sfColorTransparent(const b2Color& color);
	sf::Color b2sfColor(const b2Color& color);
};

DrawPolygon

void SFMLDebugDraw::DrawPolygon( const b2Vec2* vertices, int32 vertexCount, const b2Color& color )
{
	sf::ConvexShape polygon;	
	polygon.setPointCount(vertexCount);
	polygon.setOutlineColor(b2sfColor(color));
	polygon.setOutlineThickness(1.f);
	polygon.setFillColor(sf::Color::Transparent);
	for(int32 i = 0; i < vertexCount; i++)
	{
		b2Vec2 vertex = vertices[i];
		polygon.setPoint(i, sf::Vector2f(vertex.x * SCALE, vertex.y * SCALE));
	}
	m_window.draw(polygon);
}

DrawSolidPolygon

void SFMLDebugDraw::DrawSolidPolygon( const b2Vec2* vertices, int32 vertexCount, const b2Color& color )
{
	if(vertexCount ==== 4)
	{
		sf::RectangleShape rect;
		rect.setPosition(sf::Vector2f(vertices[3].x * SCALE, vertices[3].y * SCALE));
		rect.setSize(sf::Vector2f(vertices[2].x * SCALE - vertices[3].x * SCALE, vertices[0].y * SCALE - vertices[3].y * SCALE));
		rect.setOutlineColor(b2sfColor(color));
		rect.setOutlineThickness(1.f);
		rect.setFillColor(b2sfColorTransparent(color));
 
		m_window.draw(rect);
	} else {
		sf::ConvexShape polygon;
		polygon.setPointCount(vertexCount);
		polygon.setOutlineColor(b2sfColor(color));
		polygon.setOutlineThickness(1.f);
		polygon.setFillColor(b2sfColorTransparent(color));
 
		for(int32 i = 0; i < vertexCount; i++)
		{
			b2Vec2 vertex = vertices[i];
			polygon.setPoint(i, sf::Vector2f(vertices[i].x * SCALE, vertices[i].y * SCALE));
		}
		m_window.draw(polygon);
	}
}

DrawCircle

void SFMLDebugDraw::DrawCircle( const b2Vec2& center, float32 radius, const b2Color& color )
{
	sf::CircleShape circle(radius * SCALE);
	circle.setPosition((float)(center.x - radius) * SCALE, (float)(center.y - radius) * SCALE);
	circle.setFillColor(sf::Color(0,0,0,0));
	circle.setOutlineColor(b2sfColorTransparent(color));
 
	m_window.draw(circle);
 
}

DrawSolidCircle

void SFMLDebugDraw::DrawSolidCircle( const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color )
{
	sf::CircleShape circle(radius * SCALE);
	circle.setPosition((float)(center.x - radius) * SCALE, (float)(center.y - radius) * SCALE);
	circle.setFillColor(b2sfColorTransparent(color));
	circle.setOutlineColor(sf::Color(0,0,0,0));
 
	m_window.draw(circle);	
}

b2sfColor

Hilfsfunktion, die ein b2Color-Objekt in ein sf::Color-Objekt umwandelt. Box2D benutzt float-Werte von 0-1, SFML int-Werte von 0-255.

sf::Color SFMLDebugDraw::b2sfColor( const b2Color& color )
{
	return sf::Color((sf::Uint8)(color.r*255), (sf::Uint8)(color.g*255), (sf::Uint8)(color.b*255), 255);
}

b2sfColorTransparent

Gleiche Funktion wie b2sfColor, hier wird der Alphawert halb transparent gesetzt

sf::Color SFMLDebugDraw::b2sfColorTransparent( const b2Color& color )
{
	return sf::Color((sf::Uint8)(color.r*255), (sf::Uint8)(color.g*255), (sf::Uint8)(color.b*255), 128);
}

Nicht benötigte Methoden

Diese Methoden habe ich noch nie benötigt und sie sind deshalb ohne Inhalt.

void SFMLDebugDraw::DrawSegment( const b2Vec2& p1, const b2Vec2& p2, const b2Color& color )
{
 
}
 
void SFMLDebugDraw::DrawTransform( const b2Transform& xf )
{
 
}

Benutzung

Dies ist ein minimales Beispiel, wie die DebugDraw-Klasse benutzt.

// Setup code
b2World world(b2Vec(0.f, 0.f));
SFMLDebugDraw dbgdraw(window, 1.f);
world.setDebugDraw(&dbgdraw);
 
// Render code
world.DrawDebugData();

Es ist aber anzumerken, dass mit aktiviertem DebugDraw die Framerate merklich sinkt. Besser ist es, es nur zu aktivieren, wenn eine bestimmte Taste gedrückt wird.

Weblinks

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Werkzeuge