Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

How do you change air friction?

Asked by 6 years ago
Edited 6 years ago

So... I looked back into long-ago questions and I saw swimming in the air... and I made this LocalScript in StarterPlayerScripts.

wait()
local player = game:GetService("Players").LocalPlayer
wait(2)
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)
player.Character.Humanoid:SetStateEnabled(Enum.HumanoidStateType.Swimming, true)
for i,v in pairs(Enum.HumanoidStateType:GetEnumItems()) do
    if v ~= Enum.HumanoidStateType.Swimming then
        player.Character.Humanoid:SetStateEnabled(v, false)
    end
end

wait()
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)
wait()
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)
wait()
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)
for _, part in pairs(game:GetService("Players").LocalPlayer.Character:GetChildren()) do
    if part:IsA("BasePart") then
        local F = Instance.new("BodyForce", part)
        F.Force = Vector3.new(0, 196.2, 0) * part:GetMass()
    elseif part:IsA("Accoutrement") then
        local F = Instance.new("BodyForce", part.Handle)
        F.Force = Vector3.new(0, 196.2, 0) * part.Handle:GetMass()
    end
end--]]

The issue is, the BodyForces cause swimming in the air to be more like... well... swimming in the air; there's not enough friction.

How do I modify air friction here?

Response to answer:

I changed the code to this

wait()
local player = game:GetService("Players").LocalPlayer
player.Character.Humanoid.WalkSpeed = 20
wait(2)
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)
player.Character.Humanoid:SetStateEnabled(Enum.HumanoidStateType.Swimming, true)
for i,v in pairs(Enum.HumanoidStateType:GetEnumItems()) do
    if v ~= Enum.HumanoidStateType.Swimming and v ~= Enum.HumanoidStateType.None then
        player.Character.Humanoid:SetStateEnabled(v, false)
    end
end

wait()
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)
wait()
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)
wait()
spawn(function() while true do
    player.Character.Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
    game:GetService("RunService").RenderStepped:Wait()
end end)

-- helper function so we can use a single bodyforce in rootpart 
-- instead of individual bodyforces per part
local function getSummedMass(model)
    local mass = 0 
    for _, v in pairs(model:GetDescendants()) do
        if v:IsA('BasePart') and v.ClassName ~= 'Terrain' then
            mass = mass + v:GetMass()
        elseif v:IsA("Accoutrement") then
            mass = mass + v.Handle:GetMass()
        end
    end

    return mass
end

-- in a loop, RenderStep recommended
while true do
    local rootPart = player.Character.HumanoidRootPart
    local force = Instance.new("BodyForce", rootPart)
    local mass = getSummedMass(player.Character)
    -- no need to convert mass to kg but for reference 1kg = 8000 rbx 
    local p = mass * 1.225
    local v = rootPart.Velocity
    -- a cube has a drag coefficient of 1.05 so we will use that
    local Cd = 1.05
    -- when air 'swimming' with top of head oriented with velocity there is an area of about 3 square studs
    local A = 3^2

    local DragForce = (.5 * p) * (v.Magnitude^2) * Cd * A

    local GravityOffset = Vector3.new(0, mass * workspace.Gravity, 0)

    local ActingForce = (v * DragForce) + GravityOffset

    force.Force = ActingForce
    game:GetService("RunService").RenderStepped:Wait()
end

However, it simply just poofs the whole character goodbye, and triggers a blackscreen. (as in, the character's parts and accessories/hats just go poof, and a never-ending blackscreen pops up, and the character doesn't recover)

So err....

0
merr sweetkid01 176 — 6y
0
You can change the speed of the player to mimic that, "air friction" isn't really a thing... TiredMelon 405 — 6y

1 answer

Log in to vote
6
Answered by 6 years ago

Roblox doesn't model drag force due to air resistance.

A simple model is Drag Force = 1/2 p v^2 Cd A where:

p is the fluid density (at sea level air has a density of 1.225 kg/m^3)

v is the velocity magnitude of the object relative to the fluid (just the objects velocity for the sake of keeping things simple)

Cd is the drag coefficient of the object's current cross section

A is the cross section area.

In code this looks a bit like:

-- helper function so we can use a single bodyforce in rootpart 
-- instead of individual bodyforces per part
local function getSummedMass(model)
    local mass = 0 
    for _, v in pairs(model:GetDescendants()) do
        if v:IsA('BasePart') and v.ClassName ~= 'Terrain' then
            mass = mass + v:GetMass()
        end
    end

    return mass
end

-- in a loop, RenderStep recommended
local rootPart = character.HumanoidRootPart
local mass = getSummedMass(character)
-- no need to convert mass to kg but for reference 1kg = 8000 rbx 
local p = mass * 1.225
local v = rootPart.Velocity
-- a cube has a drag coefficient of 1.05 so we will use that
local Cd = 1.05
-- when air 'swimming' with top of head oriented with velocity there is an area of about 3 square studs
local A = 3^2

local DragForce = (.5 * p) * (v.Magnitude^2) * Cd * A

local GravityOffset = Vector3.new(0, mass * workspace.Gravity, 0)

local ActingForce = (v * DragForce) + GravityOffset

rootPart.BodyForce.Force = ActingForce

If you're not satisfied with a constant cross section surface area; you can work through how I did it. I fire a bunch of rays from a flat plane, determine if there's an intersection with the object, then sum surface areas of each individual triangle formed by truthy intersections. I do this 180 times to capture a surface area for every angle in 2D.

Hope this helps!

Ad

Answer this question