Weirdly enough, even with streaming enabled parts don’t render out of my view when in-game, unlike in Studio, where parts remain parented to the models even when not rendered.
Buuuut, I noticed there are some unnecessary lines and things that can potentially cause errors, like looping through all anchor parts only to find the ones that can move, or checking if the float animation is playing while it hasn’t been loaded yet.
Anyways, I moved stuff around and updated the model. Here’s the new script compared to the old one:
New
--// Constants
local DEBUG = false -- Determines whether or not the float areas will be visible for the player.
local FLOAT_ACCELERATION = 100 -- How fast the player will accelerate upwards regardless of mass.
local INITIAL_FALLING_VELOCITY = -30 -- Sets player's vertical velocity to this value when they enter a float area while falling.
local ROTATIONS_PER_SECOND = 3 -- Spin frequency of the model's fan rotor parts.
--// Services
local COLLECTION_SERVICE = game:GetService("CollectionService")
local PLAYERS = game:GetService("Players")
local RUN_SERVICE = game:GetService("RunService")
--// Variables
-- Fan models
local initial_time = 0
local moving_anchor_parts = {}
local rotors = {}
local float_areas = {}
-- Floating
local character: Model
local humanoid: Humanoid
local root_part: BasePart
local dive_animation: AnimationTrack
local float_animation: AnimationTrack
local vector_force: VectorForce = script.VectorForce
local current_float_area: BasePart
--// Fan model setup
local function CloneSound(sound: Sound, parent: BasePart)
sound = sound:Clone()
sound.TimePosition = math.random(10, 100) / 10
sound.Playing = true
sound.Parent = parent
end
local function SetNewFan(fan: Model)
local float_area: BasePart = fan:WaitForChild("FloatArea")
float_area.Transparency = DEBUG and 0 or 1
table.insert(float_areas, float_area)
local anchor_part: BasePart = fan:WaitForChild("AnchorPart")
local destination: Vector3 = anchor_part:GetAttribute("MoveDelta")
if destination then
anchor_part:SetAttribute("INITIAL_CFRAME", anchor_part.CFrame)
table.insert(moving_anchor_parts, anchor_part)
end
CloneSound(script.Close, anchor_part)
CloneSound(script.Far, anchor_part)
CloneSound(script.Wind, float_area)
end
script.Parent.Models.ChildAdded:Connect(SetNewFan)
for i, fan: Model in script.Parent.Models:GetChildren() do
SetNewFan(fan)
end
--// Rotor spinning
local function AddNewRotor(rotor: BasePart)
table.insert(rotors, rotor)
rotor.Orientation += Vector3.new(0, 0, initial_time * 360 * ROTATIONS_PER_SECOND * rotor:GetAttribute("SpinMark") + math.random(0, 360))
end
COLLECTION_SERVICE:GetInstanceAddedSignal("FloatingFanRotor"):Connect(AddNewRotor)
for i, rotor: BasePart in COLLECTION_SERVICE:GetTagged("FloatingFanRotor") do
AddNewRotor(rotor)
end
--// Detect character added
local function OnStateChanged(old_state: Enum.HumanoidStateType, new_state: Enum.HumanoidStateType)
if new_state ~= Enum.HumanoidStateType.Freefall and float_animation.IsPlaying and not current_float_area then
float_animation:Stop()
end
end
local function SetNewCharacter(new_character: Model)
if new_character then
character = new_character
humanoid = character:WaitForChild("Humanoid")
root_part = character:WaitForChild("HumanoidRootPart")
local animator: Animator = humanoid:WaitForChild("Animator")
dive_animation = animator:LoadAnimation(script.DiveAnim)
float_animation = animator:LoadAnimation(script.FloatAnim)
vector_force.Attachment0 = root_part:WaitForChild("RootAttachment")
humanoid.StateChanged:Connect(OnStateChanged)
end
end
PLAYERS.LocalPlayer.CharacterAdded:Connect(SetNewCharacter)
SetNewCharacter(PLAYERS.LocalPlayer.Character)
--// Frame step
local function IsRootPartInCylinder(cylinder: BasePart)
return (Vector2.new(root_part.Position.X, root_part.Position.Z) - Vector2.new(cylinder.Position.X, cylinder.Position.Z)).Magnitude <= cylinder.Size.Z / 2 and root_part.Position.Y <= cylinder.Position.Y + cylinder.Size.Y / 2 and root_part.Position.Y >= cylinder.Position.Y - cylinder.Size.Y / 2
end
local function OnPreRender(delta_time: number)
initial_time += delta_time
for i, anchor_part: BasePart in moving_anchor_parts do
local initial_cframe: CFrame = anchor_part:GetAttribute("INITIAL_CFRAME")
anchor_part.CFrame = initial_cframe:Lerp(initial_cframe + anchor_part:GetAttribute("MoveDelta"), (math.sin((workspace.DistributedGameTime + anchor_part:GetAttribute("MoveTimeOffset")) * anchor_part:GetAttribute("MoveSpeed")) + 1) * 0.5)
end
for i, rotor: BasePart in rotors do
rotor.Orientation += Vector3.new(0, 0, delta_time * 360 * ROTATIONS_PER_SECOND * rotor:GetAttribute("SpinMark"))
end
if root_part then
vector_force.Force = Vector3.new(0, root_part.AssemblyMass * (workspace.Gravity + FLOAT_ACCELERATION), 0)
if float_animation.IsPlaying then
float_animation:AdjustSpeed(1 + (math.clamp(math.abs(root_part.AssemblyLinearVelocity.Y), 0, 100) / 100) * 1.5)
end
if current_float_area then
if IsRootPartInCylinder(current_float_area) and humanoid.Health > 0 then
return
end
current_float_area = nil
vector_force.Enabled = false
humanoid.HipHeight = humanoid.RigType == Enum.HumanoidRigType.R15 and 2 or 0
end
for i, float_area: BasePart in float_areas do
if IsRootPartInCylinder(float_area) then
current_float_area = float_area
humanoid.HipHeight = humanoid.RigType == Enum.HumanoidRigType.R15 and 0 or -2
if not float_animation.IsPlaying then
float_animation:Play(0.35)
dive_animation:Play(0.2)
end
if root_part.AssemblyLinearVelocity.Y < 0 then
root_part.AssemblyLinearVelocity = Vector3.new(root_part.AssemblyLinearVelocity.X, INITIAL_FALLING_VELOCITY, root_part.AssemblyLinearVelocity.Z)
end
vector_force.Enabled = true
break
end
end
end
end
RUN_SERVICE.PreRender:Connect(OnPreRender)
Old
--// Constants
local DEBUG = false -- Determines whether or not the float areas will be visible for the player.
local FLOAT_ACCELERATION = 100 -- How fast the player will accelerate upwards regardless of mass.
local INITIAL_FALLING_VELOCITY = -30 -- Sets player's vertical velocity to this value when they enter a float area while falling.
local ROTATIONS_PER_SECOND = 3 -- Spin frequency of the model's fan rotor parts.
--// Services
local COLLECTION_SERVICE = game:GetService("CollectionService")
local PLAYERS = game:GetService("Players")
local RUN_SERVICE = game:GetService("RunService")
--// Variables
-- Setup
local initial_time = 0
local anchor_parts = {}
local rotors = {}
local float_areas = {}
local function CloneSound(sound: Sound, parent: BasePart)
sound = sound:Clone()
sound.TimePosition = math.random(10, 100) / 10
sound.Playing = true
sound.Parent = parent
end
for i, fan: Model in script.Parent.Models:GetChildren() do
local float_area: BasePart = fan:WaitForChild("FloatArea")
float_area.Transparency = DEBUG and 0 or 1
local anchor_part: BasePart = fan:WaitForChild("AnchorPart")
local destination: Vector3 = anchor_part:GetAttribute("MoveDelta")
if destination then
anchor_part:SetAttribute("INITIAL_CFRAME", anchor_part.CFrame)
end
CloneSound(script.Close, anchor_part)
CloneSound(script.Far, anchor_part)
CloneSound(script.Wind, float_area)
table.insert(float_areas, float_area)
table.insert(anchor_parts, anchor_part)
end
-- Floating
local character: Model
local humanoid: Humanoid
local root_part: BasePart
local dive_animation: AnimationTrack
local float_animation: AnimationTrack
local vector_force: VectorForce = script.VectorForce
local current_float_area: BasePart
--// Rotor spinning
local function AddRotor(rotor: BasePart)
table.insert(rotors, rotor)
rotor.Orientation += Vector3.new(0, 0, initial_time * 360 * ROTATIONS_PER_SECOND * rotor:GetAttribute("SpinMark") + math.random(0, 360))
end
COLLECTION_SERVICE:GetInstanceAddedSignal("FloatingFanRotor"):Connect(AddRotor)
for i, rotor: BasePart in COLLECTION_SERVICE:GetTagged("FloatingFanRotor") do
AddRotor(rotor)
end
--// Detect character added
local function StateChanged(old_state: Enum.HumanoidStateType, new_state: Enum.HumanoidStateType)
if new_state ~= Enum.HumanoidStateType.Freefall and float_animation.IsPlaying and not current_float_area then
float_animation:Stop()
end
end
local function CharacterAdded(new_character: Model)
if new_character then
character = new_character
humanoid = character:WaitForChild("Humanoid")
root_part = character:WaitForChild("HumanoidRootPart")
local animator: Animator = humanoid:WaitForChild("Animator")
dive_animation = animator:LoadAnimation(script.DiveAnim)
float_animation = animator:LoadAnimation(script.FloatAnim)
vector_force.Attachment0 = root_part:WaitForChild("RootAttachment")
humanoid.StateChanged:Connect(StateChanged)
end
end
PLAYERS.LocalPlayer.CharacterAdded:Connect(CharacterAdded)
CharacterAdded(PLAYERS.LocalPlayer.Character)
--// Frame step
local function IsRootPartInCylinder(cylinder: BasePart)
return (Vector2.new(root_part.Position.X, root_part.Position.Z) - Vector2.new(cylinder.Position.X, cylinder.Position.Z)).Magnitude <= cylinder.Size.Z / 2 and root_part.Position.Y <= cylinder.Position.Y + cylinder.Size.Y / 2 and root_part.Position.Y >= cylinder.Position.Y - cylinder.Size.Y / 2
end
local function PreRender(delta_time: number)
initial_time += delta_time
for i, anchor_part: BasePart in anchor_parts do
local initial_cframe: CFrame = anchor_part:GetAttribute("INITIAL_CFRAME")
if initial_cframe then
anchor_part.CFrame = initial_cframe:Lerp(initial_cframe + anchor_part:GetAttribute("MoveDelta"), (math.sin((workspace.DistributedGameTime + anchor_part:GetAttribute("MoveTimeOffset")) * anchor_part:GetAttribute("MoveSpeed")) + 1) * 0.5)
end
end
for i, rotor: BasePart in rotors do
rotor.Orientation += Vector3.new(0, 0, delta_time * 360 * ROTATIONS_PER_SECOND * rotor:GetAttribute("SpinMark"))
end
if float_animation.IsPlaying then
float_animation:AdjustSpeed(1 + (math.clamp(math.abs(root_part.AssemblyLinearVelocity.Y), 0, 100) / 100) * 1.5)
end
if root_part then
vector_force.Force = Vector3.new(0, root_part.AssemblyMass * (workspace.Gravity + FLOAT_ACCELERATION), 0)
if current_float_area then
if IsRootPartInCylinder(current_float_area) and humanoid.Health > 0 then
return
end
current_float_area = nil
vector_force.Enabled = false
humanoid.HipHeight = humanoid.RigType == Enum.HumanoidRigType.R15 and 2 or 0
end
for i, float_area: BasePart in float_areas do
if IsRootPartInCylinder(float_area) then
current_float_area = float_area
humanoid.HipHeight = humanoid.RigType == Enum.HumanoidRigType.R15 and 0 or -2
if not float_animation.IsPlaying then
float_animation:Play(0.35)
dive_animation:Play(0.2)
end
if root_part.AssemblyLinearVelocity.Y < 0 then
root_part.AssemblyLinearVelocity = Vector3.new(root_part.AssemblyLinearVelocity.X, INITIAL_FALLING_VELOCITY, root_part.AssemblyLinearVelocity.Z)
end
vector_force.Enabled = true
break
end
end
end
end
RUN_SERVICE.PreRender:Connect(PreRender)