Is there a way to create collision shapes based on the contour of a sprite?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Xrayez
:warning: Old Version Published before Godot 3 was released.

Lets say I want to create nodes of arbitrary shape inside a scene. Naturally when I add a Sprite as a child of RigidBody2D, I also want the CollisionShape2D to be exactly (or at least approximately) the shape of Sprite. How do I go about it? Is it difficult to implement? Am I limited to using built-in collision shapes? The question is related to pixel-perfect collision too. In other words, I want to automate the process of creating collision shapes from a Sprite.

The example usage is creating randomly generated terrain maps as a StaticBody2D imported from .png transparent image.

Using Godot 2.1.2 stable.

:bust_in_silhouette: Reply From: bruteforce

Use a CollisionPolygon2D instead of predefined shapes, and you can add the coordinates manually!

Using CollisionPolygon2D solves the problem of limited number of built-in shapes, yes. But what I’m trying to achieve is actually how to automate the process of creating such shapes so I don’t have to manually create a CollisionPolygon2D for each sprite I import.

Xrayez | 2017-02-15 10:56

So you want to create shapes programmatically.
IMO you have to use collisionobject2d api, because Collision*** nodes are editor-helpers only :(.

bruteforce | 2017-02-15 11:04

Yeah, seems like I need to dig into it more. Thanks for pointing out to the API, I suspected it wouldn’t be easy… Maybe Godot 3.0 will bring such functionality.

Xrayez | 2017-02-15 11:11

May I suggest writing a tool for this in another language? It could generate the vertexes and write them to a file, then have Godot build a polygon from that. I’m considering doing that with Python+Pillow for my game, and perhaps later making a plugin of it through DLScript (unlikely).

fredspipa | 2017-02-15 15:43

Go for it! I’m rather interested in some general algorithm for it, implementation doesn’t really matter. It would be even better to make this stuff work at run-time.

Xrayez | 2017-02-15 15:47

You can read the Image data from the ImageTexture resource and look for transparent points to create your Convex/Concave PolygonShape2D.

eons | 2017-02-16 14:50

:bust_in_silhouette: Reply From: Xrayez

I’ve figured a somewhat hacky solution that could turn sprites into a bunch of convex shapes using mesh instances in 2D space:

Create collision shapes from sprites in Godot 3.0

  1. Create a sprite and assign its texture.
  2. Select the node sprite, at the top panel of the viewport click Sprite.
  3. In the popup menu, press Convert to 2D Mesh.
  4. In the window dialog, press Create 2D Mesh button.

Now you can get faces from the mesh, convert those faces into a bunch of ConvexPolygonShape2D (which are triangles), and add those directly to a physics body.

func _ready():
    # Get triangles points from mesh
    var points = $MeshInstance.mesh.get_faces()

    var idx = 0
    var shapes = []

while idx < points.size():
	
	# Each three vertices represent one triangle
	# Converts automatically from Vector3 to Vector2!
	var tri_points = PoolVector2Array([points[idx], points[idx + 1], points[idx + 2]])
	
	# Create an actual triangle shape
	var tri_shape = ConvexPolygonShape2D.new()
	tri_shape.points = tri_points
	shapes.push_back(tri_shape)
	
	idx += 3
	
for sh in shapes:
	# Add created shapes to this collision body
	# `0` indicates the first shape owner which is `CollisionShape2D`
	shape_owner_add_shape(0, sh)

I should note that this solution is not complete because it doesn’t take into account possible holes in the sprite’s texture, but it’s still quite useful.

Xrayez | 2018-10-12 08:32

:bust_in_silhouette: Reply From: ichster

Sprites now have a tool that creates CollisionPolygon2D’s automatically. Click on “Sprite” on the top tool bar, and then select “Create CollisionPolygon2D sibling option”.
See 2D meshes tutorial for details.

Using Godot 3.1.1 stable.