How to get random coords on the surface of a part

Hello, I would like to obtain random coordinates located on the surface of a part. How do I proceed ?

Exemple (not working):

local position = math.random(script.Parent.TopSurface)

Thanks to all!

Start where the Part is initially located, which should always be Part.Position. The Position is always going to be in the center of it, so we to get our Position to the surface point of the Part, which should be Position + Size.Y/2, because the Position is in the center part, that should mean both top and bottom locations are exactly half of the Size on the Y axis, because of this The Top Portion would be Positive, while the Bottom Portion would be negative.

If I had a Part with a Y Axis size of 30, this would mean both sides are exactly 15, in which we can use this information to increment upwards or downwards as a way to reach the end point

From there we have to use the rest of the axes using the same method. Instead of moving our posiion upwards to surface, we are moving it around the length and width of it.

We could tell math.random to use Size.X/2 as a Maximum Value, but we could also use it as a Minimum value for our opposite side.

local randomAxisX = math.random(-Size.X/2, Size.X/2)

From there we can combine them form our new position

local Position = Part.Position -- Current Position
local Size = Part.Size -- Current Size

local randomX = math.random(-Size.X/2, Size.X/2)
-- it will then choose a number based on the size on the X axis
local randomX = math.random(-Size.Z/2, Size.Z/2)
-- it will then choose a number based on the size on the X axis

local Offset = Position + Vector3.new(randomX, Size.Y/2, randomZ)
-- our new position

If you place an Object on that point, its going to be inside the object due to just being on the surface, in which you can use the same method to fix that.

1 Like

If the part is rectangular (on any angle), you can use this function to get a random CFrame of a position somewhere on the top surface of a part:

local function randomOnSurface(part)
	local x,y,z = part.Size.X,part.Size.Y,part.Size.Z
	local xPosition = math.random(-x,x)
	local zPosition = math.random(-z,z)
	local middle = part.CFrame + part.CFrame.UpVector*(y/2)
	local rx,ry,rz = middle:ToOrientation()
	
	return CFrame.new(middle*Vector3.new(xPosition/2,0,zPosition/2))*CFrame.Angles(rx,ry,rz)
end

make sure to pass through the part that will act as the surface.

1 Like

Sorry but what should I do if my part is not rectangular?
It’s more like this:

you could try separating it into two rectangular shapes

And if it’s a triangle? I have differents shapes

You’d probably have to do some complicated math or something to achieve this on any shape.
Another option would be to use my code but repeat it until it is on the surface.

It could be possible if you were to get a vector value of each corner of the part, put it into a table and use this code:

function getRandomPoint(vertices)
	local n = #vertices
	if n < 3 then return end
	
	local point = Vector3.new(0,0,0)
	local vectorWeights = {}
	local total = 0
	
	for i = 1,n do
		local weight = math.random()
		total+=weight
		table.insert(vectorWeights,weight)
	end
	local fixedWeight = 1/total
	for i,weight in vectorWeights do
		vectorWeights[i]*=fixedWeight
	end
	for i,vector in vertices do
		point += vector * vectorWeights[i]
	end
	
	return point
end

local vertices = {
	Vector3.new(0,0,0),
	Vector3.new(10,0,10),
	Vector3.new(20,20,20),
	Vector3.new(5,5,5)
}

local randomPoint = getRandomPoint(vertices)

This works by getting each vector value its own randomly generated weight that pulls the final position in that direction. Ultimately ending with a random spot between the positions.

1 Like