So I’m making a projectile ability where I clone an Attachment with a ParticleEmitter from ReplicatedStorage and parent it to a moving Part (a shard). The problem is: the particle emitter doesn’t show immediately. It only starts showing once the shard starts falling.
I’ve tried:
task.wait()task.spawn + task.wait(0)- setting
Enabled = true - emitting more particles
Nothing works. I attached a video showing the issue.
Here’s my code:
local ArcaneFlick = {}
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local CollectionService = game:GetService("CollectionService")
local TweenService = game:GetService("TweenService")
local ABILITY_COOLDOWN = script:GetAttribute("Cooldown") or 5
local CHARACTER_NAME_REQUIRED = "Street Sorcerer"
local MIN_ABILITY_COOLDOWN = 5
local SHARD_SPEED = 120
local MAX_DISTANCE = 30
local BASE_DAMAGE = 10
local STREET_SORCERER = ReplicatedStorage:WaitForChild("Abilties"):WaitForChild("Street Sorcerer")
local ANIM_FOLDER = STREET_SORCERER:WaitForChild("Animations")
local VFX_FOLDER = STREET_SORCERER:WaitForChild("VFX").ArcaneFlick
local SOUND_FOLDER = STREET_SORCERER:WaitForChild("Sounds").ArcaneFlick
local ANIMATION = ANIM_FOLDER:WaitForChild("ArcaneFlick") :: Animation
local SHARD_VFX_ATTACHMENT_TEMPLATE = VFX_FOLDER:WaitForChild("Shard") :: Attachment
local IMPLOSION_VFX_ATTACHMENT_NAME = VFX_FOLDER:WaitForChild("Implosion") :: Attachment
local SHOOT_SOUND = SOUND_FOLDER:WaitForChild("Shoot") :: Sound
local lastAbilityTime = {}
local function toggleParticleEmitters(attachment: Attachment, emitCount: number?)
for _, child in ipairs(attachment:GetDescendants()) do
if child:IsA("ParticleEmitter") then
child:Emit(emitCount or 50)
end
end
end
function ArcaneFlick.Trigger(player: Player, targetPos: Vector3)
local character = player.Character
if not character or not character:FindFirstChild("HumanoidRootPart") then return end
local humanoid = character:FindFirstChildOfClass("Humanoid")
local hrp = character.HumanoidRootPart
local animator = humanoid and humanoid:FindFirstChildOfClass("Animator")
local rHand = character:FindFirstChild("RightHand") or character:FindFirstChild("Right Arm")
if not animator or not rHand then return end
if character:GetAttribute("Character") ~= CHARACTER_NAME_REQUIRED then return end
-- Cooldown
local cooldownReduction = player:GetAttribute("CooldownReduction") or 0
local effectiveCooldown = math.max(MIN_ABILITY_COOLDOWN, ABILITY_COOLDOWN * (1 - cooldownReduction))
if lastAbilityTime[player.UserId] and (tick() - lastAbilityTime[player.UserId] < effectiveCooldown) then return end
lastAbilityTime[player.UserId] = tick()
-- Animation
local animTrack = animator:LoadAnimation(ANIMATION)
animTrack:Play()
animTrack:GetMarkerReachedSignal("Shoot"):Wait()
-- Shoot sound
if SHOOT_SOUND then
local s = SHOOT_SOUND:Clone()
s.Parent = rHand
s:Play()
Debris:AddItem(s, 2)
end
-- Implosion VFX
local explodeVFX = IMPLOSION_VFX_ATTACHMENT_NAME:Clone()
explodeVFX.Parent = rHand
toggleParticleEmitters(explodeVFX, true, 20)
Debris:AddItem(explodeVFX, 1)
-- Create shard and physics
local shardPart = Instance.new("Part")
shardPart.Name = "ArcaneShard"
shardPart.Size = Vector3.new(1,1,1)
shardPart.Transparency = 0.6
shardPart.Anchored = false
shardPart.Massless = true
shardPart.CanCollide = true
shardPart.CFrame = CFrame.lookAt(rHand.Position, targetPos)
shardPart.Parent = workspace
shardPart.CustomPhysicalProperties = PhysicalProperties.new(0.01,0,1,0,0)
local spawnPos = rHand.CFrame * CFrame.new(0,0,-1)
shardPart.CFrame = CFrame.lookAt(spawnPos.Position, targetPos)
-- Apply velocity
local bv = Instance.new("BodyVelocity")
bv.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
bv.Velocity = (targetPos - spawnPos.Position).Unit * SHARD_SPEED
bv.Parent = shardPart
Debris:AddItem(bv, 2)
-- Clone and parent VFX
local vfxAttachment = SHARD_VFX_ATTACHMENT_TEMPLATE:Clone()
vfxAttachment.Parent = shardPart
local emitter = vfxAttachment:FindFirstChildOfClass("ParticleEmitter")
if emitter then
emitter.Enabled = true
task.spawn(function()
task.wait(0)
emitter:Emit(30)
end)
end
local function stopVFX()
if emitter then
emitter.Enabled = false
end
end
local hasHit = false
local startPos = shardPart.Position
-- Touch detection
local connection
connection = shardPart.Touched:Connect(function(hit)
if hasHit or hit:IsDescendantOf(character) then return end
hasHit = true
-- Damage logic (placeholder)
if hit.Name == "VFXHitbox" or hit:FindFirstChild("VFXHitbox") or CollectionService:HasTag(hit, "Event") then
local eventPart = if CollectionService:HasTag(hit, "Event") then hit else (if hit.Name == "VFXHitbox" then hit.Parent else hit:FindFirstChild("VFXHitbox").Parent)
if eventPart and eventPart:IsA("BasePart") then
local powerMult = player:GetAttribute("PowerDamageMultiplier") or 1
print("Damage Taken")
end
end
stopVFX()
-- Cleanup
connection:Disconnect()
Debris:AddItem(shardPart, 25)
end)
-- Distance check
task.spawn(function()
while shardPart and shardPart.Parent and not hasHit do
local dist = (shardPart.Position - startPos).Magnitude
if dist >= MAX_DISTANCE then
hasHit = true
stopVFX()
Debris:AddItem(shardPart, 25)
if connection then connection:Disconnect() end
break
end
task.wait(0.05)
end
end)
end
return ArcaneFlick