I have created the following method to outline an 2D polygon using an Line2D node (in favor of _drawing because of texturing and round jointing capabilities of the Line2D node):
func Set_Polygon_Outline(_polygon_node: Node2D, _width: int = 5, _color: Color = Color.black, _texture: Texture = null) -> void:
if _polygon_node is Polygon2D:
var _polygon: PoolVector2Array = (_polygon_node as Polygon2D).polygon
if _polygon.size() >= 3:
# Line2D node setup
var _line_node: Line2D = null
var _line_name: String = str(_polygon_node.name, "_Line")
if not _polygon_node.has_node(_line_name):
_line_node = Line2D.new() ; _line_node.name = _line_name ; _polygon_node.add_child(_line_node)
else: _line_node = _polygon_node.get_node(_line_name) as Line2D
# Line2D properties setup
if _line_node != null:
_line_node.width = _width ; _line_node.default_color = _color ; _line_node.joint_mode = Line2D.LINE_JOINT_ROUND
if _texture != null:
_line_node.texture = _texture ; _line_node.texture_mode = Line2D.LINE_TEXTURE_STRETCH
var _points: PoolVector2Array = _polygon ; _points.append(_polygon[0]) ; _line_node.points = _points
How would it be possible to replicate the round point jointing on point 0 in the same way as the other points?
The result meets expectations except on the closing points (from 4 to 0)
One approach I have tried is appending an additional point (point 1) to the _points Array. While the un-textured one looks as desired, the textured variant is slightly off on the additional line because of the two superimposing textures with alpha values making it look "bolder".
Another (very unorthodox approach) is creating two polygons: one black and one with an blur shader, using the following method:
func Set_Polygon_Shadow(_polygon_node: Node2D, _size: float = 10.0, _color: Color = Color.black) -> void:
if _polygon_node is Polygon2D:
var _polygon: PoolVector2Array = (_polygon_node as Polygon2D).polygon
if _polygon.size() >= 3:
# Shadow Polygon node setup
var _shadow_name: String = str(_polygon_node.name, "_Shadow")
if not _polygon_node.has_node(_shadow_name):
var _shadow_node: Polygon2D = Polygon2D.new()
_shadow_node.polygon = Geometry.offset_polygon_2d(_polygon, _size).front() ; _shadow_node.color = _color
_shadow_node.show_behind_parent = true ; _polygon_node.add_child(_shadow_node)
# Blur Polygon node setup
var _blur_node: Polygon2D = Polygon2D.new()
_blur_node.polygon = Geometry.offset_polygon_2d(_polygon, _size * 2.0).front()
_blur_node.material = ShaderMaterial.new()
_blur_node.material.shader = preload("res://shaders/Shader_Blur.shader")
_blur_node.material.set_shader_param("Strength", 2.0)
_blur_node.show_behind_parent = true ; _polygon_node.add_child(_blur_node)
The shader code:
shader_type canvas_item;
uniform float Strength : hint_range(0.0, 5.0);
void fragment() {COLOR = textureLod(SCREEN_TEXTURE, SCREEN_UV, Strength);}
The result looks good but I can't possibly imagine using this approach on a large number of polygons.
Thank you kindly, Mike.
If using a Line2D is a viable solution, except for fixing the loop, then let us fix the loop.
For a Line2D to loop seamless, even with transparency, it must close in a straight segment (not a corner). And have no end caps.
Thus, I suggest to move the first point, half way between its original position and the second point. Then you add at the end the original position of the first point, following by a copy of its moved position...
Like this:
# Let o be a copy of the original first point
var o = _points[0]
# Let m be the middle of the straight segment between the first and second points
var m = o + (_points[1] - o) * 0.5
_points[0] = m # The line now starts in m, we are moving the first point forth
_points.append(o) # Since we moved the first point forth, add its original position back
_points.append(m) # Add m at the end, so it loops, in the middle of a straight segment
That should result in a Line2D that loops seamlessly.