Orientation resets to 0,0,0

So I wanted to have a moving fish in my game and the script worked fine except that it resets the orientation and the fish ends up going backwards. Is there a way to fix that? Oh and, how could I make it so it rotates when it moves to the sides?

while true do

wait()

for i = 1,1000 do

script.Parent.CFrame = CFrame.new(script.Parent.Position + Vector3.new(.2,0,0))

wait()

end

for i = 1,10 do

script.Parent.CFrame = CFrame.new(script.Parent.Position + Vector3.new(0,3,0))

wait()

end

for i = 1,1000 do

script.Parent.CFrame = CFrame.new(script.Parent.Position - Vector3.new(.2,0,0))

wait()

end

for i = 1,10 do

script.Parent.CFrame = CFrame.new(script.Parent.Position - Vector3.new(0,3,0))

wait()

end

end

image

Because the new CFrame’s orientation is 0,0,0.
In your case, you should completely avoid it in movements and slide it by a vector:

script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0.2,0,0)

You can also use a local offset by using CFrame.new instead of Vector3.new:

script.Parent.CFrame = script.Parent.CFrame * CFrame.new(0.2,0,0)

To make them rotate, you will have to use CFrame.Angles:

script.Parent.CFrame = script.Parent.CFrame * CFrame.new(0.2,0,0) * CFrame.Angles(0,math.rad(5),0)

As a note, it is always a bad idea to use loops with wait() as the intervals can be very irregular and cause the fish to stutter. Use RunService instead.

local iterations,maxiterations = 0,1000
local connection; connection = game:GetService("RunService").Heartbeat:Connect(function(timedelta)
    script.Parent.CFrame = script.Parent.CFrame * CFrame.new(0.2*timedelta,0,0) * CFrame.Angles(0,math.rad(5*timedelta),0)
    iterations = interations+1
    if iterations==maxiterations then
        iterations = 0
        connection:Disconnect()
    end
end

EDIT: Use script.Parent.CFrame = script.Parent.CFrame * CFrame.Angles(0,math.rad(5),0) * CFrame.new(0,0,0.2) for the offset rotation instead as it will first rotate the fish and then move it forward in the direction it is facing.

4 Likes

It works like a charm, many thanks.
Didn’t get the last part about RunService though but for now it’s working relatively well.

These are the changes I made, do you think it’ll cause any issues with like lag?

while true do
 wait()
 for i = 1,1000 do
 script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0.2,0,0)
 wait()
 end

 for i = 1,10 do
 script.Parent.CFrame = script.Parent.CFrame - Vector3.new(0,0,6)
 wait()
 script.Parent.CFrame = script.Parent.CFrame * CFrame.Angles(0,math.rad(18),0) * CFrame.new(0,0,0.2)
 wait()
 end

 for i = 1,1000 do
 script.Parent.CFrame = script.Parent.CFrame - Vector3.new(0.2,0,0)
 wait()
 end

 for i = 1,10 do
 script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0,0,6)
 wait()
 script.Parent.CFrame = script.Parent.CFrame * CFrame.Angles(0,math.rad(18),0) * CFrame.new(0,0,0.2)
 wait()
 end
end
1 Like

Lua runs in threads which are basically parts of your code that wait for their turn not to cause any issues. wait() is a Roblox specific global function that tries to pause the current thread for a set amount of time (0.04 seconds minimum). That “tries” part is the most important, as it will never fire under the given amount of delay, but can complete even 5 seconds or more in case of extreme CPU usage.

RunService is meant to overcome this issue, offering 2 events that fire depending on your frame rate. Heartbeat fires before physics are computed, while RenderStepped just before the frame is rendered. They fire the connected function each frame with 1 parsed argument which is the amount of time in seconds since the last frame. You can use this argument to compensate for lag by multiplying your values with it, which is exactly what I have done.

In short, wait() should always be avoided.

2 Likes