Breaking a loop when function fired

button.MouseEnter:Connect(function()
		spawn(function()
			
			while true do
				for i = 1, 360 do
					camera.CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(i), 0)*offset
					wait()
				end
				button.MouseLeave:Connect(function()
					camera.CFrame = clone.PrimaryPart.CFrame*offset
					break
				end)
			end
		end)
	end)

Obviously this won’t work. But how can I make it work? The idea is when the mouse enters a button it starts rotating, once it leaves it would stop rotating

2 Likes

This is unrelated, but can’t you just use TweenService to move the camera? It would be so much easier.

Edit:

local TweenService = game:GetService("TweenService")
local TweenSettings = TweenInfo.new(10,Enum.EasingStyle.Linear,Enum.EasingDirection.InOut,math.huge,false,0)

local CameraTween = TweenService:Create(Camera,TweenSettings,{CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(360), 0)*offset})

button.MouseEnter:Connect(function()
    CameraTween:Play()
end

button.MouseLeave:Connect(function()
    CameraTween:Stop()
end

As for what the OP is asking, I think the while statements should be setup like this

button.MouseEnter:Connect()
    local IsMouseEntered = true
    while IsMouseEntered do
        --code to move camera
        button.MouseLeave:Connect(function()
            IsMouseEntered = false
        end)
    end
end
2 Likes

You could use a boolean which will be set to false when the MouseLeave event is fired.

button.MouseEnter:Connect(function()
	local mouseEntered = true
	
	spawn(function()
		while mouseEntered do
			for i = 1, 360 do
				if (not mouseEntered) then
					break
				end
				camera.CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(i), 0)*offset
				wait()
			end
		end
		camera.CFrame = clone.PrimaryPart.CFrame*offset
	end)
	
	local connection
	connection = button.MouseLeave:Connect(function()
		mouseEntered = false
		connection:Disconnect()
	end)
end)
7 Likes

I’m fairly certain this should do the trick. Let me know if there are any issues:

local RunService = game:GetService("RunService")
local rotation = 0

button.MouseEnter:Connect(function()
	RunService:BindToRenderStep("CameraRotation", Enum.RenderPriority.Camera.Value + 1, function()
		rotation = (rotation + 1 < 360 and rotation + 1 or 0) 
		camera.CFrame = clone.PrimaryPart.CFrame * CFrame.Angles(0, math.rad(rotation), 0) * offset
	end)
end)

button.MouseLeave:Connect(function()
	RunService:UnbindFromRenderStep("CameraRotation")
	camera.CFrame = clone.PrimaryPart.CFrame * offset
--	Uncomment the next line if you want rotation to reset each time mouse enters button:
--	rotation = 0
end)
4 Likes

In my opinion the best way to do it is with a boolean variable.

local deb = false

button.MouseEnter:connect(function()
     deb = true
   spawn(function()

   while deb do
      for i = 1, 360 do 
         if deb then
            camera.CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(i), 0)*offset
            wait()
         else
            break
         end
      end
   end
end)

button.MouseLeave:connect(function()
   deb = false
end)

I think that the code above will work, if not, something close to it will do the work.

2 Likes

The easiest way to do this is to use a return. Returning while in a function will stop execution of a function (can also be used for returning values, but not relevant)

button.MouseEnter:Connect(function()
		spawn(function()
			--Also, why are you using spawn? You do not have to, as connect wraps into it's own thread
			while true do
				for i = 1, 360 do
					camera.CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(i), 0)*offset
					wait()
				end
				button.MouseLeave:Connect(function()
					camera.CFrame = clone.PrimaryPart.CFrame*offset
					return --Stop function
				end)
			end
		end)
	end)

You could also use a variable, but that requires more lines of code.

1 Like

I disagree… I think Rocky28447’s code is the right way to do this (if he wants better overall code, not simply just answering his question)

3 Likes

Rocky’s is also pretty good, but everything is just easier using TweenService.

1 Like

The reason I went with BindToRenderStep over TweenService in this case is because with BindToRenderStep, you’re able to unbind from any other script on the client, which you may end up wanting (or needing) to do.

3 Likes

It depends on your use case. Using RenderStep to alter the camera is generally the way to go.

1 Like

I’ve since changed how the offset works, but now I’m not sure how I’d get the models to rotate like so

clone:SetPrimaryPartCFrame(CFrame.new(Vector3.new(-0.5, -0.4, -0.5).unit*(GetCameraOffset(camera.FieldOfView, clone:GetExtentsSize())*0.85)))
camera.CFrame = CFrame.new(Vector3.new(), Vector3.new(-0.5, -0.4, -0.5))
		
rotation = 0
		
button.MouseEnter:Connect(function()
	runService:BindToRenderStep('CameraRotation', Enum.RenderPriority.Camera.Value + 1, function()
		rotation = (rotation + 1 < 360 and rotation + 1 or 0) 
		camera.CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(rotation), 0)*offset
	end)
end)
	
button.MouseLeave:Connect(function()
	runService:UnbindFromRenderStep('CameraRotation')
	camera.CFrame = clone.PrimaryPart.CFrame*offset
end)

So offset doesn’t have a value here, so how would I go about this?

Also keep getting this in the output, which thus causes the rotating to stop

RunService:UnbindFromRenderStep removed different functions with same reference name CameraRotation 2 times. (x4)

Tried this

camera.CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(rotation), 0)*CFrame.new(Vector3.new(), Vector3.new(-0.5, -0.4, -0.5))

but that didn’t seem to do anything whatsoever to it

Chances are that both events, button.MouseEnter and button.MouseLeave, could be firing multiple times at the same time, causing the bind and unbind functions to be called multiple times as well.

This is most likely because you entering and leaving a button at the same time, such as between buttons in your GUI. This could even happen if you place the buttons some pixels apart, since your cursor can travel multiple pixels every frame.

The simplest way to solve this is to unbind whatever function is binded to ‘CameraRotation’ at the time the event button.MouseEnter is being fired before binding a different function to it. I am pretty sure there is no harm from unbinding a function multiple times as a sanity check.

A different solution to this would simply be to make sure to bind and unbind a function once using a boolean to check whether the function has been binded or not.

Using this, plus your use of a base instead of an offset:

clone:SetPrimaryPartCFrame(CFrame.new(Vector3.new(-0.5, -0.4, -0.5).unit*(GetCameraOffset(camera.FieldOfView, clone:GetExtentsSize())*0.85)))
initAngle = CFrame.new(Vector3.new(), Vector3.new(-0.5,-0.4,-0.5))
camera.CFrame = initAngle
		
rotation = 0
		
button.MouseEnter:Connect(function()
	runService:UnbindFromRenderStep('CameraRotation')
	runService:BindToRenderStep('CameraRotation', Enum.RenderPriority.Camera.Value + 1, function()
		rotation = (rotation + 1 < 360 and rotation + 1 or 0) 
		camera.CFrame = clone.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(rotation), 0)
	end)
end)
	
button.MouseLeave:Connect(function()
	runService:UnbindFromRenderStep('CameraRotation')
	rotation = 0
	camera.CFrame = initAngle
end)

This code might not fix the problem because I don’t have all the details to the situation, but I hope this helps.

2 Likes

I’ve changed a bit since my last reply, so some variable names have changed etc and stuff, but still kinda the same.

I don’t seem to get that error anymore, but moving the mouse between the buttons really fast still doesn’t always make the frame visible

button.MouseEnter:Connect(function()
		subcategory.Icon.Model:ClearAllChildren()
		
		camera3D = Instance.new('Camera')
		camera3D.FieldOfView = 60
		
		subcategory.Icon.Model.CurrentCamera = camera3D
		
		local model3D = item:Clone()
		model3D.Parent = subcategory.Icon.Model
		
		subcategory.Visible = true
		
		runService:UnbindFromRenderStep('CameraRotation')
		
		runService:BindToRenderStep('CameraRotation', Enum.RenderPriority.Camera.Value + 1, function()
			rotation = (rotation + 1 < 360 and rotation + 1 or 0) 
			camera3D.CFrame = model3D.PrimaryPart.CFrame*CFrame.Angles(0, math.rad(rotation), 0)
		end)
	end)
	
	button.MouseLeave:Connect(function()
		subcategory.Visible = false
		
		runService:UnbindFromRenderStep('CameraRotation')
		rotation = 0
		camera3D.CFrame = initAngle
	end)

As well as the model being incredibly large when rotating
com-video-to-gif

This may be because the MouseEnter event for one button may be firing before the MouseLeave event for the previous button, but I’m not positive.

What’s the best way to fix that then???///

This is not the most efficient way but it should work fine. Just add this at the beginning of the MouseEnter event:

while (subcategory.Visible) do runService.Stepped:Wait() end

(Again, this is only if the MouseEnter event is firing before the MouseLeave event and by a substantial amount of time)