I couldn’t think of a great way to describe what this tutorial will show you how to make, but I think the title coveys information better than “Making A Thing with ViewPort Frame”. A character customization is just a potential addition to this concept that could be added fairly easily. “Wait, so what are you giving me code for?” Great question, like I said, it’s hard to describe, so watch these videos!
This one has some context and shows what you could do with this.
Let’s get started! So we need a ScreenGui, the ViewportFrame itself, and the LocalScript.
Of course there are other configurations, like using a SurfaceGui and a normal Script if you want to adapt this code to do something similar to the result of these instructions. Now to the actual scripting! First we need to start by setting some basic things up.
local thePlayer = game.Players.LocalPlayer --Get the player
thePlayer.Character.Archivable = true --Make sure we can clone the character
newCamera = Instance.new('Camera') --Make a new camera
newCamera.CameraType = Enum.CameraType.Scriptable
script.Parent.CurrentCamera = newCamera --Set the viewport to use that camera
local vector1 = Vector3.new(0, -0.5, 7) --This is how far away the camera is away from the character, I like these settings the most.
local vector2 = Vector3.new(0, 3.142, 0) --Without this variable, we'd be staring at the back of the character's head. So we take 180 degrees and turn it into radians
Oh, since we’re going to be working with CFrames and Vector3s, we’re going to use this handy dandy function provided by Roblox
local function addcfv3(a, b)
local x, y, z, m11, m12, m13, m21, m22, m23, m31, m32, m33 = a:components()
return CFrame.new(x + b.x, y + b.y, z + b.z, m11, m12, m13, m21, m22, m23, m31, m32, m33);
end
Nice. But how can we update the ViewPort every frame? RunService.Heartbeat, that’s how! Let’s add this, in addition to the rest of the stuff.
RunService.Heartbeat:Connect(function()
if thePlayer.Character:FindFirstChild("HumanoidRootPart") then --Check if there's a HumanoidRootPart
for i, descendant in ipairs(script.Parent:GetDescendants()) do --Get all the parts already in the viewport...
if descendant.ClassName ~= "LocalScript" then -- ... check if it's not the LocalScript ...
descendant:Destroy() -- ... And destroy it, so we can put the new stuff in.
end
end
--This whole area is pretty neat, in that it gets the average of all the part positions. This reduces jittery motion by a lot
local targetedVector3 = Vector3.new()
local totalDivide = 0
for i, component in ipairs(thePlayer.Character:GetDescendants()) do
if component:IsA("BasePart") then
totalDivide = totalDivide + 1
targetedVector3 = targetedVector3 + component.Position
end
end
targetedVector3 = targetedVector3/totalDivide
--Finally, we set the camera to our desired position
newCamera.CoordinateFrame = addcfv3(
CFrame.new(
Vector3.new(),
thePlayer.Character.HumanoidRootPart.CFrame.LookVector
),
targetedVector3
)
local me = thePlayer.Character:Clone() --And clone your character into the viewport.
me.Sound:Destroy() --(Yeah, there's a sound here, delete it otherwise you get an error)
me.Parent = script.Parent
end
end)
So that’s all the code! Just combine it, tweak it, add more etc. I hope you find use of this mess of code!