Help with MIRROR

hi best rb scripters :wave:

ive been trying to fix the problem for a couple of days, looked at the forum, and nothing helped :sob:
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)

image

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
2 Likes

up up up up up pls help meee :sob: :sob: :sob:

This is Scripting Support, In order to receive help for your issue, please provide additional information (such as a script) for people to assist you.

1 Like

sorry I forgot. I have now added scripts and screenshots

up up up up up pls help meee :pray: :pray: :pray:

I would suggest that you don’t add those sounds to a clip that other devs will help you with. It is very irrelevant.

3 Likes

pls help meee help meee help meee help meee help meee help meee help meee help meee :pray: :pray: :pray:

pls help meee help help help meee help meee help meee help meee help meee help meee :pray: :pray: :pray:

help him!!!