I've moved this to its own repo here: https://github.com/kevinthompson/godot-generate-polygon-from-sprite-tool. Original gist is below.
Last active
June 12, 2024 13:28
-
-
Save kevinthompson/84b2010306817d7845d2b11e96da2c48 to your computer and use it in GitHub Desktop.
Tool Script to Create a CollisionPolygon2D from a child Sprite2D in Godot 4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Tool to regenerate CollisionPolygon2D nodes from a sprite node | |
# when the scenes is loaded, when the editor regains focus, or | |
# when the "Recalculate Geometry" checkbox is clicked in the inspector. | |
@tool | |
extends Node2D | |
@export var recalculate_geometry : bool : | |
set(_value): | |
_create_polygon2d_from_sprite2d() | |
func _create_polygon2d_from_sprite2d(): | |
# Find First StaticBody2D Child | |
var static_body = find_children("*", "StaticBody2D")[0] | |
# Destroy Existing Collision Polygons | |
for node in static_body.find_children("*", "CollisionPolygon2D"): | |
node.queue_free() | |
# Generate Bitmap from Sprite2D | |
var sprite = $Sprite2D | |
var image = sprite.texture.get_image() | |
var bitmap = BitMap.new() | |
bitmap.create_from_image_alpha(image) | |
# Create Collision Polygon from Opaque Pixels | |
var polys = bitmap.opaque_to_polygons(Rect2(Vector2.ZERO, image.get_size()), 0.0) | |
for poly in polys: | |
var collision_polygon = CollisionPolygon2D.new() | |
collision_polygon.polygon = poly | |
static_body.add_child(collision_polygon) | |
collision_polygon.set_owner(get_tree().get_edited_scene_root()) | |
collision_polygon.position -= sprite.texture.get_size() / 2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is the same as above but it also adds reloading the collision | |
# polygons on scene load and when the editor window is focussed. | |
# | |
# It also accounts for convex shapes (shapes with holes in the middle) | |
# by splitting the sprite down the center and generating one group of | |
# polygons for the left side of the sprite and another for the right. | |
@tool | |
extends Node2D | |
@export var recalculate_geometry : bool : | |
set(_value): | |
_create_polygon2d_from_sprite2d() | |
@onready var sprite = $Sprite2D | |
func _ready(): | |
if Engine.is_editor_hint(): | |
_create_polygon2d_from_sprite2d() | |
if sprite: | |
sprite.connect("texture_changed", _handle_texture_change) | |
if sprite.texture: | |
sprite.texture.connect("changed", _create_polygon2d_from_sprite2d) | |
func _handle_texture_change(): | |
_create_polygon2d_from_sprite2d() | |
if sprite.texture && !sprite.texture.is_connected("changed", _create_polygon2d_from_sprite2d): | |
sprite.texture.connect("changed", _create_polygon2d_from_sprite2d) | |
func _create_polygon2d_from_sprite2d(): | |
# Find First StaticBody2D Child | |
var static_body | |
var static_bodies = find_children("*", "StaticBody2D") | |
if static_bodies.size() > 0: | |
static_body = static_bodies[0] | |
# Destroy Existing Collision Polygons | |
for node in static_body.find_children("*", "CollisionPolygon2D"): | |
node.queue_free() | |
if sprite.texture: | |
# Generate Bitmap from Sprite2D | |
var sprite = $Sprite2D | |
var image = sprite.texture.get_image() | |
var bitmap = BitMap.new() | |
bitmap.create_from_image_alpha(image) | |
var polys = bitmap.opaque_to_polygons(Rect2(Vector2.ZERO, Vector2(image.get_width()/2,image.get_height())), 0.0) | |
_add_collision_polygons_to_static_body(polys,static_body,sprite.texture.get_size() / 2) | |
polys = bitmap.opaque_to_polygons(Rect2(Vector2(image.get_width()/2, 0), Vector2(image.get_width(),image.get_height())), 0.0) | |
_add_collision_polygons_to_static_body(polys,static_body,Vector2(0, sprite.texture.get_height() / 2)) | |
func _add_collision_polygons_to_static_body(polys: Array[PackedVector2Array], static_body: StaticBody2D, offset: Vector2): | |
for poly in polys: | |
var collision_polygon = CollisionPolygon2D.new() | |
collision_polygon.polygon = poly | |
static_body.add_child(collision_polygon) | |
collision_polygon.set_owner(get_tree().get_edited_scene_root()) | |
collision_polygon.position -= offset |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment