hi best rb scripters
ive been trying to fix the problem for a couple of days, looked at the forum, and nothing helped
i would like to either fix this mirror or find a working one
i want to make a mirror, but I cant do it, I took it from the toolbox, but there are problems in it:
- strange character animation
- strange models (walls, windows)
- models and characters are not deleted in the mirror after being deleted in the workspace
- the character in the mirror does not change his appearance before reset (for example if you added an accessory in real time)
Read
local mirror = script.Mirror
mirror.Adornee = script.Parent
mirror:Clone().Parent = game.StarterGui
Control
local view = script.Parent.ViewportFrame
local sub = script.Parent.Adornee
if not sub then
repeat task.wait() sub = script.Parent.Adornee until sub
end
local p = game.Players.LocalPlayer
local FOV120 = math.rad(120)
local XZ = Vector3.new(1, 0, 1)
local YZ = Vector3.new(0, 1, 1)
local UNIT_NZ = Vector3.new(0, 0, -1)
local Y_SPIN = CFrame.fromEulerAnglesXYZ(0, math.pi, 0)
local clone = nil
if workspace.CurrentCamera then
clone = workspace.CurrentCamera:Clone()
clone.Parent = view
end
local chars = require(script.Characters)
local mapping = require(script.Map)
chars:setVpf(view)
task.wait()
mapping.connectModel(workspace:WaitForChild("MirrorFolder"), sub,view)
view.CurrentCamera = clone
local function getSurfaceInfo(part:BasePart):(CFrame,Vector3)
local partCF, partSize = part.CFrame, part.Size
local back = Vector3.FromNormalId(Enum.NormalId.Back)
local axis = (math.abs(back.y) == 1) and Vector3.new(back.y, 0, 0) or Vector3.new(0,1,0)
local right = CFrame.fromAxisAngle(axis, math.pi/2) * back
local top = back:Cross(right).Unit
local cf = partCF * CFrame.fromMatrix(-back*partSize/2, right, top, back)
local size = Vector3.new((partSize * right).Magnitude, (partSize * top).Magnitude, (partSize * back).Magnitude)
return cf, size
end
game:GetService("RunService").RenderStepped:Connect(function(d)
local cam = workspace.CurrentCamera
if not cam or not sub then
return
end
--local surfaceCF = sub.CFrame
--local surfaceSize = sub.Size
local surfaceCF,surfaceSize = getSurfaceInfo(sub)
local camCF = cam.CFrame
local tc = surfaceCF * Vector3.new(0, surfaceSize.Y/2, 0)
local bc = surfaceCF * Vector3.new(0, -surfaceSize.Y/2, 0)
local cross = camCF.LookVector:Cross(surfaceCF.UpVector)
local right = cross:Dot(cross) > 0 and cross.Unit or camCF.RightVector
local levelCamCF = CFrame.fromMatrix(camCF.Position, right, surfaceCF.UpVector, right:Cross(surfaceCF.UpVector))
local levelCamCFInv = levelCamCF:Inverse()
local csbc = levelCamCFInv * bc
local cstc = levelCamCFInv * tc
local v1 = (csbc*YZ).Unit
local v2 = (cstc*YZ).Unit
local alpha = math.sign(v1.y)*math.acos(v1:Dot(UNIT_NZ))
local beta = math.sign(v2.y)*math.acos(v2:Dot(UNIT_NZ))
local fh = 2*math.tan(math.rad(cam.FieldOfView)/2)
local hPrime = math.tan(beta) - math.tan(alpha)
local refHeight = hPrime / fh
--
local c2p = surfaceCF:VectorToObjectSpace(surfaceCF.Position - camCF.Position)
local c2pXZ = c2p * XZ
local c2pYZ = c2p * YZ
local dpX = c2pXZ.Unit:Dot(UNIT_NZ)
local camXZ = (surfaceCF:VectorToObjectSpace(camCF.LookVector) * XZ)
local scale = camXZ.Unit:Dot(c2pXZ.Unit) / UNIT_NZ:Dot(c2pXZ.Unit)
local tanArcCos = math.sqrt(1 - dpX*dpX) / dpX
--
local w, h = 1, (surfaceSize.X / surfaceSize.X)
local dx = math.sign(c2p.x*c2p.z)*tanArcCos
local dy = c2pYZ.y / c2pYZ.z * h
local d = math.abs(scale * refHeight * h)
local ncf = (surfaceCF - surfaceCF.Position) * Y_SPIN * CFrame.new(0, 0, 0, w, 0, 0, 0, h, 0, dx, dy, d)
local c = {ncf:GetComponents()}
local max = {}
for i = 1, #c do max[i] = math.abs(c[i]) end
max = math.max(unpack(max))
ncf = CFrame.new(c[1], c[2], c[3], c[4]/max, c[5]/max, c[6]/max, c[7]/max, c[8]/max, c[9]/max, c[10]/max, c[11]/max, c[12]/max)
--
--[[
-- can set w and h to 1 and use this as an alternative scaling method, but I find the above is better
local ratioXY = (surfaceSize.x / surfaceSize.y)
local ratioYX = (surfaceSize.y / surfaceSize.x)
if (ratioXY > ratioYX) then
self.SurfaceGUI.CanvasSize = Vector2.new(1024, 1024 * ratioYX)
else
self.SurfaceGUI.CanvasSize = Vector2.new(1024 * ratioXY, 1024)
end
--]]
local ncamCF = ncf + camCF.Position
local data = {
FieldOfView = cam.FieldOfView,
CFrame = ncamCF,
Focus = ncamCF * CFrame.new(0, 0, camCF:PointToObjectSpace(surfaceCF.Position).Z)
}
clone.FieldOfView = data.FieldOfView
clone.CFrame = data.CFrame
clone.Focus = data.Focus
end)
for _,v in pairs(game.Players:GetPlayers()) do
chars.connectP(v)
end
game.Players.PlayerAdded:Connect(chars.connectP)
Characters
local module = {
vpf = nil
}
local reflect = require(script.Parent.Reflect)
function module:setVpf(vpf)
self.vpf = vpf
end
function module.character(c,vpf)
task.wait(2)
c.Archivable = true
local clone = c:Clone()
--c.Archivable = false
clone.Parent = vpf.WorldModel
--print(clone)
local chum:Humanoid = clone:WaitForChild("Humanoid")
local hum:Humanoid = c:WaitForChild("Humanoid")
chum.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
local track:Animator = hum:WaitForChild("Animator")
local ctrack:Animator = chum:WaitForChild("Animator")
for i,a:AnimationTrack in pairs(ctrack:GetPlayingAnimationTracks()) do
a:Stop()
end
--clone.PrimaryPart.Anchored = true
local run
run = game:GetService("RunService").RenderStepped:Connect(function(d)
if clone and c and clone.PrimaryPart and c.PrimaryPart then
local get = c:GetPrimaryPartCFrame()
local sub = script.Parent.Parent.Adornee
local rel = sub.CFrame:ToObjectSpace(get)
clone:SetPrimaryPartCFrame(reflect(sub.CFrame,c:GetPrimaryPartCFrame(),clone:GetExtentsSize()))
elseif run.Connected then
run:Disconnect()
end
end)
track.AnimationPlayed:Connect(function(animTrack)
local anim = animTrack.Animation
local speed = animTrack.Speed
local load = ctrack:LoadAnimation(anim)
load:Play()
load:AdjustSpeed(speed)
animTrack.Stopped:Connect(function()
load:Stop()
load:Destroy()
end)
end)
c.Destroying:Connect(function()
clone:Destroy()
end)
end
function module.connectP(p:Player)
warn("connected ",p)
if p.Character then
module.character(p.Character,module.vpf)
end
p.CharacterAdded:Connect(function(c)
print(c)
module.character(c,module.vpf)
end)
end
return module
Map
local module = {}
local reflect = require(script.Parent.Reflect)
function inChar(t,v)
for _,c in pairs(t) do
if v:IsDescendantOf(c) then
return true
end
end
return false
end
function module.connectModel(m,sub,vpf)
local chars = {}
for _,p in pairs(game.Players:GetPlayers()) do
table.insert(chars,p.Character)
end
local group = Instance.new("Model",vpf)
local function tie(v)
if v:IsA("BasePart") and v~=workspace.Terrain and v~=sub and not inChar(chars,v) then
local clone = v:Clone()
clone.Parent = group
clone.CFrame = reflect(sub.CFrame,v.CFrame,clone.Size)
v.Changed:Connect(function(prop:string)
if prop == "CFrame" or prop == "Position" or prop == "Orientation" then
return
end
pcall(function()
local val = v[prop]
clone[prop] = val
end)
end)
local run1 = sub:GetPropertyChangedSignal("CFrame"):Connect(function()
clone.CFrame = reflect(sub.CFrame,v.CFrame)
end)
local lastFrame = v.CFrame
local run2 = game:GetService("RunService").RenderStepped:Connect(function()
local new = v and v.CFrame or lastFrame
if new==lastFrame then
return
end
lastFrame = new
--warn("change")
clone.CFrame = reflect(sub.CFrame,v.CFrame)
end)
v.Destroying:Connect(function()
clone:Destroy()
--run1:Disconnect()
run2:Disconnect()
end)
end
end
for i,v:Instance in pairs(m:GetDescendants()) do
tie(v)
end
--m.DescendantAdded:Connect(tie)
return group
end
return module
Reflect
function getSides(cf,s)
local sides = {
CFrame.new(-s.X/2,-s.Y/2,-s.Z/2),
CFrame.new(s.X/2,-s.Y/2,-s.Z/2),
CFrame.new(s.X/2,s.Y/2,-s.Z/2),
CFrame.new(s.X/2,s.Y/2,s.Z/2),
CFrame.new(-s.X/2,s.Y/2,s.Z/2),
CFrame.new(-s.X/2,-s.Y/2,s.Z/2),
CFrame.new(s.X/2,-s.Y/2,s.Z/2),
CFrame.new(-s.X/2,s.Y/2,-s.Z/2)
}
for i,v in pairs(sides) do
rawset(sides,i,cf*v)
end
return sides
end
function isBehind(a,b,s)
local sides = getSides(b,s)
--print(sides)
for i,v in pairs(sides) do
local rel = a:ToObjectSpace(v)
--print(rel)
if rel.Z<0 then
--print("visible")
return false
end
end
return true
end
return function(ca, cb, s)
--Get the CFrame relative to the mirror
local relCF = ca:toObjectSpace(cb)
if s then
local behind = isBehind(ca,cb,s)
if behind then
return CFrame.new(0,1e10,0)
end
end
--Get the original CFrame values
local x, y, z,
a, b, c,
d, e, f,
g, h, i = relCF:components()
--Reflecting along Z direction - negate Z axis on
--all vectors
local newCF = CFrame.new(
x, y, -z,
a, b, c,
d, e, f,
-g, -h, -i
)
--Convert back to world space
local finalCFrame = ca:toWorldSpace(newCF)
local x, y, z, r00, r01, r02, r10, r11, r12, r20, r21, r22 = finalCFrame:components()
finalCFrame = CFrame.new(x, y, z, -r00, r01, r02, -r10, r11, r12, -r20, r21, r22)
return finalCFrame
end