How to move a part in a random direction on x,z planes?

It’s crazy that I can’t find any answers already on the forum for this… but… how do you take a model, and move it in a random direction? I.e., taking x,z axis, and picking a random angle (0-360 degrees), and moving forwards on that random angle?

  • Ignoring Y axis - keeping it at exacly the same height.
  • The model contains a primaryPart (which is a box with a decal on the top).
  • I want collisions to work for it as normal. When it hits a wall, it’s going to bounce.
  • It should just move in that direction until I say otherwise.
	part.Anchored=false
	local randomVector = Vector3.new(math.random(-math.pi * 90, math.pi * 90), 0, math.random(-math.pi * 90, math.pi * 90))
	--monster.wsObj.AssemblyLinearVelocity=randomVector --tried this because .Velocity is deprecated

	local bodyVelocity = Instance.new("BodyVelocity", part)
	bodyVelocity.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
	--bodyVelocity.Velocity = Vector3.new(0.5,0,0)
	bodyVelocity.Velocity = randomVector * 500000 -- tried 1,5, 50, 500

Some of my problems are… if it moves, it shoots off way too fast. Or, if I set MaxForce to low values, it only moves a short distance then stops. And I think the random Vector3 has a potential to make (0,0,0) (or near to it) resulting in no movement sometimes. I want to guarantee it moves, and not to calculate the X and Z both randomly (as they could both end up as 0).

Lovely post with the real programming, im happy to help you, so lets start.

The BodyVelocity is DEPRECATED, instead, use LinearVelocity

I would use math.cos and math.sin, for example:

local part = workspace.Part

local function getround()
	local randomnumber1 = math.random(20,100)
	local randomnumber2 = math.random(1,100)
	local randomnumber3 = math.random(1,100)

	print(randomnumber1, randomnumber2, randomnumber3)

	local randompartofthecircle = (randomnumber1 / 100) * 2 * math.pi

	local x = math.cos(randompartofthecircle) * randomnumber2
	local z = math.sin(randompartofthecircle) * randomnumber3

	return Vector3.new(x, 0, z)
end

local result = getround()

local attachment = Instance.new("Attachment", part)

local linearVelocity = Instance.new("LinearVelocity", part)
linearVelocity.Attachment0 = attachment
linearVelocity.VectorVelocity = result * 4
linearVelocity.MaxForce = 10000000

task.wait(0.24)

attachment:Destroy()
linearVelocity:Destroy()

This script will move the object to a random direction i didnt understand about

picking a random angle (0-360 degrees), and moving forwards on that random angle

You mean about the object spinning and then moving to the front?

If thats the case, heres the script extended:

local function infinite()
	local part = workspace.Part

	local function getround()
		local randomnumber1 = math.random(20,100)
		local randomnumber2 = math.random(1,100)
		local randomnumber3 = math.random(1,100)

		print(randomnumber1, randomnumber2, randomnumber3)

		local randompartofthecircle = (randomnumber1 / 100) * 2 * math.pi

		local x = math.cos(randompartofthecircle) * randomnumber2
		local z = math.sin(randompartofthecircle) * randomnumber3

		return Vector3.new(x, 0, z)
	end

	local result = getround()

	local attachment = Instance.new("Attachment", part)
	local linearVelocity = Instance.new("LinearVelocity", part)
	local angularvelocity = Instance.new("AngularVelocity", part)

	linearVelocity.Attachment0 = attachment
	linearVelocity.VectorVelocity = result * 4
	linearVelocity.MaxForce = 10000000

	task.wait(0.24)

	linearVelocity.MaxForce = 0

	task.wait(4)

	angularvelocity.Attachment0 = attachment
	angularvelocity.AngularVelocity = Vector3.new(0, math.random(-100, 100), 0)
	angularvelocity.MaxTorque = 10000000

	task.wait(3)

	angularvelocity:Destroy()

	task.wait(3)

	linearVelocity.VectorVelocity = part.CFrame.LookVector * 60
	linearVelocity.MaxForce = 10000000

	task.wait(0.24)

	linearVelocity:Destroy()
	attachment:Destroy()

	task.wait(5)

	infinite()
end

infinite()

Hope it helps!

Just one important note, depending of the Density of the Objects that are in the model, you will need huge amount of force to move them, so check that ok?

1 Like

Thanks, I’ll work on that and see how it goes. And I’ll switch to LinearVelocity first.

I see how your ‘randompartofthecircle’ calc is picking a random point on the circle, and then you’re using COS and SIN to get the X and Z elements of it. Why is randomnumber1 between 20 and 100, and not 0 and 100?

This script will move the object to a random direction i didnt understand about

You mean about the object spinning and then moving to the front?

I iust mean… if it was moving at 37°, for it just to move directly in that direction, no-questions-asked. (Except collisions). This is a top-down pseudo-2D game (hence, no Y-axis movements), which is why ‘random direction’ is just a matter of degrees in X,Z plane.

I’ll come mark as Accepted answer (may take a few days, I’m only a spare-time developer).

i placed a number between 20 and 100 because you said:

I want to guarantee it moves

if i place between 0 and 100, it can be 0, and if its 0, the entire calculation wont work, because everything is being multiplied, and everything multiplied by 0, is 0, meaning here that i wont move, you can place between 1 and 100 tho.

If the object is just going to move to a random direction, so you use the first script:

local part = workspace.Part

local function getround()
	local randomnumber1 = math.random(20,100)
	local randomnumber2 = math.random(1,100)
	local randomnumber3 = math.random(1,100)

	print(randomnumber1, randomnumber2, randomnumber3)

	local randompartofthecircle = (randomnumber1 / 100) * 2 * math.pi

	local x = math.cos(randompartofthecircle) * randomnumber2
	local z = math.sin(randompartofthecircle) * randomnumber3

	return Vector3.new(x, 0, z)
end

local result = getround()

local attachment = Instance.new("Attachment", part)

local linearVelocity = Instance.new("LinearVelocity", part)
linearVelocity.Attachment0 = attachment
linearVelocity.VectorVelocity = result * 4
linearVelocity.MaxForce = 10000000

task.wait(0.24)

attachment:Destroy()
linearVelocity:Destroy()

Hope it helps!

You inspired me to think about circles properly.

Firstly, randomnumber1 can indeed be 0. If 0, this also comes out as 0:

local randompartofthecircle = (randomnumber1 / 100) * 2 * math.pi

and that’s fine, because SIN,COS of (0) gives (0,1), which is ‘straight up’, which is 0 degrees, which is valid and good. So, we have:

local randomnumber1 = math.random(0,100)
local radian = (randomnumber1 / 100) * 2 * math.pi

But there’s no point making a number 0-100 then dividing by /100. So, we can just use math.random() on its own, which gives a 0-1 number. Therefore:

local radian = math.random() * 2 * math.pi

From that, math.cos(radian) gives the X component, and math.sin(radian) gives the Z. There’s no need to multiply those by randomnumber 2 and 3, as the radian gave the full randomness required for the direction.

In short, here’s the final version:

function randomXZDirection():Vector3
	local radians = math.random() * 2 * math.pi --random point on circle
	return Vector3.new(math.cos(radians), 0, math.sin(radians)) --Extract X and Z component from the angle
end

I added the :Vector3 on the end, so Roblox Studio knows what kind of value it returns and can do better autocomplete when calling it. If you add this ‘final version, after discussion (see comments)’ to your solution (or post a new answer), I’ll mark it!

Thanks for the initial code and inspiration,