UI Container - Node2D or Polygon2D alternative

Hey guys.
I am trying to figure out a thing about UI. From the documentation, it seems like you have to use Control nodes (containers) for everything relating to the UI, cause Node2D and all its children do not interact with the containers (anchor etc.), which means they won’t be moved or rescaled by the Controls. Instead we are to use Container with applied texture, which works basically the same as a Sprite would.

Now my issue is, I am using a big image file with many different parts, and Polygon2D nodes to cut them out via UV into separate pieces to allow for deform and a Skeleton Rig capable of parts swapping without relying on texture swap that migh be really messy with different sized body parts (hence why I don’t want to use Sprite2D, although I think remote control for bones might work with multiple body parts). I wanted to make a UI Character Frame with the cut out polygon2D nodes inside so no matter what the player currently has (hair, facial expression…), it would be visible. But since Polygon2D does not work with the container, and (at least to my knowledge) there is no equivalent that allows UV and Polygon points, how am I supposed to do this? Am I forced to either not use Control nodes (that would be hard since it’s a text based UI heavy game, basically everything would be in a container to allow scaling etc.), or not to use polygon2D and transfer everything relevant into Sprite nodes/Control nodes and having hundreds of separate source images, and issues with part swapping due to different piece sizes? Also I read that Shader (particle effects) also would not work with containers, so having a container to nest animations would probably create issues there as well?

Or is there a way to bound the Polygon2D node to the Container so it somehow scales and positions with the container? I want to use containers to allow the player to rescale any part of the UI as necessary, be it a side panel with game info, or the scene that plays the character animations, and to allow scrolling etc.

You can mix Control and Node2D nodes as long as you need it.

You can override Control._get_minimum_size() to return the Control minimum size it will take and calculate it from the Polygon2D.polygon points. You can also use the Control.resized signal to position and scale the Polygon2D node inside the Control

Example:

@tool
extends Control

@onready var polygon_2d: Polygon2D = $Polygon2D


func _ready() -> void:
	# Trigger an update the minimum size now that the node is ready
	update_minimum_size()

	# Connect to the resized signal to update the scale and position of the Polygon2D
	resized.connect(func():
		var min_size = _get_polygon_minimum_size()
		polygon_2d.scale = size / min_size
		polygon_2d.position *= polygon_2d.scale
	)


func _get_minimum_size() -> Vector2:
	return _get_polygon_minimum_size()


# Gets the polygon minimum size
func _get_polygon_minimum_size() -> Vector2:
	# If the node is not ready yet then the Polygon2D node won't be either
	if not is_node_ready():
		# Return Vector2(0,0) in this case
		return Vector2.ZERO

	# Get the top left and polygon size from the Polygon2D points
	var top_left = Vector2.INF
	var poly_size = Vector2.ZERO
	for p in polygon_2d.polygon:
		top_left.x = min(p.x, top_left.x)
		top_left.y = min(p.y, top_left.y)
		poly_size.x = max(p.x, poly_size.x)
		poly_size.y = max(p.y, poly_size.y)

	# Offset the Polygon2D with the top left corner of the polygon
	polygon_2d.position = -top_left

	return poly_size - top_left

Result:

2 Likes

Holy, thank you, this is exactly what I needed. And you even provided the example script and a video.

You saved me a whole lot of time and headaches. Thank you again.

Hey,
just created account to thank you for this very much.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.