Trouble with ViewportFrame

So, basically, I’ve been trying to get a character to be in a viewport frame, however, I’ve come across a few issues.

  1. The camera is weirdly positioned at the legs of the character, and I can’t seem to change that, no matter what I try.

  2. I can’t rotate the camera properly for some reason. I really don’t know why, the camera is set to attach, and I’m rotating the part that it’s attached to, nothing. I have a stupidly long and bulky script here, and it just straight-up doesn’t work.

while wait(1) do

	game:GetService("TweenService"):Create(

		script.Parent,

		TweenInfo.new(
			2,
			Enum.EasingStyle.Linear,
			Enum.EasingDirection.InOut,	
			0,
			false,
			0
		),
	
		{Orientation = Vector3.new(0, 180, 0)}

	):Play()

	wait(2)

	game:GetService("TweenService"):Create(

		script.Parent,

		TweenInfo.new(
			1,
			Enum.EasingStyle.Linear,
			Enum.EasingDirection.InOut,	
			0,
			false,
			0
		),

		{Orientation = Vector3.new(0, -90, 0)}

	):Play()

	wait(1)

	game:GetService("TweenService"):Create(

		script.Parent,

		TweenInfo.new(
			1,
			Enum.EasingStyle.Linear,
			Enum.EasingDirection.InOut,	
			0,
			false,
			0
		),

		{Orientation = Vector3.new(0, 0, 0)}

	):Play()

end
1 Like

The way I personally do rotating around an object is with a short Module I wrote awhile back when first learning.

Basically just sets up the object and the second function more importantly sets up the Tween which you store in a variable. I store it in TweenVar[“Tween”]. This acts by tweening one NumValue from 0-360 on repeat. Here’s where I also define the TweenVar[“Offset”], a simple configurable Vector3. Using either RenderStepped or a .Changed event if you want to use an IntValue instead, you call the update like so:

Probably not the best solution available but works 100% reliably in my case and doesn’t have a noticeable impact on performance even when rendering a large amount of rotating objects.

2 Likes

I don’t understand most of the second part, could you maybe elaborate on what the brackets are doing, as well as what ClosetTweens is?

1 Like

ClosetTween is just a table of Tweens and their information essentially. I store them in a table because I have multiple objects rotating at any given time. In your case you might want to use a single variable such as PlayerTween. The variable itself though you’ll still want to be a Table so you can set various information about it such as PlayerTween[“Offset”].

The second function of the Module, CreateCameraTween creates the RotationalAngle object in the viewport and creates the Tween for going between 0-360 on it. It then returns that Tween which is what we’re storing in the Tables.

So it’d be called something like:

PlayerTween["Tween"] = ViewportModule:CreateCameraTween(Viewport, 5)
PlayerTween["Offset"] = Vector3.new(0,1.5,0) --Offsets it 1.5 studs upwards

The “Object” parts of the PlayerTween table stores the object it’s rotating around to get it’s primary part for pointing the Camera at. The [“Frame”] may not be one you need as it simply refers to the specific Frame that that particular objects Viewport is in.

2 Likes

This hasn’t seemed to work, and I’m not sure what I did wrong. (There’s no for loop at the end because I am only testing this with one viewpointFrame, and there is no object cloning because the object is already in the frame)

local viewportFunctionStorage = require(game:GetService("ReplicatedStorage").Functions.ViewportFunctionStorage)
local camera = viewportFunctionStorage.CreateCamera(script.Parent, script.Parent.CameraPos.CFrame)
local playerTween = {}

playerTween["Tween"] = viewportFunctionStorage.CreateCameraTween(script.Parent, 5)
playerTween["Offset"] = Vector3.new(0, 1.5, 0)

local target = script.Parent.CameraPos

game:GetService("RunService").RenderStepped:Connect(function()
	viewportFunctionStorage.UpdateViewportCamera(camera, playerTween["Offset"], script.Parent, target.Position)
end)
local functions = {}

--Create Camera

functions.CreateCamera = function(viewport, camPos)
	local newCam = workspace.Camera:Clone()
	newCam.Parent = viewport
	newCam.CFrame = camPos
	viewport.CurrentCamera = newCam
	return newCam
end

--Create Camera Tween

functions.CreateCameraTween = function(viewport, rotationTime)
	local rotationAngle = Instance.new("NumberValue", viewport)
	rotationAngle.Name = "RotationAngle"
	local tween = game:GetService("TweenService"):Create(
		rotationAngle,
		TweenInfo.new(
			rotationTime,
			Enum.EasingStyle.Linear,
			Enum.EasingDirection.InOut,
			-1
		),
		{Value = 360}
	)
	return tween
end

--Update Camera

functions.UpdateViewportCamera = function(camera, cameraOffset, viewport, lookAtPosition)
	local rotatedCFrame = CFrame.Angles(0, math.rad(viewport.RotationAngle.Value), 0)
	camera.CFrame = CFrame.new(lookAtPosition) * rotatedCFrame * CFrame.new(cameraOffset)
	camera.CFrame = CFrame.new(camera.CFrame.Position, lookAtPosition)
end

return functions

All this does is this:


And it stays like that, too. No rotation.

1 Like

After you create playerTween[“Tween”] make sure to call playerTween[“Tween”]:Play()

When the viewport isn’t being displayed you’ll probably want to Destroy the Tween and clear the table as well.

2 Likes

There’s still no rotation, and the camera is still in the same odd place.

A solution I’ve found to this issue is that instead of rotation the camera is to rotate the model itself?

Heres some code i’ve made if you’d like to use it.

local NEWSTUDS = 200
local WAIT = 1

local TARGET = script.Parent


    while wait(1) do
        if TARGET:IsA("Model") then
            if TARGET.PrimaryPart then
                TARGET:SetPrimaryPartCFrame(TARGET.PrimaryPart.CFrame * CFrame.Angles(0,math.rad(NEWSTUDS),0))
            end
        else
            TARGET.CFrame *= CFrame.Angles(0,math.rad(NEWSTUDS),0)
        end
    end
1 Like

Alright, it’s rotating now, but I still have the problem of the odd camera position.

1 Like

What is target.Position? Is CameraPos where you’re wanting to position the camera initially or where you want it to look at? The position of the camera away from the object is determined by the Offset whereas LookAtPos is the position the camera will rotate around as well as look at.

Ideally you’ll want the LookAtPos somewhere around the center of the object, and Offset you’ll need to tweak as needed to achieve the desired camera. With an offset of (0,1.5,0) you’ll move only 1.5 studs above where you want to rotate, you’ll need another slight offset in either the x or z axis, I think it’s normally +z but can depend on your initial setup.

2 Likes

Oh, that’s a good point. After making the offset change, everything works! Thanks for the help!

Final Scripts:

local functions = {}

--Create Camera

functions.CreateCamera = function(viewport, camPos)
	local newCam = workspace.Camera:Clone()
	newCam.Parent = viewport
	newCam.CFrame = camPos
	viewport.CurrentCamera = newCam
	return newCam
end

--Create Camera Tween

functions.CreateCameraTween = function(viewport, rotationTime)
	local rotationAngle = Instance.new("NumberValue", viewport)
	rotationAngle.Name = "RotationAngle"
	local tween = game:GetService("TweenService"):Create(
		rotationAngle,
		TweenInfo.new(
			rotationTime,
			Enum.EasingStyle.Linear,
			Enum.EasingDirection.InOut,
			-1
		),
		{Value = 360}
	)
	return tween
end

return functions
local viewportFunctionStorage = require(game:GetService("ReplicatedStorage").Functions.ViewportFunctionStorage)
local camera = viewportFunctionStorage.CreateCamera(script.Parent, script.Parent.CameraPos.CFrame)
local target = script.Parent.CameraPos

viewportFunctionStorage.CreateCameraTween(script.Parent, 7.5):Play()
camera.CFrame = CFrame.new(Vector3.new(0, 1, 5))

game:GetService("RunService").RenderStepped:Connect(function() script.Parent:FindFirstChildWhichIsA("Model"):SetPrimaryPartCFrame(CFrame.Angles(0, math.rad(script.Parent.RotationAngle.Value), 0)) end)
1 Like