Hi. I am making a mirror, and it’s most likely done. Just a bit of help, the problem is with when a player is facing straight, the clone is also facing straight instead of looking at the character and it’s unanimated, too. Here’s how:
local Mirror = game.Workspace:WaitForChild("Mirror")
local RunService = game:GetService("RunService");
local Mirror = game.Workspace:WaitForChild("Mirror")
local RunService = game:GetService("RunService");
local function reflect()
for i, v in next, game.Players:GetPlayers() do
if (v) ~= nil then
if (v.Character) ~= nil then
for a, b in next, v.Character:GetDescendants() do
if (b) ~= nil then
if b:IsA("BasePart") or b:IsA("UnionOperation") or b:IsA("MeshPart") then
local objectSpace = Mirror.CFrame:Inverse() * (v.Character:GetPrimaryPartCFrame());
local worldSpace = Mirror.CFrame:ToWorldSpace(CFrame.new(objectSpace.X, objectSpace.Y, -objectSpace.Z) * CFrame.Angles(objectSpace:ToEulerAnglesXYZ()));
v.Character.Archivable = true;
local newCharacter;
if not workspace:FindFirstChild("Dummy") then
newCharacter = v.Character:Clone()
newCharacter.Name = "Dummy"
newCharacter.Parent = workspace;
end
local new = workspace:FindFirstChild("Dummy")
if new then
new:SetPrimaryPartCFrame(worldSpace)
end
end
end
end
end
end;
end;
end;
RunService.RenderStepped:Connect(reflect);
The reason it isn’t animated is because you’re only setting the CFrame of the dummy and not each of its individual parts. I see you’re looping through each part inside of the character, but you’re setting only the character’s CFrame each time, which is redundant. Try doing the same math but on the individual parts instead. You also have several unnecessary if checks. You don’t need to check if (b) is not nil, because the GetDescendants function by definition will not return a table with nil values.
Lol.
I basically did what you told me to, and it is still not animated, instead it’s giving me some weird CFrame changes when jumping, or walking. Here’s the new code:
local Mirror = game.Workspace:WaitForChild("Mirror")
local RunService = game:GetService("RunService");
local function reflect()
for i, v in next, game.Players:GetPlayers() do
if (v) ~= nil then
if (v.Character) ~= nil then
v.Character.Archivable = true
if not game.Workspace:FindFirstChild("Dummy") then
local character = v.Character:Clone()
character.Name = "Dummy"
character.Parent = game.Workspace
end
if workspace:FindFirstChild("Dummy") then
for index, val in pairs(workspace.Dummy:GetDescendants()) do
if val:IsA("BasePart") or val:IsA("UnionOperation") or val:IsA("MeshPart") then
local plrchar = v.Character:FindFirstChild(val.Name, true)
local objectedSpace = Mirror.CFrame:Inverse() * plrchar.CFrame
local yaw, pitch, roll = objectedSpace:ToEulerAnglesXYZ()
local worldSpace = Mirror.CFrame:ToWorldSpace(CFrame.new(objectedSpace.X,objectedSpace.Y, -objectedSpace.Z)) * CFrame.Angles(yaw, -pitch, roll);
val.CFrame = worldSpace * CFrame.Angles(0, -math.pi+math.pi, 0)
end
end
end
end
end
end;
end;
RunService.RenderStepped:Connect(reflect);
I did the way @gooey333 suggested, and it is still not working. Can you help? It’s kinda weird when the player jumps and walks.
local Mirror = game.Workspace:WaitForChild("Mirror")
local RunService = game:GetService("RunService");
local Mirror = game.Workspace:WaitForChild("Mirror")
local RunService = game:GetService("RunService");
local function getElements()
local elements = {};
for i, v in next, game.Players:GetPlayers() do
if (v) ~= nil then
if (v.Character) ~= nil then
for a, b in next, v.Character:GetDescendants() do
if (b) ~= nil then
if b:IsA("BasePart") or b:IsA("UnionOperation") or b:IsA("MeshPart") then
table.insert(elements, b.Name)
end
end
end
end
end;
end;
return elements
end
local function getObjectedSpace(cf1, cf2)
return cf1:ToObjectSpace(cf2)
end
local function getWorldedSpace(cf1, cf2)
return cf1:ToWorldSpace(cf2)
end
local function reflect()
local elements = getElements()
game.Players.LocalPlayer.Character.Archivable = true
local Playercharacter = game.Players.LocalPlayer.Character
local clonedCharacter = Playercharacter:Clone()
clonedCharacter.Parent = game.Workspace
RunService.RenderStepped:Connect(function()
for index, element in pairs(elements) do
local elementInOriginal, elementInFake = Playercharacter:FindFirstChild(element, true), clonedCharacter:FindFirstChild(element, true)
local objectedSpace = getObjectedSpace(Mirror.CFrame, elementInOriginal.CFrame)
local yaw, pitch, roll = objectedSpace:ToEulerAnglesXYZ()
local worldSpace = getWorldedSpace(Mirror.CFrame, CFrame.new(objectedSpace.X, objectedSpace.Y, -objectedSpace.Z)*CFrame.Angles(yaw, -pitch, roll))
local new = worldSpace * CFrame.Angles(0, -math.pi, 0)
elementInFake.CFrame = new
end
end)
end;
wait(1)
reflect()
Well your math is wrong. It would be pretty complicated. One thing you could try is cloning the character and reverting to what you had previously, but instead of copying part positions, copy Motor6d properties for all the limbs. This may replicate animations better than CFrames.
After setting copying the CurrentAngle property, I feel like I am almost there. Idle animation works, but others don’t work as intended. Here’s a video: robloxapp-20201209-0904353.wmv (4.4 MB)
and here’s the code:
local Mirror = game.Workspace:WaitForChild("Mirror")
local RunService = game:GetService("RunService");
local Mirror = game.Workspace:WaitForChild("Mirror")
local RunService = game:GetService("RunService");
local function reflect()
for i, v in next, game.Players:GetPlayers() do
if (v) ~= nil then
if (v.Character) ~= nil then
for a, b in next, v.Character:GetDescendants() do
if (b) ~= nil then
if b:IsA("BasePart") or b:IsA("UnionOperation") or b:IsA("MeshPart") or b:IsA("Motor6D") then
if not b:IsA("Motor6D") then
local objectSpace = Mirror.CFrame:Inverse() * (v.Character:GetPrimaryPartCFrame());
local yaw, pitch, roll = objectSpace:ToEulerAnglesXYZ()
local worldSpace = Mirror.CFrame:ToWorldSpace(CFrame.new(objectSpace.X, objectSpace.Y, -objectSpace.Z) * CFrame.Angles(yaw, -pitch, roll));
v.Character.Archivable = true;
local newCharacter;
if not workspace:FindFirstChild("Dummy") then
newCharacter = v.Character:Clone()
newCharacter.Name = "Dummy"
newCharacter.Parent = workspace;
end
local new = workspace:FindFirstChild("Dummy")
if new then
local set = worldSpace * CFrame.Angles(0, -math.pi, 0)
new:SetPrimaryPartCFrame(set)
end
else
local new = workspace:FindFirstChild("Dummy")
if new then
local motor = new:FindFirstChild(b.Name, true)
if motor and motor.Name == b.Name then
motor.Part0 = new:FindFirstChild(b.Part0.Name)
motor.Part1 = new:FindFirstChild(b.Part1.Name)
motor.CurrentAngle = b.CurrentAngle
end
end
end
end
end
end
end
end;
end;
end;
RunService.RenderStepped:Connect(reflect);
You shouldn’t have to set Part0 and Part1 every frame, but I don’t think that is messing you up. Instead of copying motor.CurrentAngle, try copying motor.Transform instead.
motor.Transform = b.Transform
Also you should create the dummy outside of the render stepped function and reference it. Make sure you are not redundantly setting the CFrame of the dummy for every part within the dummy. You only need to do that once per frame.