# Create a Hitbox Editor

In this tutorial the goal is to create a hitbox editor. Hitbox are polygons use to detect collisions in video games.

In a point and click game we need to check the collision between one point and a polygon which is simpler than the collision between two polygon. This tutorial is not about collisions so we will only check if a point is in the polygon. The coordinates of the point will be the same as the cursor like point and click games. Only one method is enough to achieve that. The code for this algorithm is very short:

``````/*
nvert: Number of vertices in the polygon. Whether to repeat the first vertex at the end has been discussed in
the article referred above.
vertx, verty: Arrays containing the x- and y-coordinates of the polygon's vertices.
testx, testy: X- and y-coordinate of the test point.
*/
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy) {
int i, j, c = 0;
for (i = 0, j = nvert - 1; i < nvert; j = i++) {
if (((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j] - vertx[i]) * (testy - verty[i]) /
(verty[j] - verty[i]) + vertx[i]))
c = !c;
}
return c;
}``````

If you want to have more complex collisions you will need to use SAT (Separate Axis Theorem) or maybe use a 2D physics library to have an efficient implementation of collisions.

## Create the project

To make this editor I will useÂ SFMLÂ but you can do the same thing with SDL if you want
We will use this image as a background in the editor :Â machinarium.jpgÂ –Â Source :Â machinarium

We will need to display polygons and the only class available in SFML to do that isÂ sf::ConvexShape. Next, we need something to draw concave polygon, we can simply divide the concave polygon into multiple convex polygon. To do that we have to use some library to split the polygon :Â Efficient Polygon Triangulation

## Hitbox Editor

Once the project is created and configured we can see what do we need ?

• Add a vertex to the polygon after a click
• A key to remove the last vertex added
• A key to display the polygon
• A key to clear the polygon and save the result

Here is the main of the editor, everything should be simple to understand if you know a little bit of SFML :).

``````bool testMode = false;
float *vertx = NULL;
float *verty = NULL;

sf::Vector2f pos = sf::Vector2f(0, 0);
sf::Texture tex;

sf::Sprite spr(tex);
spr.setPosition(pos);

std::vector<sf::ConvexShape> polyShapes;
std::vector<sf::CircleShape> circles;

Vector2dVector polygon;

sf::RenderWindow window(sf::VideoMode(1280, 800), "Hitbox Editor");

while (window.isOpen()) {
sf::Event event;

while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::MouseButtonPressed) {
if (event.key.code == sf::Mouse::Left) {
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
if (testMode) {
std::cout << "result : " << pnpoly(polygon.size(), vertx, verty,
(float) mousePos.x, (float) mousePos.y) << "\n";
}
else {
polygon.push_back(Vector2d(mousePos.x, mousePos.y));

sf::CircleShape circle;
circle.setOutlineColor(sf::Color::White);
circle.setFillColor(sf::Color::White);
circle.setPosition((float) mousePos.x - 2, (float) mousePos.y - 2);
circles.push_back(circle);
}
}
}
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Escape)
window.close();

// Remove the last point added
if (event.key.code == sf::Keyboard::BackSpace) {
polygon.pop_back();
circles.pop_back();
}
// Clear the current hitbox
if (event.key.code == sf::Keyboard::C) {
polyShapes.clear();
polygon.clear();
circles.clear();

if (vertx != NULL) {
delete(vertx);
delete(verty);
vertx = NULL;
verty = NULL;
}
}

// Enable the test mode
if (event.key.code == sf::Keyboard::T) {
testMode = !testMode;
}

// Save the hitbox into a file and clear
if (event.key.code == sf::Keyboard::S) {
save_file("out.txt", polygon, pos);

// Clear the hitbox
polyShapes.clear();
polygon.clear();
circles.clear();
if (vertx != NULL) {
delete(vertx);
delete(verty);
vertx = NULL;
verty = NULL;
}
}

if (event.key.code == sf::Keyboard::F) {
vertx = new float[polygon.size()];
verty = new float[polygon.size()];

for (size_t i = 0; i < polygon.size(); i++) {
vertx[i] = polygon[i].GetX();
verty[i] = polygon[i].GetY();
}

Vector2dVector result;

// Split the polygon into triangles
Triangulate::Process(polygon, result);

size_t tcount = result.size() / 3; // number of triangles

for (size_t i = 0; i < tcount; i++) {
const Vector2d &p1 = result[i * 3 + 0];
const Vector2d &p2 = result[i * 3 + 1];
const Vector2d &p3 = result[i * 3 + 2];

// Create a triangle with the coordinates
sf::ConvexShape poly;
poly.setPointCount(3);
poly.setPoint(0, sf::Vector2f(p1.GetX(), p1.GetY()));
poly.setPoint(1, sf::Vector2f(p2.GetX(), p2.GetY()));
poly.setPoint(2, sf::Vector2f(p3.GetX(), p3.GetY()));
poly.setOutlineColor(sf::Color::White);
poly.setFillColor(sf::Color::White);
poly.setPosition(0, 0);
polyShapes.push_back(poly);
}
}
}
}

window.clear();
window.draw(spr);

for (auto& x : circles) {
window.draw(x);
}

for (auto& x : polyShapes) {
window.draw(x);
}

window.display();
}

if (vertx != NULL) {
delete(vertx);
delete(verty);
vertx = NULL;
verty = NULL;
}

return 0;``````

We need the helper function save_file for this main to compile:

``````void save_file(const char* filename, Vector2dVector vect, sf::Vector2f pos) {
std::string seq = "";
for (size_t i = 0; i < vect.size(); i++) {
seq.append(std::to_string((int)(vect[i].GetX() - pos.x)));
seq.push_back(':');
seq.append(std::to_string((int)(vect[i].GetY() - pos.y)));
if (i != vect.size() - 1) {
seq.push_back('-');
}
}

std::ofstream file;
file.open(filename, std::ios::out | std::ios::app);
file << seq << "\n";
std::cout << seq << "\n";
file.close();
}``````

If you have some errors you can download the project for visual studio with libraries : HitboxEditor.7z

Do not forget to change the include path and lib path in the configuration !

Scroll to Top