Enhancing Projectile?

I’m beginning to work on some projectiles again for my Wand system; Below is a past example - (I am aware that I use a deprecated version of RayCasting, this will be upgraded.)

However, as this was an early project - I have since learned that using a for loop and CFrame contributes greatly to performance issues.

Does anyone have any suggestions on what I can do to enhance my projectiles?

Please note, I wish to avoid using FastCast() as I want to design from the ground up.

Thank you.

local SpellSpeed = math.random(6, 10)
	for Movement = 1, math.huge do 
  		if not SpellPart then break end
 		wait()
  		local SpellRay = Ray.new(SpellPart.Position, SpellPart.CFrame.LookVector * SpellSpeed)
  		local Obj, Position = workspace:FindPartOnRay(SpellRay, IgnoreList) 
		if not Obj then
			SpellPart.CFrame = SpellPart.CFrame + SpellPart.CFrame.LookVector * SpellSpeed
		else
	    	if Obj.Parent:FindFirstChild("Protego") == nil and Obj.Parent.Parent:FindFirstChild("Protego") == nil then
		    	SpellPart:Destroy()
		    	break
	    	else
				IgnoreList = nil
	    		SpellPart.CFrame = CFrame.new(SpellPart.CFrame.p, Player.Character["HumanoidRootPart"].CFrame.p)
	    	end
  		end
	end

Nah, not really.

these two lines could be replaced with:

while SpellPart do

(but you can also remove the loop entirely, keep reading)

wait() sort of sucks. It’s fine, but better is to attach your update to the actual physics updates with the RunService | Documentation - Roblox Creator Hub event:

game:GetService("RunService").Stepped:Connect(function(time, step)
    -- do stuff in here that you want to be called every frame
end)

Now because we don’t have a loop we can’t break, but we can disconnect the event:

local connection
connection = game:GetService("RunService").Stepped:Connect(function(time, step)
    if not SpellPart then
        connection:Disconnect()
        return
    end
    -- etc
    -- also for the other 'break'
end)

(both places you do this) you shouldn’t just multiply by SpellSpeed, because frames (either with the loop and wait(), or with Stepped) aren’t always the same length. Better is to use the step argument of Stepped (or the return value of wait()) to scale your speed by the time of the frame:

local connection
-- BTW 'Stepped' might be called 'PostSimulation' now/in the future but I've never
-- tested that
connection = game:GetService("RunService").Stepped:Connect(function(time, step)
    -- ...
    local StudsToMove = SpellSpeed * step -- use this where you used SpellSpeed before
    -- ...
end)

Just note that your SpellSpeed would be in studs/second units now, so it’ll probably need to be much bigger (~30x) than what you had before.

1 Like

This looks brilliant!

With this being managed via the Server, however, would it not cause performance issues with per-say like 16+ projectiles firing at once or within a 30s interval?

Edit://
Also, after adjusting this to work with: “PostSimulation” it no longer works?

Edit://
Turns out the new API are yet to be enabled.

Nah, computers are pretty fast. Moving parts and casting rays and doing physics are sorta what ROBLOX is made to do.

One performance improvement could be to have a single Stepped event that’s always connected, and it loops through all the spells currently in play and updates them in the one event. That would probably make the task scheduler a little happier.

But I don’t think it’s really necessary, and the cost of making your code more complex prematurely might outweigh the slight speed benefit for you.