How to get a random point around the player

Godot Version

4.2

Question

I’m trying to get a random a point around my payer character between an area 2d and a range but so far I havent been able to find an answer to this question. So far I found some guidance but so far all I have been able to do is get a random point within the area 2d. But I want the points to be outside the area 2d.

@onready var collision_shape_2d = $"../Player/Area2D/CollisionShape2D".shape.get_rect()
@onready var targetPos : Vector2
func PickRandomPoint():
	var x = randi_range(collision_shape_2d.position.x, (collision_shape_2d.position.x + collision_shape_2d.size.x) + 50)
	var y = randi_range(collision_shape_2d.position.y, (collision_shape_2d.position.y + collision_shape_2d.size.y) + 50)
	targetPos = Vector2(x,y)
	#Spawns a Tag to see where the random point is
	var pos = POINT.instantiate()
	pos.position = targetPos
	get_tree().root.add_child(pos)

Shouldn’t you be adding the size to the rand_range from parameter? Something like this
Also size may not be enough. For simplicity, you will have to get the radius of an imaginary circle around your rectangle. I am assuming your position is centered in the rectangle.

	var pos=$StaticBody3D/collision_shape_2d.position
	var sz=$StaticBody3D/collision_shape_2d.size.length() / 2
	var from=pos + sz
	var to=(pos + sz) + 50
	var x = randi_range(from.x, to.x)
	var y = randi_range(from.y, to.y)

I am using a circle for the collision shape 2d so the radius and size I am using are those of the circle and the player is centered in it.

I can’t test this right now, but the basic idea is as follows and I’m pretty sure my math is right.

If your area is a square and you want a square area outside that, run your first range from -1 to 1 for both x and y. This gives you a quadrant your point lies in. then you just scale that value to be within your hollow shape. So if you roll (-0.2, -0.6) and (assume a square) your shape has an outer limit of 6 and an inner limit of 4 you multiple the vector by the difference 2, which gives (-0.4, -1.2) then add (or subtract if negative) 4 to give you a final value for your point of (-4.4, -5.2).

To confirm with limits:
(-1, -1) → (-2, -2) → (-6, -6)
(1, 0) → (2, 0) → (6, 4)

This will work with rectangles, but you’ll need to use vector multipliers instead of scalars. I’m doing it as a square because I don’t want to do that math in my head.

The same procedure works for a circle in polar coordinates. Instead of x and y you have r and θ (theta). You then do some trig math to convert that back to Cartesian space.

This time, your r bound is the radius of your inner circle to radius of outer circle and your θ bound is -π to π (Godot has a PI constant defined). Then, you just convert back:

x = r cos θ
y = r sin θ

That will give you a point between your two circles. It works for an ellipse too, but I’m not getting into that math…

Thanks for sharing, very helpful

It sounds like you’re looking for a range in a donut shape around the character? If so, perhaps something like:

func random_donut_point(center: Vector2, inner: float, outer: float) -> Vector2:
    var angle: float   = randf_range(0.0, TAU)     # Random angle 0..360 degrees.
    var vec:   Vector2 = Vector2.RIGHT             # (0.0, 1.0)
    var dist:  float   = randf_range(inner, outer) # Random length.

    # Put 'em all together...
    return (vec * dist).rotated(angle)

If you hand that your player’s position, the radius of the collision shape for the inner radius (maybe plus a small fudge value so they don’t overlap) and the furthest away you want something to be, it should give you a random point within a circle of the larger radius that doesn’t fall inside the smaller radius.

oooh thanks for sharing this! I’ll probably have a hard time translating this into code but this is a start

oh this is exactly what i needed thank you for sharing