I am programming a turret that spins around its Y-axis. Once the turret sees a player in front, it will run a sub-routine in which the turret points itself at the player every frame for as long as the player is within line-of-sight. The turret exists out of a static base (blue in the image below) and a MeshPart (in red) that spins around.
The hierarchy of the turret is as follows:
Spinning the turret in its default state is done by increasing a rotation
variable every frame, then rotating the attachment in the blue base, and then CFraming the red MeshPart such that its relative offset from the attachment remains consistent:
-- rotate the turret around
local dt = game:GetService("RunService").Heartbeat:Wait()
rotation = rotation + dt * ROTATION_SPEED
TurretAtt.Orientation = Vector3.new(0, math.deg(rotation), 0) -- rotate the attachment
MeshPart.CFrame = TurretAtt.WorldCFrame * turretOffset -- CFrame the red MeshPart accordingly
One oversight with this approach is that when a player is detected, the sub-routine is called which also rotates the turret around (to follow the player). When the sub-routine is finished and the code above is called again, the rotation
value will cause the code to rotate the turret back to the orientation it was at when a player was first detected. This causes a sudden change in the CFrame of the turret which looks unnatural.
Instead, what should happen is that after the sub-routine finishes running, the rotation
variable is set to some value corresponding to the current CFrame of the MeshPart at that moment. I was thinking that this could be done by reading the look-vector of the MeshPartās CFrame. However, I am having trouble figuring out how I can use this vector to calculate what value I should assign to the rotation
variable.