After trying to help someone make floating ballons here, I kinda got caught up in the idea and spent most of yesterday playing around with it. Being farily content with the results I figured I’d post a little guide on how to do it. This was a Saturday afternoon project so it’s far from perfect but I thought it was fun so here it is.
The script below with the described rig makes floating ballons the player can grab and drag along with them. With enough ballons held, (currently 5) the air density will be increased and the player will start to float away for however many seconds floatTime is set to. If time runs out you can quickly click a ballon to release it then click it again to start the air density timer over again.
The ballons could look better and they do spin about themselves quite quickly at times and they snap to the player in an rather abrupt manner but they work for a quick example of what Studio’s Beta feature “Aerodynamics” can do. Not sure what (if anything) happens to free (unheld ballons) , they should eventually come down but they do rise really quickly when not held, may need to Destroy/respawn if Y > 1000 or something.
Requires the currently Beta Studio feature “Aerodynamics” to be enabled as of posting. File>Beta Features, place a checkmark in “Aerodynamics” and restart Studio if prompted.
Setting game.Workspace.AirDensity to 0.02 seems to be a good starting point.
Optional: Provide a small vector (10, 0, 0) to game.Workspace.GlobalWind to get carried away by the wind when floating.
Save this script as a “Script” in ServerScriptService folder, put ballon models in a Workspace folder named “Ballons”.
Ballon model heirarchy as follows:
-Ballon model (named YellowBallon)
–Ballon part (named Ballon)
—Attachment (named BallonRopeAttach)
—Rope Constraint (named RopeConstraint)
—Weight part (named Weight)
----Attachment (named WeightRopeAttach)
Settings for ballon rig are as follows:
Ballon part: shape ball, size 4, preferably a color that’s not red, CustomPhysicalProperties enabled and Density set to 0.0195, position 10 units up along Y.
Ballon Attachment: position one stud below the ballon part along Y.
Rope Constraint: set Attachment0 to the BallonRopeAttch, set Attachment1 to the WeightRopeAttach. Rope.Length 10, Rope.Restitution 0.9.
Weight part: position 4-6 studs below the ballon part, shape ball, size 1,1,1, transparency 1, CustomPhysicalProperties enabled and Density set to 0.07
Create the ballon model then duplicate it for as many ballons as you need. Offset duplicates by some amount, clicks may not register correctly if ballons are in the same position. The comments should explain it all but if you have any quesions ask away.
Enjoy!
--the script
local ballons = game.Workspace.Ballons:GetChildren() --get all the ballon models in the Workspace.Ballons folder
local players = game:GetService("Players") --get the current players
local heldColor = Color3.fromRGB(255, 0, 0) --the color red... the ballon color will change to this when held
local startingAirDensity = game.Workspace.AirDensity --original air density value
local tempAirDensity = 0.5 --value to increase the air density to, a higher value = faster rise
local floatTime = 20 --duration in seconds, air density is increased during this time
local heldBallonsToTrigger = 5 --number of ballons that need to be held before triggering the air density change
local function SetAirDensity(density: number) --function to change the Air Density
game.Workspace.AirDensity = density --set the new density
end
for _, ballon in ballons do --for each model in ballons
--print("Found Model: " .. ballon.Name) --print the name of the model
local bp = ballon.Ballon --get the ballon part
bp:SetAttribute("OriginalColor", bp.Color) --create an attribute to save the ballons current color
local cd = Instance.new("ClickDetector") --create a click detector
cd.Parent = ballon --parent the click dectector to the model
cd.MouseClick:Connect(function(player) --when the ballon is clicked
local char = game.Workspace:FindFirstChild(player.Name) --get the player character
local playerBC = char:GetAttribute("BallonCount") --get the player ballon count, can be nil
if playerBC == nil or playerBC <= 0 then --if it doesn't exist or is less or equal to 0
char:SetAttribute("BallonCount", 1) --create the attribute and set it to 1
playerBC = 1
else --if the attribute exists
playerBC += 1 --increment the player ballon count by 1
char:SetAttribute("BallonCount", playerBC) --set the attribute to the new ballon count
end
--print("Ballon Count is: " .. playerBC)
local held = ballon:GetAttribute("Held") --get the Held attribute from the ballon
local rp = bp.RopeConstraint --get the rope constraint on the ballon part
if held then --if true the ballon is currently being held
ballon:SetAttribute("Held", false) --set the Held attribute to false
local weight = bp.Weight --get the ballons weight part
local weldWeight = weight.WeldConstraint --get the weldconstraint
weldWeight:Destroy() --destroy the weldconstraint
weight.CFrame = CFrame.new(bp.Position + Vector3.new(0, -3, 0)) --move the weight back under the ballon
weight.CanTouch = true --disable CanTouch
weight.CanCollide = true --disable CanCollide
weight.Massless = false --enable Massless
rp.Attachment1 = weight.WeightRopeAttach --set rope attachment1 back to the weight
rp.Length = 10 --reset rope length
bp.Color = bp:GetAttribute("OriginalColor") --change the ballon back to it's original color
playerBC -= 1 --reduce ballon count
char:SetAttribute("BallonCount", playerBC)
return --stop here
end
--if we're here, the ballon was not being held so grab it
local wrist = char.RightHand.RightGripAttachment --get the characters RightGripAttachment
ballon:SetAttribute("Held", true) --set the Held attribute to true
rp.Attachment1 = wrist --attach the ballon string to the players right hand
rp.Length = 15 --makes the rope a bit longer
bp.Color = heldColor --change the ballon color to the heldColor
local weight = bp.Weight --get the ballons weight part, we're going to "hide" it inside the ballon
weight.CFrame = CFrame.new(bp.Position) --move the weight into the middle of the ballon
local weldWeight = Instance.new("WeldConstraint", weight) --create a weldconstraint and parent to weight
weldWeight.Part0 = weight --set the first weld to the weight part
weldWeight.Part1 = bp --set the second weld to the ballon part
weight.CanTouch = false --disable CanTouch, it's inside the ballon, nothing should touch it
weight.CanCollide = false --disable CanCollide, again inside ballon.
weight.Massless = true --enable massless so the weight doesn't affect the ballon
if playerBC >= heldBallonsToTrigger then --if holding more than heldBallonsToTrigger ballons
--print("Increasing AirDensity for 20 seconds.")
SetAirDensity(tempAirDensity) --increase the air density
task.wait(floatTime) --time in seconds the air density will be increased for.
SetAirDensity(startingAirDensity) --return the air density back to what it was
--print("AirDensity returned to normal.")
end
end)
end