How to create smooth curves with polygons?

Godot Version

4.7

Question

I’m making an ice hockey rink where the edges are walls so play can happen within.
I’m using a `CollisionPolygon2D` with Build Mode set to `Segments` so that it’s not solid and things can be inside the what is in effect a rounded rectangle.

I’m creating the polygon with script so the length and width of the rectangle can be configured.

My problem is that it seems the rounded corners are “jagged” so my little puck doesn’t slide along it, it bounces when it hits the curve.
Here’s a video clip of what happens.

https://imgur.com/a/o2B3AXk

The corner creation code looks like this,

# Top left rounded corner.
	var center = Vector2(corner_radius, corner_radius)
	for angle in range(270, 180, -1):
		var rad = deg_to_rad(angle)
		polygon.append(center + Vector2(cos(rad), sin(rad)) * corner_radius)

The polygon is set _collision_polygon_2d.polygon = polygon in the end.

Is there a better way to get smooth rounded edges so things can slide all along them?

Here’s the full function that generates the collision polygon.

func _generate_collision_polygon() -> void:	
	var corner_radius = rules.corner_radius * pixels_per_meter
	var height = rules.height * pixels_per_meter
	var width = rules.width * pixels_per_meter
	
	var polygon = PackedVector2Array()
	
	# Top left rounded corner.
	var center = Vector2(corner_radius, corner_radius)
	for angle in range(270, 180, -1):
		var rad = deg_to_rad(angle)
		polygon.append(center + Vector2(cos(rad), sin(rad)) * corner_radius)

	 # Left edge (top to bottom).
	polygon.append(Vector2(0, corner_radius))
	polygon.append(Vector2(0, height - corner_radius))

	# Bottom-left arc (clockwise: 90° to 180°).
	center = Vector2(corner_radius, height - corner_radius)
	for angle in range(180, 90, -1):
		var rad = deg_to_rad(angle)
		polygon.append(center + Vector2(cos(rad), sin(rad)) * corner_radius)

	# Bottom edge (right to left).
	polygon.append(Vector2(corner_radius, height))
	polygon.append(Vector2(width - corner_radius, height))

	# Bottom-right arc (clockwise: 0° to 90°).
	center = Vector2(width - corner_radius, height - corner_radius)
	for angle in range(90, 0, -1):
		var rad = deg_to_rad(angle)
		polygon.append(center + Vector2(cos(rad), sin(rad)) * corner_radius)

	# Right edge (bottom to top).
	polygon.append(Vector2(width, height - corner_radius))
	polygon.append(Vector2(width, corner_radius))

	# Top-right arc (clockwise: 270° to 360°).
	center = Vector2(width - corner_radius, corner_radius)
	for angle in range(360, 270, -1):
		var rad = deg_to_rad(angle)
		polygon.append(center + Vector2(cos(rad), sin(rad)) * corner_radius)

	# Top edge (left to right).
	polygon.append(Vector2(width - corner_radius, 0))
	polygon.append(Vector2(corner_radius, 0))

	# Close the polygon.
	polygon.append(polygon[0])
		
	_collision_polygon_2d.polygon = polygon
	_polygon_2d.polygon = polygon
	_polygon_2d.color = Color(0.75, 0.9, 0.9, 1.0)

Enable Debug → Visible Collision Shapes to see what you have generated.

Maybe my pinball demo using Scalable Vector Shapes 2D can help?

There is a setting in the inspector to set the tolerance_degrees all the way down to zero for a smooth curve. Or even better: right click the hole’s outline to make an arc and play with the Arc settings. Once done, extract your CollisionPolygon2D’s (it will generate 2 instances to handle the hole) and get rid of my plugin again.

The plugin:

(Also on Github and in asset lib)

Thank you! Your tool worked like a charm.

Using it I made a rounded rectangle and setting the tolerance_degrees made it smooth as can be.

Huge thanks! :heart:

When you’re ready to promote, be sure to let me know. I’d love to share how people used the plugin.