i’ve figured out how to create 2.5D characters using viewport frames, which is great! now i’ve managed to get myself into a pickle: every time i respawn, my character gets cloned incorrectly, which makes me into a gray default dummy, and my accessories aren’t being removed. i’ve been trying to solve this for a while, but i’ve had no luck.
the place file, in case my spaghetti code is confusing
pseudo 3D.rbxl (66.7 KB)
my full script
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
--\\ character setup
local client = Players.LocalPlayer
local plrGui = client:WaitForChild("PlayerGui")
local spriteSheet = plrGui:WaitForChild("char-2d")
local viewport = spriteSheet:FindFirstChildWhichIsA("ViewportFrame")
local worldModel = viewport:FindFirstChildWhichIsA("WorldModel")
local fakeChar = viewport:FindFirstChild("noob")
local currentCam = workspace.CurrentCamera
local testPart = workspace:WaitForChild("test-part") -- fake sprite for testing purposes (NOT real)
local connection
--\\ debugging function to track issues
local function debugPrint(message)
print(`[DEBUG:] {tostring(message)}`)
end
--\\ other functions
local function applyCharacter(char)
debugPrint("applying character...")
if not char.Archivable then
debugPrint("original character is not archivable")
char.Archivable = true
end
local newChar = char:Clone()
if not newChar then
debugPrint("new character is nil after cloning")
return
end
newChar.Parent = worldModel
if not fakeChar.PrimaryPart then
debugPrint("fake character's primary part is nil")
return
end
newChar:PivotTo(fakeChar.PrimaryPart.CFrame)
debugPrint("character applied successfully")
end
local function makeItemInvisible(target)
for _, descendant in target:GetDescendants() do
if descendant:IsA("BasePart") or descendant:IsA("MeshPart") then
descendant.Transparency = 1
descendant.Material = Enum.Material.SmoothPlastic
elseif descendant:IsA("Decal") then
descendant.Transparency = 1
elseif descendant:IsA("Accessory") then
descendant:Destroy()
end
end
end
local function loadCharacter(char)
if not char or not char.Parent then
debugPrint("character is nil or not fully spawned")
return
end
debugPrint("loading character...")
applyCharacter(char)
-- disconnect existing connection if character respawns
if connection then
connection:Disconnect()
end
local root = char:WaitForChild("HumanoidRootPart", 10)
if not root then
debugPrint("error: root not found")
return
end
makeItemInvisible(char) -- make character invisible
-- sync y-axis rotation with test part
connection = RunService.PreRender:Connect(function()
local camCFrame = currentCam.CFrame
local _, camYRot, _ = camCFrame:ToEulerAnglesYXZ() -- gimme that y-axis rotation
local partPos = root.Position
-- apply y-axis of the camera to the part while maintaining its position
testPart.CFrame = CFrame.new(partPos) * CFrame.Angles(0, camYRot, 0)
end)
debugPrint("character loaded successfully")
end
--\\ listen for character spawns and load the character
client.CharacterAdded:Connect(function(newCharacter)
debugPrint("character added event triggered")
newCharacter:WaitForChild("HumanoidRootPart", 10)
loadCharacter(newCharacter)
end)
-- load the character if already present (first run)
if client.Character and client.Character.Parent then
debugPrint("character exists on first run")
client.Character:WaitForChild("HumanoidRootPart", 10)
loadCharacter(client.Character)
else
debugPrint("no character on first run")
end
here is a screenshot of what happens after i respawn.
⠀
vs a screenshot of what is supposed to happen.