Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --!native
- --!strict
- local GrassPhysics = {}
- GrassPhysics.__index = GrassPhysics
- -- Services
- local Players = game:GetService("Players"); Players.LocalPlayer.CharacterAdded:Wait()
- local CollectionService = game:GetService("CollectionService")
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local TweenService = game:GetService("TweenService")
- local RunService = game:GetService("RunService")
- -- Constants
- local Root = workspace
- local Camera = Root.CurrentCamera
- local Player = Players.LocalPlayer
- local Character: Model = nil
- local Humanoid: Humanoid = nil
- local HumanoidRootPart: BasePart = nil
- type WindShakeConfig = {
- Enabled: boolean,
- ScriptPath: {
- Enabled: boolean,
- Path: string?
- }
- }
- type ScriptPathConfig = {
- Enabled: boolean,
- Path: string?
- }
- GrassPhysics.Config = {
- WindShake = {
- Enabled = false, -- Enable/disable wind shake effect, ENABLING THIS DOES NOT ADD IT INTO YOUR CODE! You must set it up yourself, but turn this on if you have it shake the grass using wind.
- ScriptPath = {
- Path = nil -- Path to the wind shake script, not the module, the script that requires it, example: Players.LocalPlayer.PlayerScripts.WindControllerClient
- } :: ScriptPathConfig
- } :: WindShakeConfig,
- OcclusionCulling = {
- HideGrass = {
- Enabled = false -- Enable/disable hiding grass when its not visible on the screen, can improve performance but may cause bugs.
- }, -- ONLY KEEP ONE OF THESE ENABLED, THE OTHER ONE FALSE
- DisablePhysics = {
- Enabled = false -- Enable/disable disabling grass physics when the grass isn't visible on the screen, can improve performance.
- },
- },
- Sound = {
- Enable = true, -- Enable/disable sound effects
- Volume = 0.1, -- Volume of the plant sound effects (0.0 - 1.0)
- PitchRange = { -- Range for randomizing pitch of plant sounds
- Min = 0.8,
- Max = 1.0
- },
- Reverb = { -- Reverb settings for the sound
- Enable = false,
- DecayTime = 2.0,
- ReflectLevel = 0.5
- },
- Spatial = { -- Spatial audio settings
- Enable = true,
- RolloffMode = Enum.RollOffMode.Linear,
- MinDistance = 10,
- MaxDistance = 100
- }
- },
- Tween = {
- Duration = 2, -- Default duration of animation tweens in seconds
- EasingStyle = Enum.EasingStyle.Elastic, -- Default easing style for animation tweens
- EasingDirection = Enum.EasingDirection.Out, -- Default easing direction for animation tweens
- TweenName = "pivotTween", -- Default name for the tween instance
- -- Object-specific tween settings
- ObjectTweens = {
- ["ExampleObject"] = {
- Duration = 1.4,
- EasingStyle = Enum.EasingStyle.Exponential,
- EasingDirection = Enum.EasingDirection.Out
- },
- }
- },
- Physics = {
- HitboxRadius = 200, -- Radius around the hitbox within which effects will be activated
- Intervals = {
- UpdateInterval = 0.1, -- Update interval for checking activations and camera positions
- CameraUpdateFactor = 2, -- Factor to control how often camera updates are checked
- ActivationUpdateFactor = 2 -- Factor to control how often activation updates are checked
- }
- },
- Grass = {
- Tag = "Grass", -- Tag used to identify grass objects, changing this can break the plugin
- HitboxTag = "Hitbox", -- Tag used to identify hitbox objects, changing this can break the plugin
- Transparency = 1, -- Transparency level of the hitbox
- CollisionResponse = { -- Collision response settings for the grass
- Bounce = 0.1,
- }
- },
- Camera = {
- FieldOfViewThreshold = 2, -- Additional degrees to the camera's field of view for angle checks
- MovementThreshold = 1 -- Minimum movement in position or rotation to consider camera as moved
- },
- SoundAsset = {
- SoundEnabled = true,
- SoundLimit = 50, -- Keep this low, but not too low or your sounds will sound ugly.
- SoundMappings = {
- Grass = {
- SoundId = "rbxassetid://8008438167",
- VolumeRange = { Min = 0, Max = 0.25 }
- },
- }
- },
- Debug = {
- EnableLogging = false, -- Enable or disable debug logging
- ExtraLogging = false, -- Extra debug logging, may flood your output; must have Enable Logging set to true for this to work
- LogFrequency = 5 -- Number of updates between log entries
- }
- }
- --[[
- The following code is created by varuniemcfruity for the "Interactive Grass" plugin on ROBLOX.
- If you need to contact me, please send a private message through the developer forum or reach out to me via my profile.
- Please respect my work by not stealing or reselling this code. If you have purchased the plugin, you are welcome to use it in all of your games.
- However, redistribution for profit or sharing the code for free is prohibited.
- ]]--
- -- Internal Data
- local grassInfo = {}
- local hitboxInfo = {}
- local activeObjects = {}
- local playerEvents = {}
- local physicsEvents = {}
- local hitboxEvents = {}
- local timeTracker = 0
- local updateCounter = 0
- local lastCamCFrame = Camera.CFrame
- local TW_INFO = TweenInfo.new(
- GrassPhysics.Config.Tween.Duration,
- GrassPhysics.Config.Tween.EasingStyle,
- GrassPhysics.Config.Tween.EasingDirection
- )
- local UP_VECTOR = Vector3.FromNormalId(Enum.NormalId.Back)
- local ROT_CFRAME = CFrame.Angles(0, math.rad(-90), math.rad(90))
- local SQRT_3 = math.sqrt(3)
- local INTERVAL = GrassPhysics.Config.Physics.Intervals.UpdateInterval
- local HITBOX_RADIUS = GrassPhysics.Config.Physics.HitboxRadius
- -- Debugging Functions
- local function logDebug(message)
- if GrassPhysics.Config.Debug.EnableLogging then
- print("[GrassPhysics Debug]: " .. message)
- end
- end
- -- Tweening Functions
- local function createTween(obj: Instance, info, properties): Tween
- local tween = TweenService:Create(obj, info, properties)
- tween:Play()
- return tween
- end
- local function getTweenInfoForPart(partName: string): TweenInfo
- local objectTweenConfig = GrassPhysics.Config.Tween.ObjectTweens[partName]
- if objectTweenConfig then
- return TweenInfo.new(
- objectTweenConfig.Duration,
- objectTweenConfig.EasingStyle,
- objectTweenConfig.EasingDirection
- )
- else
- return TW_INFO
- end
- end
- local function initiateTween(name: string, basePart: BasePart, targetCFrame: CFrame): ()
- if basePart:FindFirstChild(name) then
- local tween = basePart:FindFirstChild(name)
- tween:Destroy()
- end
- local tweenInfo = getTweenInfoForPart(basePart.Name)
- local tween = createTween(basePart, tweenInfo, { CFrame = targetCFrame })
- tween.Name = name
- tween.Parent = basePart
- tween.Completed:Connect(function()
- tween:Destroy()
- end)
- end
- -- Sound Functions
- local function playSound(hitbox: BasePart, part: BasePart)
- local partParent = part.Parent :: BasePart
- local partType = partParent.Name
- local soundConfig = GrassPhysics.Config.SoundAsset.SoundMappings[partType]
- local soundCount = 0
- for _, child in pairs(hitbox:GetChildren()) do
- if child:IsA("Sound") then
- soundCount = soundCount + 1
- end
- end
- if soundCount >= GrassPhysics.Config.SoundAsset.SoundLimit then
- logDebug("Hitbox sound limit reached. New sound not added.")
- return
- end
- local partParent = part.Parent :: BasePart
- local partType = partParent.Name
- local soundConfig = GrassPhysics.Config.SoundAsset.SoundMappings[partType]
- if GrassPhysics.Config.Sound.Enable and soundConfig then
- local sound = Instance.new("Sound", hitbox)
- sound.SoundId = soundConfig.SoundId
- local pitchShift = Instance.new("PitchShiftSoundEffect", sound)
- pitchShift.Octave = math.random(
- GrassPhysics.Config.Sound.PitchRange.Min * 100,
- GrassPhysics.Config.Sound.PitchRange.Max * 100
- ) / 100
- sound.Volume = math.random(
- soundConfig.VolumeRange.Min * 100,
- soundConfig.VolumeRange.Max * 100
- ) / 100
- sound:Play()
- delay(sound.TimeLength, function()
- sound:Destroy()
- end)
- if GrassPhysics.Config.Sound.Reverb.Enable then
- local reverb = Instance.new("ReverbSoundEffect", sound)
- reverb.DecayTime = GrassPhysics.Config.Sound.Reverb.DecayTime
- reverb.Density = GrassPhysics.Config.Sound.Reverb.ReflectLevel
- end
- if GrassPhysics.Config.Sound.Spatial.Enable then
- sound.RollOffMode = GrassPhysics.Config.Sound.Spatial.RolloffMode
- sound.RollOffMinDistance = GrassPhysics.Config.Sound.Spatial.MinDistance
- sound.RollOffMaxDistance = GrassPhysics.Config.Sound.Spatial.MaxDistance
- end
- end
- end
- function GrassPhysics:toggleSoundsEnabled(boolean: boolean)
- local soundConfig = GrassPhysics.Config.Sound
- soundConfig.Enabled = boolean
- end
- -- Windshake Functions
- local function toggleWindShake(boolean: boolean)
- local windShakeConfig = GrassPhysics.Config.WindShake
- logDebug("WindShake Enabled: " .. tostring(windShakeConfig.Enabled))
- if windShakeConfig.Enabled then
- local windShakePath = windShakeConfig.ScriptPath
- if windShakePath then
- logDebug("WindShake ScriptPath: " .. tostring(windShakePath))
- local windShakeScript = Players.LocalPlayer.PlayerScripts:FindFirstChild(tostring(windShakePath.Path))
- if windShakeScript then
- logDebug("Found WindShakeScript: " .. windShakeScript.Name)
- if windShakeScript:IsA("Script") then
- windShakeScript.Disabled = not boolean
- logDebug("WindShakeScript Disabled set to: " .. tostring(windShakeScript.Disabled))
- else
- logDebug("WindShakeScript is not a Script object.")
- end
- else
- logDebug("WindShakeScript not found at path: " .. tostring(windShakePath.Path)) -- Correct logging
- end
- else
- logDebug("WindShake.ScriptPath is not defined.")
- end
- else
- logDebug("WindShake is not enabled; no action taken.")
- end
- end
- function GrassPhysics:toggleWindEnabled(boolean: boolean)
- local windShakeConfig = GrassPhysics.Config.WindShake
- windShakeConfig.Enabled = boolean
- end
- -- Physics Functions
- local function activateEffect(hitbox: BasePart): ()
- physicsEvents[hitbox] = {
- Touched = hitbox.Touched:Connect(function(part: BasePart)
- if not grassInfo[part] or not grassInfo[part].Eligible then return end
- if table.find(activeObjects, part) then return end
- local partParent = part.Parent :: BasePart
- table.insert(activeObjects, part)
- local rotation = partParent:GetAttribute("Rotation")
- local info = grassInfo[part]
- local direction = ((hitbox.Position - part.Position) * -Vector3.new(1, 0, 1)).Unit * part.Size.Y / SQRT_3
- local targetLook = info.Top + direction
- local targetPos = info.Base + (targetLook - info.Base).Unit * part.Size.Y / 2
- local finalCFrame = CFrame.lookAt(targetPos, targetLook, UP_VECTOR) * ROT_CFRAME * CFrame.Angles(rotation.X, rotation.Y + math.rad(90), rotation.Z)
- initiateTween(GrassPhysics.Config.Tween.TweenName, partParent, finalCFrame)
- playSound(hitbox, part)
- logDebug("Activated effect for part: " .. part.Name)
- toggleWindShake(false)
- end),
- TouchEnded = hitbox.TouchEnded:Connect(function(part: BasePart)
- local idx = table.find(activeObjects, part)
- if not grassInfo[part] or not idx then
- return
- end
- local partParent = part.Parent :: BasePart
- local touchingParts = hitbox:GetTouchingParts()
- local stillTouching = false
- table.remove(activeObjects, idx)
- initiateTween(GrassPhysics.Config.Tween.TweenName, partParent, part.CFrame)
- logDebug("Ended touch effect for part: " .. part.Name)
- for _, touchingPart in touchingParts do
- if touchingPart:IsA("BasePart") and grassInfo[touchingPart] and table.find(activeObjects, touchingPart) then
- stillTouching = true
- break
- end
- end
- local windShakeConfig = GrassPhysics.Config.WindShake
- local windShakePath = windShakeConfig.ScriptPath
- local windShakeScript = Players.LocalPlayer.PlayerScripts:FindFirstChild(tostring(windShakePath.Path))
- if not stillTouching then
- toggleWindShake(true)
- end
- end)
- }
- end
- local function deactivateEffect(hitbox: BasePart): ()
- if physicsEvents[hitbox] then
- physicsEvents[hitbox].Touched:Disconnect()
- physicsEvents[hitbox].TouchEnded:Disconnect()
- physicsEvents[hitbox] = nil
- logDebug("Deactivated effect for hitbox: " .. hitbox.Name)
- end
- end
- -- Grass Functions
- function GrassPhysics:enableGrass(grass: BasePart): ()
- local hitbox = grass:FindFirstChild("Hitbox") :: BasePart
- hitbox.CanTouch = true
- end
- function GrassPhysics:disableGrass(grass: BasePart): ()
- local hitbox = grass:FindFirstChild("Hitbox") :: BasePart
- local idx = table.find(activeObjects, hitbox)
- if idx then
- table.remove(activeObjects, idx)
- end
- hitbox.CanTouch = false
- if grass:FindFirstChild(GrassPhysics.Config.Tween.TweenName) then
- local tween = grass:FindFirstChild(GrassPhysics.Config.Tween.TweenName) :: Tween
- tween:Cancel()
- end
- grass.CFrame = hitbox.CFrame
- end
- local function resetGrass(grass: BasePart): ()
- local hitbox = grass:FindFirstChild("Hitbox") :: BasePart
- local idx = table.find(activeObjects, hitbox)
- if idx then
- table.remove(activeObjects, idx)
- end
- if grass:FindFirstChild(GrassPhysics.Config.Tween.TweenName) then
- local tween = grass:FindFirstChild(GrassPhysics.Config.Tween.TweenName) :: Tween
- tween:Cancel()
- end
- grass.CFrame = hitbox.CFrame
- end
- local function setupGrassInstance(grass: BasePart): ()
- grass:SetAttribute("Rotation", Vector3.new(math.rad(grass.Orientation.X), math.rad(grass.Orientation.Y), math.rad(grass.Orientation.Z)))
- local grassHitbox: BasePart = nil
- local grassRotation = grass:GetAttribute("Rotation")
- if grass:FindFirstChild("Hitbox") then
- local hitbox = grass:FindFirstChild("Hitbox") :: BasePart
- grassHitbox = hitbox
- else
- grassHitbox = Instance.new("Part", grass)
- end
- grassInfo[grassHitbox] = {
- Top = grass.Position + Vector3.new(0, grass.Size.Y / 2, 0),
- Base = grass.Position - Vector3.new(0, grass.Size.Y / 2, 0),
- Eligible = true,
- Updated = false
- }
- if not grass:FindFirstChild("Hitbox") then
- grassHitbox.Size = grass.Size
- grassHitbox.CanCollide = false
- grassHitbox.Anchored = true
- grassHitbox.Transparency = GrassPhysics.Config.Grass.Transparency
- grassHitbox.Name = "Hitbox"
- grass.CFrame = CFrame.lookAt(grass.Position, grassInfo[grassHitbox].Top, UP_VECTOR) * ROT_CFRAME * CFrame.Angles(grassRotation.X, grassRotation.Y + math.rad(90), grassRotation.Z)
- grassHitbox.CFrame = grass.CFrame
- end
- end
- local function removeGrassInstance(grass: BasePart): ()
- local hitbox = grass:FindFirstChild("Hitbox") :: BasePart
- GrassPhysics:disableGrass(grass)
- if grassInfo[hitbox] then
- grassInfo[hitbox] = nil
- end
- hitbox:Destroy()
- logDebug("Removed grass instance: " .. grass.Name)
- end
- -- Hitbox Functions
- local function setupHitboxInstance(hitbox: BasePart): ()
- if not hitbox:IsDescendantOf(Root) then
- return
- end
- hitboxInfo[hitbox] = { Eligible = true, Updated = false }
- activateEffect(hitbox)
- logDebug("Setup hitbox instance: " .. hitbox.Name)
- end
- local function removeHitboxInstance(hitbox: BasePart): ()
- deactivateEffect(hitbox)
- hitboxInfo[hitbox] = nil
- if hitboxEvents[hitbox] then
- hitboxEvents[hitbox]:Disconnect()
- hitboxEvents[hitbox] = nil
- end
- logDebug("Removed hitbox instance: " .. hitbox.Name)
- end
- -- Character Functions
- local function handleCharacterAddition(character: Model)
- Character = character
- HumanoidRootPart = Character:WaitForChild("HumanoidRootPart") :: BasePart
- Humanoid = Character:WaitForChild("Humanoid") :: Humanoid
- -- Log character and HumanoidRootPart details
- logDebug("Handling character addition: " .. character.Name)
- logDebug("HumanoidRootPart Position: " .. tostring(HumanoidRootPart.Position))
- logDebug("HumanoidRootPart CFrame: " .. tostring(HumanoidRootPart.CFrame))
- -- Check if a hitbox with the same CFrame already exists
- local hitboxExists = false
- logDebug("Checking for existing hitboxes in player: " .. tostring(Character.Name))
- local existingHitbox = Character:FindFirstChild("Hitbox")
- if existingHitbox then
- hitboxExists = true
- logDebug("Hitbox with matching CFrame found: " .. tostring(existingHitbox.Name))
- end
- if not hitboxExists then
- logDebug("No matching hitbox found. Adding new hitbox.")
- local newHitbox = ReplicatedStorage.InteractiveGrass.Hitbox:WaitForChild("Hitbox"):Clone()
- newHitbox.Parent = Character
- -- Create an attachment in the HumanoidRootPart
- local humanoidRootAttachment = Instance.new("Attachment")
- humanoidRootAttachment.Name = "HumanoidRootAttachment"
- humanoidRootAttachment.Parent = HumanoidRootPart
- -- Set the hitbox's CFrame to the HumanoidRootPart's CFrame
- newHitbox.CFrame = HumanoidRootPart.CFrame
- logDebug("New hitbox created at CFrame: " .. tostring(newHitbox.CFrame))
- -- Set up constraints for the hitbox
- local attachment = Instance.new("Attachment", newHitbox)
- local alignPosition = Instance.new("AlignPosition", newHitbox)
- alignPosition.RigidityEnabled = true
- alignPosition.Mode = Enum.PositionAlignmentMode.OneAttachment
- alignPosition.Attachment0 = attachment
- alignPosition.Attachment1 = humanoidRootAttachment
- alignPosition.MaxForce = math.huge
- alignPosition.MaxVelocity = math.huge
- alignPosition.Responsiveness = 50
- alignPosition.Enabled = true
- local alignOrientation = Instance.new("AlignOrientation", newHitbox)
- alignOrientation.RigidityEnabled = true
- alignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
- alignOrientation.Attachment0 = attachment
- alignOrientation.Attachment1 = humanoidRootAttachment
- alignOrientation.MaxTorque = math.huge
- alignOrientation.Responsiveness = 50
- alignOrientation.Enabled = true
- -- Connect the AlignPosition and AlignOrientation to the HumanoidRootPart's attachment
- hitboxEvents[newHitbox] = RunService.Stepped:Connect(function()
- alignPosition.Position = newHitbox.Parent.PrimaryPart.Position
- alignOrientation.CFrame = newHitbox.Parent.PrimaryPart.CFrame
- end)
- CollectionService:AddTag(newHitbox, GrassPhysics.Config.Grass.HitboxTag)
- logDebug("New hitbox added and tagged: " .. newHitbox.Name)
- else
- logDebug("Hitbox with the same CFrame already exists; not adding a new one.")
- end
- Humanoid.Died:Connect(function()
- logDebug("Humanoid died, resetting grass and hitboxes.")
- for _, grass in pairs(activeObjects) do
- local grassPart = grass.Parent :: BasePart
- resetGrass(grassPart)
- logDebug("Reset grass: " .. grassPart.Name)
- end
- activeObjects = {}
- logDebug("Player died, deactivated all grass and hitboxes")
- end)
- end
- local function handleCharacterRemoval(character: Model): ()
- local hitboxPart = character:FindFirstChild("Hitbox")
- if hitboxPart then
- hitboxPart:Destroy()
- end
- logDebug("Character removed: " .. character.Name)
- end
- -- Camera Functions
- local function cameraPositionChanged(hitboxOnly: boolean): ()
- task.desynchronize()
- local controlVec = lastCamCFrame.LookVector
- local threshold = Camera.FieldOfView + GrassPhysics.Config.Camera.FieldOfViewThreshold
- local infoType = if hitboxOnly then hitboxInfo else grassInfo
- for obj: BasePart, data in pairs(infoType) do
- local directionVec = obj.Position - lastCamCFrame.Position
- local angle = math.deg(directionVec.Unit:Angle(controlVec))
- local playerPosVec = Character and HumanoidRootPart and (obj.Position - HumanoidRootPart.Position)
- local distance = playerPosVec and (Vector3.new(playerPosVec.X, 0, playerPosVec.Z)).Magnitude
- if angle <= threshold and distance and distance <= HITBOX_RADIUS then
- if not data.Eligible then
- data.Eligible = true
- data.Updated = false
- end
- else
- if data.Eligible then
- data.Eligible = false
- data.Updated = false
- end
- end
- end
- lastCamCFrame = Camera.CFrame
- if GrassPhysics.Config.Debug.ExtraLogging == true then
- logDebug("Camera position changed. Hitbox only: " .. tostring(hitboxOnly))
- end
- task.synchronize()
- end
- local function updateCameraCFrame(deltaTime: number): ()
- timeTracker += deltaTime
- if timeTracker > INTERVAL * GrassPhysics.Config.Physics.Intervals.CameraUpdateFactor then
- timeTracker = 0
- if (Camera.CFrame.Position - lastCamCFrame.Position).Magnitude > GrassPhysics.Config.Camera.MovementThreshold or Camera.CFrame.Rotation ~= lastCamCFrame.Rotation then
- updateCounter = 0
- task.spawn(cameraPositionChanged, false)
- else
- updateCounter += 1
- if updateCounter > GrassPhysics.Config.Debug.LogFrequency then
- updateCounter = 0
- task.spawn(cameraPositionChanged, true)
- end
- end
- end
- if GrassPhysics.Config.Debug.ExtraLogging == true then
- logDebug("Camera CFrame updated.")
- end
- end
- local function updateActivations(deltaTime: number): ()
- timeTracker += deltaTime
- if timeTracker > INTERVAL * GrassPhysics.Config.Physics.Intervals.ActivationUpdateFactor then
- timeTracker = 0
- for obj, data in grassInfo do
- local objParent = obj.Parent :: BasePart
- if data.Eligible then
- if not data.Updated then
- data.Updated = true
- GrassPhysics:enableGrass(objParent)
- end
- else
- if not data.Updated then
- data.Updated = true
- GrassPhysics:disableGrass(objParent)
- end
- end
- end
- for obj, data in hitboxInfo do
- if data.Eligible then
- if not data.Updated then
- data.Updated = true
- activateEffect(obj)
- end
- else
- if not data.Updated then
- data.Updated = true
- deactivateEffect(obj)
- end
- end
- end
- if GrassPhysics.Config.Debug.ExtraLogging == true then
- logDebug("Activations updated.")
- end
- end
- end
- function GrassPhysics:Init()
- Players.PlayerAdded:Connect(function(player)
- playerEvents[player.Name] = {
- CharacterAdded = player.CharacterAdded:Connect(handleCharacterAddition),
- CharacterRemoving = player.CharacterRemoving:Connect(handleCharacterRemoval)
- }
- if player.Character then
- handleCharacterAddition(player.Character)
- end
- end)
- Players.PlayerRemoving:Connect(function(player)
- local events = playerEvents[player.Name]
- if events then
- events.CharacterAdded:Disconnect()
- events.CharacterRemoving:Disconnect()
- playerEvents[player.Name] = nil
- end
- end)
- CollectionService:GetInstanceAddedSignal(GrassPhysics.Config.Grass.Tag):Connect(setupGrassInstance)
- CollectionService:GetInstanceRemovedSignal(GrassPhysics.Config.Grass.Tag):Connect(removeGrassInstance)
- CollectionService:GetInstanceAddedSignal(GrassPhysics.Config.Grass.HitboxTag):Connect(setupHitboxInstance)
- CollectionService:GetInstanceRemovedSignal(GrassPhysics.Config.Grass.HitboxTag):Connect(removeHitboxInstance)
- RunService:BindToRenderStep("CameraUpdateStep", Enum.RenderPriority.Camera.Value, updateCameraCFrame)
- RunService:BindToRenderStep("ActivationUpdateStep", Enum.RenderPriority.Camera.Value + 2, updateActivations)
- for _, grass in ipairs(CollectionService:GetTagged(GrassPhysics.Config.Grass.Tag)) do
- setupGrassInstance(grass)
- end
- for _, hitbox in ipairs(CollectionService:GetTagged(GrassPhysics.Config.Grass.HitboxTag)) do
- setupHitboxInstance(hitbox)
- end
- for _, player in ipairs(Players:GetPlayers()) do
- playerEvents[player.Name] = {
- CharacterAdded = player.CharacterAdded:Connect(handleCharacterAddition),
- CharacterRemoving = player.CharacterRemoving:Connect(handleCharacterRemoval)
- }
- if player.Character then
- handleCharacterAddition(player.Character)
- end
- end
- local hidegrassEnabled = GrassPhysics.Config.OcclusionCulling.HideGrass.Enabled
- script.Parent.Parent.Culling.GrassCullingHideGrass.Enabled = hidegrassEnabled
- local disablephysicsEnabled = GrassPhysics.Config.OcclusionCulling.DisablePhysics.Enabled
- script.Parent.Parent.Culling.GrassCullingDisablePhysics.Enabled = disablephysicsEnabled
- end
- GrassPhysics:Init()
- return GrassPhysics
Advertisement
Add Comment
Please, Sign In to add comment