How To Pick A Random Point From Triangles, Hexagons and Squares

This tutorial will cover multiple shapes, each comprising of two parts: an explanation of how the triangle formula is used then an usable example script to place on a Node2D object.

The recommended reading order for learners is [Triangles] → [SHAPE_OF_CHOICE] → [Making Code Cleaner]

Triangles

The triangle formula simply requires the positions of the three corners.
Here, the points form an equilateral triangle with a side length of one

extends Node2D

func random_triangle_point(a, b, c):
	return a + sqrt(randf()) * (-a + b + randf() * (c - b))

func _ready():
	var a = Vector2(0,0)
	var b = Vector2(1,0) 
	var c = Vector2(0.5,sqrt(3.0)/2.0)

	var point = random_triangle_point(a,b,c)
	print(point)

In game

extends Node2D

func random_triangle_point(a, b, c):
	return a + sqrt(randf()) * (-a + b + randf() * (c - b))
	
func _draw():
	var a = Vector2(0,0)
	var b = Vector2(1,0) 
	var c = Vector2(0.5,sqrt(3.0)/2.0)
	var triangleSize = 100
	
	for i in range(10000):
		var pos = random_triangle_point(a,b,c) * triangleSize
		draw_circle(pos, 1, Color.AQUAMARINE)

Hexagons

Hexagons are just 6 equilateral triangles in disguise, each rotated 60 degrees
All we need to do is pick a random equilateral triangle point, and rotate it

extends Node2D

func random_triangle_point(a, b, c):
	return a + sqrt(randf()) * (-a + b + randf() * (c - b))

func _ready():
	var a = Vector2(0,0)
	var b = Vector2(1,0) 
	var c = Vector2(0.5,sqrt(3.0)/2.0)

	var point = random_triangle_point(a,b,c)
	print(point.rotated(randi_range(0, 5) * deg_to_rad(60)))

In game

Notice that this code is the same as the triangle’s code with the exception of an extra line that simply rotates the triangle 60 degrees a random amount of times.

extends Node2D

func random_triangle_point(a, b, c):
	return a + sqrt(randf()) * (-a + b + randf() * (c - b))
	
func _draw():
	var a = Vector2(0,0)
	var b = Vector2(1,0) 
	var c = Vector2(0.5,sqrt(3.0)/2.0)
	var triangleSize = 100
	
	for i in range(10000):
		var pos = random_triangle_point(a,b,c) * triangleSize
		pos = pos.rotated(randi_range(0, 5) * deg_to_rad(60))
		draw_circle(pos, 1, Color.AQUAMARINE)

Square

Squares are a little more difficult because they are made of two right isosceles triangles that are rotated 180 degrees from each other (aka mirror opposites) but they don’t rotate in place so it ends up looking like this:
image

These two triangles do make up a square, but one of the triangles is in the wrong spot. If we’re on the rotated triangle, we should also move it by a set amount to the correct location. One side length to the right, One side length down.

extends Node2D

func random_triangle_point(a, b, c):
	return a + sqrt(randf()) * (-a + b + randf() * (c - b))
	
func _draw():
	var a = Vector2(0,0)
	var b = Vector2(1,0) 
	var c = Vector2(1,1)
	var triangleSize = 100
	
	var pos = random_triangle_point(a,b,c) * triangleSize
	var shouldRotate = randi_range(0, 1) == 0
	if shouldRotate:
		pos = pos.rotated(deg_to_rad(180))
		pos += Vector2(1, 1) * triangleSize

In game

extends Node2D

func random_triangle_point(a, b, c):
	return a + sqrt(randf()) * (-a + b + randf() * (c - b))
	
func _draw():
	var a = Vector2(0,0)
	var b = Vector2(1,0) 
	var c = Vector2(1,1)
	var triangleSize = 100
	
	for i in range(10000):
		var pos = random_triangle_point(a,b,c) * triangleSize
		
		var shouldRotate = randi_range(0, 1) == 0
		if shouldRotate:
			pos = pos.rotated(deg_to_rad(180))
			pos += Vector2(1, 1) * triangleSize
		draw_circle(pos, 1, Color.AQUAMARINE)

Making Code Cleaner

While I actively avoided making named functions so the logic can be followed sequentially, it is probably not a good idea to have unexplained a,b,c points as well as a seemingly random rotation.

For this reason, it is better to make a function that generates a random hexagon instead.

extends Node2D

func random_triangle_point(a, b, c):
	return a + sqrt(randf()) * (-a + b + randf() * (c - b))

func random_hexagon_point():
	var a = Vector2(0,0)
	var b = Vector2(1,0) 
	var c = Vector2(0.5,sqrt(3.0)/2.0)
	var randomRotation = randi_range(0,5) * deg_to_rad(60)
	return random_triangle_point(a,b,c).rotated(randomRotation)

func _ready():
	var point = random_hexagon_point(a,b,c)
	print(point)
1 Like