 Help with Particle Spiral Velocity

I need some help with making a particle spiral around a frozen entity. I feel like I am going about this the wrong way, this is the relevant piece of code. It “somewhat” works but it isn’t a clean spiral.

Not very familiar with velocity in a 3d space.

pos = initial entity pos (for all intents and purposes just assume (0,0,0))

[lua]
timer.Create(“ParticleVelocity”, .01, 80, function()
yaw = yaw + 8
if ( yaw > 360 ) then yaw = 0; end

local yaw = yaw
if ( yaw &gt; 360 ) then yaw = yaw - 360; end
x = radius * math.cos((yaw * math.pi) / 180) -- Just gets a point on a circle (radius 20)
y = radius * math.sin((yaw * math.pi) / 180)

local ppos = particle:GetPos()

endPos = Vector(pos.x, pos.y, ppos.z) + Vector(x,y,4) --End pos is the original pos + the pos on the circle and a little bit higher.

dx = endPos.x - ppos.x
dy = endPos.y - ppos.y
dz = endPos.z - ppos.z

d = math.sqrt(dx*dx + dy*dy + dz*dz)

vx = dx/d * 24
vy = dy/d * 24
vz = dz/d * 24

particle:SetVelocity( Vector(vx,vy,vz) );

end)
[/lua]

Note that I am assuming that you want the particle to orbit around the entity, correct me if I am wrong

I would suggest using an effect for this and simply draw a sprite.
Effects are located in the lua/effects/ directory, or entities/effects/ for gamemodes.

In my example (orbit.lua), I start by marking the effect for download and create a varible that points to the material the effect will use for the sprite:

EFFECT.matsprite = Material("effects/select_ring")

The functions we are interested in for this effect is Init, Think and Render.

Let us start with Init, it gets called when the effect is created.
The first and only argument is an CEffectData object, which contains data for the effect; example on that at the end.

function EFFECT:Init(data)
local ent = data:GetEntity() -- get target entity
if not IsValid(ent) then
return -- if the entity is not valid, no need to continue
end

self:SetPos(ent:GetPos()) -- set the position of the effect at the entitys position
-- NOTE: since your entity will be frozen we only set the position once here, if you plan
--     to move the entity; set the position in the Think function

-- get the render bounds of the entity
local min, max = ent:GetRenderBounds()
-- set the render bounds of the effect to be bigger than the entitys, because the sprite
--     will most likely orbit outside the entitys render bounds; 50% larger will do(?)
self:SetRenderBounds(min*1.5, max*1.5)

self.entity = ent -- store the entity
end

Think, this function is used for the logic of the effect; returning anything but true removes the effect.

function EFFECT:Think()
local ent = self.entity -- use the entity specified in Init
if not IsValid(ent) then
return false -- if the entity is not valid, remove the effect
end

-- calculating the position of the sprite
local rad = RealTime() -- let us be lazy and just use the time as the radians :^)
self.spritepos = ent:GetPos() +

return true --keep the effect alive
end

Render, the function that renders the effect; self-explanatory:

function EFFECT:Render()
if self.spritepos then
render.SetMaterial(self.matsprite)
render.DrawSprite(self.spritepos, 16, 16, color_white)
end
end

And that’s it!
Here is the full code:

EFFECT.matsprite = Material("effects/select_ring")

function EFFECT:Init(data)
local ent = data:GetEntity() -- get target entity
if not IsValid(ent) then
return -- if the entity is not valid, no need to continue
end

self:SetPos(ent:GetPos()) -- set the position of the effect at the entitys position
-- NOTE: since your entity will be frozen we only set the position once here, if you plan
--     to move the entity; set the position in the Think function

-- get the render bounds of the entity
local min, max = ent:GetRenderBounds()
-- set the render bounds of the effect to be bigger than the entitys, because the sprite
--     will most likely orbit outside the entitys render bounds; 50% larger will do(?)
self:SetRenderBounds(min*1.5, max*1.5)

self.entity = ent -- store the entity
end

function EFFECT:Think()
local ent = self.entity -- use the entity specified in Init
if not IsValid(ent) then
return false -- if the entity is not valid, remove the effect
end

-- calculating the position of the sprite
local rad = RealTime() -- let us be lazy and just use the time as the radians :^)
self.spritepos = ent:GetPos() +

return true --keep the effect alive
end

function EFFECT:Render()
if self.spritepos then
render.SetMaterial(self.matsprite)
render.DrawSprite(self.spritepos, 16, 16, color_white)
end
end

To apply the effect, use util.Effect
I suggest applying the effect CLIENTSIDE, because some clients might not have discovered the entity you are targeting, which will remove the effect for them.

Applying the effect on an entity you are looking at:

lua_run_cl local data = EffectData() data:SetEntity(Entity(1):GetEyeTrace().Entity) data:SetRadius(24) util.Effect("orbit", data)

Applying the effect when the entity is initialized:

function ENT:Initialize()
if CLIENT then
local data = EffectData()
data:SetEntity(self)