The stuff that you saw is normal however what you could do is using humanoid:GetState() == Enum.HumanoidStateType.Running
in the condition if you want
I’ve done that before! Though for some reason it didn’t work. Quite the contrary in fact, it made it really laggy. Though, considering the scripts are heavily updated, I could try again. (which I am right now)
Oh wow! It actually worked! That’s awesome!!!
By the way are you still using RenderStepped
?
No, I’m not. I’ve removed it. (30char)
Ok goodluck with your game (It looks cool)
In that case, everything is fixed!
Thanks @faze_paspro and @ValtryekRBLX for the help! I owe you guys!
(I wish I could give solutions to both but I can’t because… DevForum.)
Okay… so never mind. There are still a few issues going on.
When you run and jump, sometimes the particles still proceed. When that happens and the person lands, the particles disappear although they’re still running until they change direction or pause for a few seconds and start walking again. What do I do??
Sorry for speaking too soon
It’s a very inconsistent bug…
Here are the updated scripts:
VFXController
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local VFXEvent = ReplicatedStorage.BindableEvents.VFX
local TweenService = game:GetService("TweenService")
local Player = game.Players.LocalPlayer
local Effects = ReplicatedStorage.VFX.Effects
local Actions = ReplicatedStorage.VFX.Actions
local UserRunning = false
-- Functions
local function Stomp()
local VFXFolder = Actions.Stomp
local InitialSize = Vector3.new(0.15, 1, 2.309)
for _, child in pairs(VFXFolder:GetChildren()) do
if child:isA("Model") and child.Name == "Triangles" then
local Effect = Effects.Spark:Clone()
Effect.Parent = Player.Character:WaitForChild("Torso")
local ModelClone = child:Clone()
ModelClone.Parent = workspace
ModelClone:MoveTo(Vector3.new(Player.Character:WaitForChild("Torso").Position.X, Player.Character:WaitForChild("Torso").Position.Y - 7, Player.Character:WaitForChild("Torso").Position.Z))
for _, child2 in pairs(ModelClone:GetChildren()) do
child2.Size = InitialSize
local RandomSize = math.random(4, 8)
local Tween1 = TweenService:Create(child2, TweenInfo.new(0.2, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut), {Size = Vector3.new(child2.Size.X, RandomSize, child2.Size.Z)})
Tween1:Play()
Effect.Enabled = true
end
task.wait(0.2)
for _, child2 in pairs(ModelClone:GetChildren()) do
local Tween2 = TweenService:Create(child2, TweenInfo.new(0.1, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut), {Size = Vector3.new(InitialSize)})
Tween2:Play()
Effect:Destroy()
end
task.wait(0.1)
ModelClone:Destroy()
end
end
end
local funcRunning = false
local function Run()
local VFXFolder = Actions.Run
if funcRunning then return end
funcRunning = true
for _, child in pairs(VFXFolder:GetChildren()) do
repeat
local Leg = math.random(0,1)
local clone = child:Clone()
if Leg == 0 then
clone.Parent = game.Players.LocalPlayer.Character:WaitForChild("Left Leg")
clone.Position = game.Players.LocalPlayer.Character:WaitForChild("Left Leg").Position
else
clone.Parent = game.Players.LocalPlayer.Character:WaitForChild("Right Leg")
clone.Position = game.Players.LocalPlayer.Character:WaitForChild("Right Leg").Position
end
local Tween = TweenService:Create(clone, TweenInfo.new(0.4, Enum.EasingStyle.Quint), {Transparency = 1, Orientation = Vector3.new(math.random(0, 360),math.random(0, 360),math.random(0, 360))})
Tween:Play()
Tween.Completed:Connect(function()
clone:Destroy()
end)
task.wait(0.1)
until UserRunning == false
end
funcRunning = false
end
local function Idle(Condition)
print("is Idle")
end
-- On Fired
VFXEvent.Event:Connect(function(Action, isRunning)
UserRunning = isRunning
if Action == "Stomp" then
Stomp()
end
if Action == "Run" then
Run()
end
if Action == "Idle" then
Idle()
end
end)
OnAction
local char = script.Parent
local root = char:WaitForChild("HumanoidRootPart")
local humanoid = char:WaitForChild("Humanoid")
local fallDistance
local Event = game:GetService("ReplicatedStorage").BindableEvents.VFX
if humanoid and root then
local headHeight
humanoid.FreeFalling:Connect(function(state)
if state then
headHeight = root.Position.Y
elseif not state and headHeight ~= nil then
fallDistance = headHeight - root.Position.Y
--print("Fall distance: " .. fallDistance)
end
end)
end
--if humanoid.FloorMaterial == nil then
-- return
--end
humanoid.StateChanged:Connect(function(old, new)
if old == Enum.HumanoidStateType.Freefall and new == Enum.HumanoidStateType.Landed and fallDistance >= 22 then
local animation = script.Parent:WaitForChild("Animate").land.landAnim
local dance = humanoid:LoadAnimation(animation)
dance:Play()
Event:Fire("Stomp")
task.wait(0.2)
end
end)
local isIdle = false
humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
if humanoid.MoveDirection.Magnitude > 0 and humanoid:GetState() == Enum.HumanoidStateType.Running then
print("Person is running")
Event:Fire("Run", true)
else
print("Person stopped or in air")
Event:Fire("Idle", false)
end
end)
It might be because there are many VFX particles being released over a course of time, and they are attached to the player. This means that even though the player is running (and hence the VFX is played), the VFX continues to player when the player stops “running” (i.e. when they jump and stop fulfilling the conditions). What you need to do is disable the VFX when they aren’t running.
AFK, will be back soon.
I’ll try to do that! Though I need to figure out how to do that because the script doesn’t only include the walking vfx…
Hey, sorry about the delay. Your code is a little bit messy but inside the Run
function, try adding a secondary check that detects when the player is touching the ground using the FloorMaterial
property vel sim.
Wait, if my code is messy, shouldn’t I work on that?
I don’t want to base work on messy things, you know? So, if you have any idea kn how i can optimize my workspace efficiently, please don’t hesitate to tell me! I’m willing to improve it!
The second script looks completely fine. The first one could be repurposed instead as a ModuleScript
, as you’ve essentially turned a local script into a module script .This will allow you to
- add and customise the VFX as you wish
- avoids the use of bindableevents
- organises and neatly arranges the functions as needed.
It’s not “messy” per se, but could use some arranging. For example, in the ModuleScript, you’d probably have the same functions but this time you have a clearer method to run and cancel VFXs outside of the module script.
Another way to organise your code a bit more is to use comments (the --
) and a bit more spacing. Use comments to explain the purpose of code, not what the code does. Good comments do not excuse unclear code, though. This is just for readability but it can help when you’re working on longer scripts.
Your nomenclature (how you name variables) also could use a bit of work - instead of naming things as Tween1
or Effect1
, try being a bit more specific, like showTween
or hideTween
.
To sum up for these general things, here is what your architecture should look like
- A module script that creates specified VFX (i.e. the Stomp VFX, the Run VFX, etc)
- Remember, an internal check here could also be useful.
- A local script that plays the VFX when needed by requiring the module scrip.t
Hope this helps! Let me know if you need help or clarification.
Hey! Sorry for the late response, it was late so I went to bed.
I have followed your advice as much as I could, and this is what I ended up with:
local VFX = {}
-- Variables
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Player = game.Players.LocalPlayer
local Effects = ReplicatedStorage.VFX.Effects
local Actions = ReplicatedStorage.VFX.Actions
local UserRunning = false
-- Functions
-- When the user stomps it activates the VFX related to it
local function Stomp()
local VFXFolder = Actions.Stomp
local InitialSize = Vector3.new(0.15, 1, 2.309)
for _, VFXContent in pairs(VFXFolder:GetChildren()) do
if VFXContent:isA("Model") and VFXContent.Name == "Triangles" then
local SparkEffect = Effects.Spark:Clone()
SparkEffect.Parent = Player.Character:WaitForChild("Torso")
local ModelClone = VFXContent:Clone()
ModelClone.Parent = workspace
ModelClone:MoveTo(Vector3.new(Player.Character:WaitForChild("Torso").Position.X, Player.Character:WaitForChild("Torso").Position.Y - 7, Player.Character:WaitForChild("Torso").Position.Z))
for _, VFXDescendant in pairs(ModelClone:GetChildren()) do
VFXDescendant.Size = InitialSize
local RandomSize = math.random(4, 8)
local ShowTween = TweenService:Create(VFXDescendant, TweenInfo.new(0.2, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut), {Size = Vector3.new(VFXDescendant.Size.X, RandomSize, VFXDescendant.Size.Z)})
ShowTween:Play()
SparkEffect.Enabled = true
end
task.wait(0.2)
for _, VFXDescendants in pairs(ModelClone:GetChildren()) do
local HideTween = TweenService:Create(VFXDescendants, TweenInfo.new(0.1, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut), {Size = Vector3.new(InitialSize)})
HideTween:Play()
SparkEffect:Destroy()
end
task.wait(0.1)
ModelClone:Destroy()
end
end
end
local funcRunning = false
-- When user runs it activates the VFX related to it
local function Run()
local VFXFolder = Actions.Run
if funcRunning then return end
funcRunning = true
for _, VFXContent in pairs(VFXFolder:GetChildren()) do
repeat
local Leg = math.random(0,1)
local VFXDescendant = VFXContent:Clone()
if Leg == 0 then
VFXDescendant.Parent = game.Players.LocalPlayer.Character:WaitForChild("Left Leg")
VFXDescendant.Position = game.Players.LocalPlayer.Character:WaitForChild("Left Leg").Position
else
VFXDescendant.Parent = game.Players.LocalPlayer.Character:WaitForChild("Right Leg")
VFXDescendant.Position = game.Players.LocalPlayer.Character:WaitForChild("Right Leg").Position
end
local RunningTween = TweenService:Create(VFXDescendant, TweenInfo.new(0.4, Enum.EasingStyle.Quint), {Transparency = 1, Orientation = Vector3.new(math.random(0, 360),math.random(0, 360),math.random(0, 360))})
RunningTween:Play()
RunningTween.Completed:Connect(function()
VFXDescendant:Destroy()
end)
task.wait(0.1)
until UserRunning == false
end
funcRunning = false
end
local function Idle(Condition)
return
end
-- On Fired
function VFX.Action(Action, isRunning)
UserRunning = isRunning
if Action == "Stomp" then
Stomp()
end
if Action == "Run" then
Run()
end
if Action == "Idle" then
Idle()
end
end
return VFX
I have turned it into a module and renamed certain variables to be more specific and understood. I have also added a few comments here and there, though I didn’t add too much. What do you think? Should I change something else? Thanks for the help, by the way, I appreciate it!
If everything is clear, what should I do to fix the issue I have mentioned before? I’ve tried to tinker with it a bit but nothing work so I have reverted everything.
I think I found what’s wrong. Your Run()
function continuously creates VFX particles until the user stops running. But, we call the run function whenever the use is already running. This creates a doubled-up loop, which can cause a lot of lag. You need to change the Run
function to only produce 1 VFX segment, and not continuously produce it.
It also wouldn’t hurt to add a secondary check inside the Run
function.
Your ModuleScript looks great ! I would change it slightly so that the Run
, Idle
and Stomp
functions are new standalone functions (i.e. VFX.Run()
, VFX.Idle()
, etc), and remove the VFX.Action
, and replace it inside the respective local scripts, though your current one works completely fine and there isn’t really a problem with it. Your nomenclature and comments look great! Well done.
Awesome! I’m glad I’ve improved! Thanks for the well done. I could change them to their respective functions, though the reason why I won’t is that I will make different types of VFX that are not actions, but they are miscellaneous so I was planning to do a VFX.Misc
alongside! What do you think??
As for this, I’m not sure what to do about it. My original plan was that when the person is running, it fires the Run()
function once and ends when the person stops. How do you think I can manipulate it in a way to make the VFX segment fire once? Is there another condition that I should add, such as detecting if any particles are existing already?
You basically just need to remove the repeat until
and have the part inside that loop on its own.
local function Run()
local VFXFolder = Actions.Run
if funcRunning then return end
funcRunning = true
for _, VFXContent in VFXFolder:GetChildren() do
local Leg = math.random(0,1)
local VFXDescendant = VFXContent:Clone()
if Leg == 0 then
VFXDescendant.Parent = game.Players.LocalPlayer.Character:WaitForChild("Left Leg")
VFXDescendant.Position = game.Players.LocalPlayer.Character:WaitForChild("Left Leg").Position
else
VFXDescendant.Parent = game.Players.LocalPlayer.Character:WaitForChild("Right Leg")
VFXDescendant.Position = game.Players.LocalPlayer.Character:WaitForChild("Right Leg").Position
end
local RunningTween = TweenService:Create(VFXDescendant, TweenInfo.new(0.4, Enum.EasingStyle.Quint), {Transparency = 1, Orientation = Vector3.new(math.random(0, 360),math.random(0, 360),math.random(0, 360))})
RunningTween:Play()
RunningTween.Completed:Connect(function()
VFXDescendant:Destroy()
end)
task.wait(0.1)
end
funcRunning = false
end
This’ll need a bit of tweaking but theoretically it should work.
It works better! Though if I play for a bit and run around, sometimes it breaks and does this:
The VFX doesn’t work while the person is running because for some reason the function doesn’t fire…
I have a feeling the reason why is because of Humanoid:GetState()
flickering. Can you try printing the humanoid state after Person stopped or in air
?
P.S., your game looks really clean and I love the lighting and animation style! Can’t wait for release if you plan on doing so.
For sure! I’ll try that.
Thank you! I really appreciate it! I’m really excited as well though development is slow since I’m the only one working on it at the moment.