How can I create CollisionPolygon2D from one Sprite programatically?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By ChuckSparrow

Hi mates!

I’m trying to create a map for a strategy game where the main screen is a map splitted in several regions and each region can be clicked to show information concerning this region. The shape of each region is irregular, so I need some way to detect when the user clicks over the “visible” area of the sprite.

I started creating a CollisionPolygon2D from the Sprite with the tool that the editor provides and it works great, but this is tedious when you have to create 200 or more regions.

I have been searching for a way to create these CollisionPolygon2D programatically, but I haven’t found anything.

Do you know how can this be done or an alternative way?

So you have a sprite with a drawn shape in it, and you want to extract that shape as a polygon to produce the collider?
If you don’t want to trace polygons of each region, how did you get those 200 regions in the first place?

Zylann | 2020-02-26 01:52

:bust_in_silhouette: Reply From: Zylann

What the editor uses to produce the polygon is a Bitmap: BitMap — Godot Engine (3.2) documentation in English

It allows you to pick the image you want, convert it to a mask (with pixels being only 0 or 1), and then use opaque_to_polygon, which will turn opaque regions into one or more polygon points.

I haven’t used that class before and it’s not documented much, but from a glance in the engine code I see opaque_to_polygon returns an array, where each item is itself an array containing 2D points of one polygon (because the shape could be composed of multiple polygons).
The editor does a bit more optional stuff to those points but it looks like none of it is available from scripts: https://github.com/godotengine/godot/blob/2d980f6f13cc761c1eb9329e7eaeba5e9d1a9b37/editor/plugins/sprite_editor_plugin.cpp#L207

Then you need to create a CollisionPolygon2D for each polygon, and send their outline by assigning the polygon property: CollisionPolygon2D — Godot Engine (3.2) documentation in English

As code:

var image = Image.new()
image.load("res://map.png")

var bitmap = BitMap.new()
bitmap.create_from_image_alpha(image)

var polygons = bitmap.opaque_to_polygons(Rect2(Vector2(0, 0), bitmap.get_size()))

for polygon in polygons:
	var collider = CollisionPolygon2D.new()
	collider.polygon = polygon
	add_child(collider)

BitMap was the missing piece. It doesn’t provide as many options as the editor, but it works great for me.

Thanks man!

ChuckSparrow | 2020-02-27 14:42

:bust_in_silhouette: Reply From: ChildLearning.Club

The Shaggy Dev’s Video, “Pixel-perfect collisions on sprites in Godot”
does good job of explaining how this can be achieved.