Wow, I mean… WOW!
I absolutely love this!
I tested it out in my game (Works very well), but I DID want to ask 1 question.
I know that the script is local inside of workspace. But I use Knit framework and was wondering if you could help me figure out why it isnt working.
--//Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local FloatingFansFolder = workspace.FloatingFans
--//Modules
local Modules = ReplicatedStorage.Modules
--//Assets
local Assets = ReplicatedStorage:WaitForChild("Assets")
local Animations = Assets.Animations
local Sounds = Assets.Sounds
--//Animations
local FloatingFanAnimations = Animations.Universal.Interaction.FloatingFan
local DiveAnimation = FloatingFanAnimations.Dive
local FloatAnimation = FloatingFanAnimations.Float
--//Sounds
local FloatingFanSounds = Sounds.Universal.Interaction.FloatingFan
local CloseSound = FloatingFanSounds.Close
local FarSound = FloatingFanSounds.Far
local WindSound = FloatingFanSounds.Wind
--//Variables
local DEBUG = false
local FLOAT_ACCELERATION = 100
local INITIAL_FALLING_VELOCITY = -30
local ROTATIONS_PER_SECOND = 3
--//Setup
local initial_time = 0
local anchor_parts = {}
local rotors = {}
local float_areas = {}
local vector_force: VectorForce = script.VectorForce
local current_float_area: BasePart
--//Main
local Knit = require(ReplicatedStorage.Packages.Knit)
--//Module
local FloatingFanController = Knit.CreateController {
Name = "FloatingFanController",
}
--//Start
function FloatingFanController:KnitStart()
vector_force.Attachment0 = Knit.Player.Character.HumanoidRootPart:WaitForChild("RootAttachment")
for i, rotor: BasePart in CollectionService:GetTagged("FloatingFanRotor") do
AddRotor(rotor)
end
CollectionService:GetInstanceAddedSignal("FloatingFanRotor"):Connect(AddRotor)
Knit.Player.Character.Humanoid.StateChanged:Connect(StateChanged)
RunService.PreRender:Connect(PreRender)
for i, fan: Model in FloatingFansFolder: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(CloseSound, anchor_part)
CloneSound(FarSound, anchor_part)
CloneSound(WindSound, float_area)
table.insert(float_areas, float_area)
table.insert(anchor_parts, anchor_part)
end
end
--//Methods
function CloneSound(sound: Sound, parent: BasePart)
sound = sound:Clone()
sound.TimePosition = math.random(10, 100) / 10
sound.Playing = true
sound.Parent = parent
end
function StateChanged(old_state: Enum.HumanoidStateType, new_state: Enum.HumanoidStateType)
if new_state ~= Enum.HumanoidStateType.Freefall and Knit.GetController("AnimationController"):IsPlaying(FloatAnimation) == true and not current_float_area then
Knit.GetController("AnimationController"):StopAnimation(FloatAnimation)
end
end
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
function IsRootPartInCylinder(cylinder: BasePart)
return (Vector2.new(Knit.Player.Character.HumanoidRootPart.Position.X, Knit.Player.Character.HumanoidRootPart.Position.Z) - Vector2.new(cylinder.Position.X, cylinder.Position.Z)).Magnitude <= cylinder.Size.Z / 2 and Knit.Player.Character.HumanoidRootPart.Position.Y <= cylinder.Position.Y + cylinder.Size.Y / 2 and Knit.Player.Character.HumanoidRootPart.Position.Y >= cylinder.Position.Y - cylinder.Size.Y / 2
end
function PreRender(delta_time: number)
local Character: Model = Knit.Player.Character
local RootPart = Knit.Player.Character.HumanoidRootPart
local Humanoid: Humanoid = Knit.Player.Character.Humanoid
local Animator: Animator = Knit.Player.Character.Humanoid.Animator
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 Knit.GetController("AnimationController"):IsPlaying(FloatAnimation) == true then
Knit.GetController("AnimationController"):AdjustSpeed(FloatAnimation, 1 + (math.clamp(math.abs(RootPart.AssemblyLinearVelocity.Y), 0, 100) / 100) * 1.5)
end
if RootPart then
vector_force.Force = Vector3.new(0, RootPart.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 Knit.GetController("AnimationController"):IsPlaying(FloatAnimation) == false then
Knit.GetController("AnimationController"):PlayAnimation(FloatAnimation)
Knit.GetController("AnimationController"):PlayAnimation(DiveAnimation)
end
if RootPart.AssemblyLinearVelocity.Y < 0 then
RootPart.AssemblyLinearVelocity = Vector3.new(RootPart.AssemblyLinearVelocity.X, INITIAL_FALLING_VELOCITY, RootPart.AssemblyLinearVelocity.Z)
end
vector_force.Enabled = true
break
end
end
end
end
return FloatingFanController
If you have any questions let me know!
I do plan to modularize it to only use collection service and some other adjustments + possible performance improvements (If I can).
I didnt want to mess around too much since you would obviously know more about this then me.