How to make a tornado pull?

Hey, I’m making a weather system and I want to add a tornado to it. The tornado is a part with particle emitters and beams.

How would I make the tornado pull players and make them spin around the tornado while going upwards?

Any help is appreciated :grinning:


I have never made a tornado, but I did at one time, make a giant toilet that made the players rotate around like a whirlpool if they were in the bowl when it flushed.

The way I did it, was to have a series of points, sort of in a ever tightening spiral as it moved down, and I would just use body movers (although now I would use AlignPosition) to move the players to each node.

However, if I were to re-do it, I would probably just use a mathematical formula, probably some sin and cos to move them with AlignPosition in a spiral motion.

1 Like

Yeah, I’m hoping to use some formula and use align position to create that spiral motion. Thank you :grinning:

1 Like

:hammer: you could make an invisible box around the tornado that carries false collisions so that when a player touches it then drag it spinning to the center, you could spin with Cframe.Angles from the HumanoidRootPart and also make it Cframe to the center or somew

I already have all the player’s HumanoidRootPart. I just need a function that pulls them toward the tornado with a force that increases the closer the player is to the tornado and then spirals the player up :grinning:

You could try getting the difference in positions and then slightly rotating it!

I’m not sure what you mean by this.

CFrame.fromEulerAngles((tornadoPosition - playercharacterPosition).Unit) * CFrame.Angles(0,3,0)
Calculating the Vector3 force required to bring the player directly to the tornado, and then slightly turning the Vector3.

I see, and how would I apply the CFrame to the HumanoidRootPart? With a VectorForce, ApplyImpulse, etc.?

You could extract the LookVector and then use that in a LineForce or just set the velocity of the character itself.

How I imagine this would work is get the difference in CFrame from the player and the Tornado, we’ll call this Diff we’ll also store some distance data.

Diff = TornadoCFrame * Player.CFrame:Inverse()
MaxDist = 300--maximum distance from the tornado
MinDist = 15--eye of the storm

Then we offset that CFrame to get our next desired position.
We’ll call this NextCFrame

--rotate the tornado angle
NextCFrame = TornadoCFrame * CFrame.Angles(0,math.rad(90),0) * Diff

Next we need to calculate a direction to go FLING!
We’ll call this Fling :stuck_out_tongue: it requires a few steps to set up

MaxPower = 300
FlingAngle =,NextCFrame.Position).LookVector
FlingDist = (CharacterPos - NextCFrame.Position).Magnitude--how far away?
--get number between 1 and 0 to represent our distance from 15-300
FlingPower = (FlingDist - MinDist)/(MaxDist - MinDist)) -- 'ol reliable (Val - Min)/(Max - Min)
Fling = FlingAngle * (FlingPower*MaxPower)

Then we should be able to apply this velocity to a player!

PrimaryPart.Velocity = Fling

disclaimer: i wrote this all here and is untested incomplete. only conceptual code snippets to get a general idea of how something like this could work

hope that helps :slight_smile:


How would I apply the Fling as Velocity is deprecated :thinking:



1 Like

Also please use local variables instead of global as that its better for long term use.

This is my current code :grinning:

local MaxPower = 300
local MaxDist = 300
local MinDist = 15

function SimulateTornado(tornado)
		for _,player in pairs(Players:GetPlayers()) do
			local character = player.Character
			if not character then continue end
			local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
			if not humanoidRootPart then continue end
			local Diff = tornado.Part.CFrame * humanoidRootPart.CFrame:Inverse()
			local NextCFrame = tornado.Part.CFrame * CFrame.Angles(0, math.rad(90), 0) * Diff
			local FlingAngle =, NextCFrame.Position).LookVector
			local FlingDist = (humanoidRootPart.Position - NextCFrame.Position).Magnitude
			local FlingPower = (FlingDist - MinDist)/(MaxDist - MinDist)
			local Fling = FlingAngle * (FlingPower * MaxPower)
			humanoidRootPart.AssemblyLinearVelocity = Fling

This is the result I’m getting. What is wrong?

I didn’t add force to throw you in the air. oops :open_mouth:
Just add an upforce value and add it to the Force

UpForce =,FlingPower*MaxForce,0)--add more upward force the closer you get
Fling = Fling + UpForce

also my calculations are probably wrong somewhere
untested code*** :sweat_smile:

This is much better. However, the character is moved depending on what way it is facing. I think this has something to do with this line:

local FlingAngle =, NextCFrame.Position).LookVector

How can I fix this?

Try using CFrame.lookAt to see if that changes anything.

That didn’t change anything :thinking:

local FlingAngle = CFrame.lookAt(humanoidRootPart.Position, NextCFrame.Position).LookVector

Try using CFrame for the position lines.