Why is CFrame rotating once goal reached

I have this code, that when I open the map, it should zoom out above the map, and then allow the player to move around. Problem is, once the tweens done, it just rotates the camera around, which I don’t.

ezgif.com-gif-maker - 2022-11-23T214848.484

The position it is when the tween ends is where it should stay, it shouldn’t just rotate 90 degrees for no reason

-- Above map camera
function CameraController:OpenMap()
	Camera.CameraType = Enum.CameraType.Scriptable

	self.OriginalCFrame = Camera.CFrame

	local YOffset = workspace.MapSize.Position.Y - Player.Character:GetPivot().Position.Y

	local GoalCFrame = Player.Character:GetPivot() * CFrame.Angles(math.rad(-90), 0, 0) + Vector3.new(0, YOffset, 0)
	local TweenOut = TweenService:Create(Camera, TweenInfo.new(), {
		CFrame = GoalCFrame,
	})
	TweenOut:Play()
	TweenOut.Completed:Wait()

	-- Create map boundaries
	self.MinPoint, self.MaxPoint =
		Region:GetPoints(workspace.MapSize.Position, workspace.MapSize.Size + Vector3.new(0, SCROLL_INCREMENT ^ 2, 0))

	if self.Trove then
		self.Trove:Destroy()
		self.Trove = nil
	end

	self.Trove = Trove.new()
	self.Trove:Connect(RunService.Heartbeat, function()
		local MouseLocation = UserInputService:GetMouseLocation()

		if UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then
			if self.LastMouseLocation then
				local Delta = self.LastMouseLocation - MouseLocation

				Camera.CFrame += Camera.CFrame.RightVector * (Delta.X / 2)
				Camera.CFrame += Camera.CFrame.UpVector * (-Delta.Y / 2)
			end
		end

		self.LastMouseLocation = MouseLocation

		local MinCorner = self.MinPoint
		local MaxCorner = self.MaxPoint
		local CameraPosition = Camera.CFrame.Position

		-- TODO: Why it rotate camera??
		Camera.CFrame = CFrame.new(Vector3.new(), Camera.CFrame.LookVector)
			+ Vector3.new(
				math.clamp(CameraPosition.X, MinCorner.X, MaxCorner.X),
				math.clamp(CameraPosition.Y, MinCorner.Y, MaxCorner.Y),
				math.clamp(CameraPosition.Z, MinCorner.Z, MaxCorner.Z)
			)
	end)
end

I think the simplest way to fix this, is change the target CFrame from:

to:

    local err = 0.1
	local GoalCFrame = Player.Character:GetPivot() * CFrame.Angles(math.rad(-90+err), 0, 0) + Vector3.new(0, YOffset, 0)

No.

The goal CFrame is the CORRECT CFrame. This cannot be changed at all. That is the rotation the Map is supposed to face.

It happens here, but what is the goal of this part of the code? This will execute every ~4ms, and it changes the camera according to user input, so a mouse move and it will fire. When it is fired you instantly change the cameras position with Vector3.new() which is equal to 0,0,0. Why tween position if you reset it straight away as soon as the mouse moves?

Don’t worry, I am aware of that. The change is minimal, try the above modification and see the effect :stuck_out_tongue: !

So it’s the Vector3.new() part?? The section of that code is in a Heartbeat, and so it needs to update it’s position constantly as player drags their mouse (that’s what the + Vector3.new() stuff does)

+ Vector3.new(
				math.clamp(CameraPosition.X, MinCorner.X, MaxCorner.X),
				math.clamp(CameraPosition.Y, MinCorner.Y, MaxCorner.Y),
				math.clamp(CameraPosition.Z, MinCorner.Z, MaxCorner.Z)
			)

Comment all this out and it will work, you can drag mouse around and move map. I’ve tried it with a baseplate and a smaller part as your defined MapSize part. No need to define limits to the movement, the mouse will do that because it goes off window and stops firing move messages.

Yes commenting it out works, but now they can just leave the map. Point of that + Vector3.new() is to keep them locked into the map boundaries, that’s what the MinCorner/MaxCorner’s are for

That’s a good reason to explain things more clearly. You were concerned about it rotating, and nothing else from your post.

I thought the map bounds were self implied from:

:man_shrugging:

Replace…

Camera.CFrame = CFrame.new(Vector3.new(), Camera.CFrame.LookVector)
	+ Vector3.new(
		math.clamp(CameraPosition.X, MinCorner.X, MaxCorner.X),
		math.clamp(CameraPosition.Y, MinCorner.Y, MaxCorner.Y),
		math.clamp(CameraPosition.Z, MinCorner.Z, MaxCorner.Z)
	)

…with…

Camera.CFrame = CFrame.lookAt(Vector3.zero, Camera.CFrame.LookVector, Camera.CFrame.UpVector)
	+ Vector3.new(
		math.clamp(CameraPosition.X, MinCorner.X, MaxCorner.X),
		math.clamp(CameraPosition.Y, MinCorner.Y, MaxCorner.Y),
		math.clamp(CameraPosition.Z, MinCorner.Z, MaxCorner.Z)
	)

Because the camera points straight down, the engine picks an arbitrary axis to use as its UpVector since it cannot use a cross product of the y-Axis. By specifying the UpVector you want, it should keep the angle correct.

Implied interpretation is a mine field, we all think differently, that’s why clearly explained problems will save unnecessary effort from people trying to help (who in the end become frustrated with the organic undefined context of the problem).