geom

Styling what you draw

Color, thickness, dashes, gradients, and the space sizes are read in.

Every shape is drawn with the current draw state. Set the state, then draw; the state persists until something changes it, which is why reset_all_draw_states() at the top of a _process is worth the line.

extends Node2D
## Draw state: color, thickness, dashes, gradients, and the space sizes are
## measured in. Each block below sets state, then draws with it.


func _process(_delta: float) -> void:
	GeomDraw.reset_all_draw_states()

	# Sizes have a space. PIXELS holds a size on screen whatever the zoom;
	# METERS is in the shape's own units and scales with the canvas.
	GeomDraw.radius_space = Geom.SPACE_PIXELS
	GeomDraw.thickness_space = Geom.SPACE_PIXELS

	# A gradient around a ring, from `color` to `color_end`.
	GeomDraw.color_mode = Geom.COLOR_ANGULAR
	GeomDraw.color = Color(0.68, 0.55, 1.0)
	GeomDraw.color_end = Color(0.55, 0.98, 0.78)
	GeomDraw.thickness = 12.0
	GeomDraw.ring_2d(Vector2(110, 150), 58.0)
	GeomDraw.color_mode = Geom.COLOR_SINGLE

	# Dashes. dash_size and dash_spacing are read in dash_space, which defaults
	# to RELATIVE -- multiples of the wall's thickness, not lengths.
	GeomDraw.dashed = true
	GeomDraw.dash_space = Geom.DASH_FIXED_COUNT
	GeomDraw.dash_size = 18.0
	GeomDraw.dash_spacing = 0.45
	GeomDraw.thickness = 9.0
	GeomDraw.ring_2d_colored(Vector2(270, 150), 58.0, Color(1.0, 0.78, 0.36))
	GeomDraw.dashed = false

	# Rectangles round per corner, clockwise from bottom-left, as fractions of
	# the shorter half-side.
	GeomDraw.corner_radii = Vector4(0.9, 0.0, 0.5, 0.0)
	GeomDraw.rect_2d_colored(Vector2(430, 150), Vector2(130, 100),
		Color(0.42, 0.85, 1.0))
	GeomDraw.corner_radii = Vector4.ZERO

	# Outlines are their own calls rather than a fill flag.
	GeomDraw.thickness = 6.0
	GeomDraw.regular_polygon_border_2d_colored(Vector2(560, 150), 58.0, 5,
		Color(1.0, 0.47, 0.6))

styling

Sizes have a space

thickness_space, radius_space and size_space each choose how a number is read:

  • Geom.SPACE_METERS — the shape’s own units. A radius of 60 is 60 world units, and shrinks as the camera pulls back or the canvas zooms out.

  • Geom.SPACE_PIXELS — screen pixels. A thickness of 2 stays 2 pixels wide at any zoom, which is what an editor overlay or a HUD generally wants.

  • Geom.SPACE_VIEWPORT — a fraction of the viewport. 100 units span its shorter side, so a value of 1 is one percent of it and a shape holds its proportions at any resolution. The same idea as CSS vmin.

    One unit is about 11 pixels at 1080p, which is worth knowing before you pick a number. A badge radius is around 4, a half-height ring 25 — comfortable. Strokes come out below 1: a readable one is about 0.5. If a stroke should stay a fixed number of pixels instead of scaling, that is what Geom.SPACE_PIXELS is for.

A node’s scale multiplies the size whichever space you choose.

Dashes read their own space too

dash_size and dash_spacing are read in dash_space, and the default is DASH_RELATIVE — multiples of the wall’s thickness, not lengths. On a wall 12 units thick, dash_size = 26 is a dash 312 units long. This catches people out.

  • Geom.DASH_RELATIVE keeps dashes square as the thickness changes.
  • Geom.DASH_METERS reads them as lengths.
  • Geom.DASH_FIXED_COUNT takes a number of dashes to fit around the shape and works the period out from the perimeter, which is usually what you want on a ring.

On a closed shape, set dash_snap to Geom.SNAP_TILING so a whole number of periods fits and the pattern meets itself where the shape closes.

Outlines are separate calls

There is no fill flag. rect_2d fills, rect_border_2d outlines, and the same pattern holds for triangles, quads and regular polygons. The outlined versions use thickness; the filled ones ignore it.