How can I improve on this AI firing script code?

while true do
	if firing then
		muzzleFlash:Emit(1)
		unit:damage(nearestZombie,unitStats.Damage.Value)
		muzzleSound.TimePosition = 0
		muzzleSound.Playing = true
		wait(1/unitStats.FireRate.Value)
	end
	wait(0.01)
end

The way the code works is it is inside the main unit behavior script. The RunService.Heartbeat event is connected to the main function which handles most stuff, but it also figures out if the unit should be firing.

I could not find a way to make the script “skip” some heartbeat events in order to maintain a set firerate. So my idea was to have an external firing value and update it. Then the other loop (the one I posted) checks to see if it is firing. All of the stuff inside the ‘if firing’ statement aside from the wait() is fine.

The system works fine but I am wondering if there is any better/smoother way of achieving this behavior? To me the whole loop just screams bad coding because while true do loops are a pretty beginner level tactic.

You can try to use “Aling Orientation” as a physic value, instead of a script doing the rotation to the zombie position, add it to the HumanoidRootPart and experiment with it.

You can search about it here:
https://developer.roblox.com/en-us/api-reference/class/AlignOrientation

Good job so far, keep the good work!

Thank you, I will actually look into this, as I used to have a script do the movement too until that caused issues with clipping and I wasn’t about to write a collisions solver. So i moved that to AlignPosition, moving orientation to physics based as well might be good.

Edit: I was doing some reading on the forums and I found a post talking about optimization, CFrames are very expensive to set so moving to AlignOrientation would remove a lot of lag (each unit sets its CFrame 1-3 times per frame at max)

1 Like

Yeah, some physics saves a lot of lag and make some scripts functions smoother. It’s a really good choice to see at the game physics limits, so you can use them instead of script functions and improve new ideas about future projects.

You could go on a different approach with the syntax using a continue operator.

while true do
	if not firing then
		task.wait()
		continue
	end
	
	muzzleFlash:Emit(1)
	unit:damage(nearestZombie,unitStats.Damage.Value)
	muzzleSound.TimePosition = 0
	muzzleSound.Playing = true
	task.wait(1/unitStats.FireRate.Value)
end

I’d rather not use polling as that is a practice which is looked down upon, but I have recently found that .Heartbeat passes along the time delta, which I can use to make accurate fire rates. If anyone else has a better solution though I am up for that.