Super portal gun (Updated)
Key RequiredUniversal

Super portal gun (Updated)

Universal ScriptPao_scriptsPao_scripts 827 views 5.9K executesUpdated Sep 22, 2026
Unrated
00
Lua Script•512 lines (14897 chars)
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local Debris = game:GetService("Debris")

local LocalPlayer = Players.LocalPlayer
local WEAPON_ASSET_ID = 136461991241487 -- ID da Arma 3D
local PORTAL_ASSET_ID = 2160656233       -- ID do Portal 3D
local TOOL_ICON_ID = 120404128273122     -- Novo ID da Imagem do Ícone no Inventário
local TOOL_NAME = "Portal Gun"

-- Nomes Atualizados dos Portais
local NOME_PORTAL_1 = "Porta9202837"
local NOME_PORTAL_2 = "portal81738380"

-- Ajustes de Posição e Rotação da Arma na Mão
local POSITION_OFFSET = Vector3.new(0, -0.2, -1) 
local ROTATION_OFFSET = CFrame.Angles(math.rad(180), math.rad(90), math.rad(0))

-- Controle de Estado
local cliqueCount = 0
local portal1 = nil
local portal2 = nil
local cooldownTeleport = false
local executandoDisparo = false

-- Interface do Canto Inferior Direito
local function mostrarNotificacaoDireita()
	local pGui = LocalPlayer:WaitForChild("PlayerGui")
	local sg = pGui:FindFirstChild("PortalGunNotif") or Instance.new("ScreenGui")
	sg.Name = "PortalGunNotif"
	sg.ResetOnSpawn = false
	sg.Parent = pGui
	
	local frame = Instance.new("Frame")
	frame.Size = UDim2.new(0, 200, 0, 40)
	frame.Position = UDim2.new(1, -210, 1, -50)
	frame.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
	frame.BorderSizePixel = 0
	frame.Parent = sg
	
	local corner = Instance.new("UICorner")
	corner.CornerRadius = UDim.new(0, 8)
	corner.Parent = frame
	
	local label = Instance.new("TextLabel")
	label.Size = UDim2.new(1, 0, 1, 0)
	label.BackgroundTransparency = 1
	label.Text = "Portal gun 1.2 Carregado"
	label.TextColor3 = Color3.fromRGB(255, 255, 255)
	label.TextSize = 14
	label.Font = Enum.Font.SourceSansBold
	label.Parent = frame
	
	task.delay(4, function()
		if sg then sg:Destroy() end
	end)
end

-- Ajuste físico do modelo da arma
local function ajustarFisicaDaPart(part)
	if part:IsA("BasePart") then
		part.Anchored = false
		part.CanCollide = false
		part.CanTouch = false
		part.CanQuery = false
		part.Massless = true
		part.CustomPhysicalProperties = PhysicalProperties.new(0.001, 0, 0, 0, 0)
	end
end

-- Solda o modelo da arma
local function soldarModeloEPreparar(instancia)
	local parts = {}
	if instancia:IsA("BasePart") then
		table.insert(parts, instancia)
		ajustarFisicaDaPart(instancia)
	end
	for _, child in ipairs(instancia:GetDescendants()) do
		if child:IsA("BasePart") then
			table.insert(parts, child)
			ajustarFisicaDaPart(child)
		end
	end
	if #parts > 1 then
		local mainPart = parts[1]
		for i = 2, #parts do
			local weld = Instance.new("WeldConstraint")
			weld.Part0 = mainPart
			weld.Part1 = parts[i]
			weld.Parent = mainPart
		end
	end
end

-- Carrega o Portal 3D e limpa scripts internos
local function carregarModeloPortal(cframeTarget, nomePortal)
	local success, result = pcall(function()
		return game:GetObjects("rbxassetid://" .. PORTAL_ASSET_ID)[1]
	end)
	
	local portalObj = nil
	if success and result then
		portalObj = result
	else
		portalObj = Instance.new("Part")
		portalObj.Size = Vector3.new(4, 7, 0.5)
		portalObj.Color = Color3.fromRGB(150, 0, 255)
		portalObj.Material = Enum.Material.Neon
	end
	
	portalObj.Name = nomePortal
	
	-- Apaga scripts, avisos e prompts nativos do asset
	for _, child in ipairs(portalObj:GetDescendants()) do
		if child:IsA("ProximityPrompt") or child:IsA("BillboardGui") or child:IsA("SurfaceGui") or child:IsA("Script") or child:IsA("LocalScript") then
			child:Destroy()
		end
	end
	
	if portalObj:IsA("Model") then
		portalObj:PivotTo(cframeTarget)
		for _, child in ipairs(portalObj:GetDescendants()) do
			if child:IsA("BasePart") then
				child.Anchored = true
				child.CanCollide = false
				child.CanTouch = true
			end
		end
	elseif portalObj:IsA("BasePart") then
		portalObj.CFrame = cframeTarget
		portalObj.Anchored = true
		portalObj.CanCollide = false
		portalObj.CanTouch = true
	end
	
	portalObj.Parent = Workspace
	return portalObj
end

local function getPortalCFrame(portal)
	if not portal then return nil end
	if portal:IsA("Model") then
		return portal:GetPivot()
	elseif portal:IsA("BasePart") then
		return portal.CFrame
	end
	return nil
end

-- Configuração do Teletransporte por Toque com Recarga de 2 Segundos
local function configurarGatilhosDeTeleport()
	if not portal1 or not portal2 then return end

	local function aplicarGatilho(portalOrigem, obterPortalDestino)
		local partsTarget = {}
		if portalOrigem:IsA("BasePart") then
			table.insert(partsTarget, portalOrigem)
		else
			for _, v in ipairs(portalOrigem:GetDescendants()) do
				if v:IsA("BasePart") then
					table.insert(partsTarget, v)
				end
			end
		end
		
		for _, part in ipairs(partsTarget) do
			part.Touched:Connect(function(hit)
				if cooldownTeleport then return end
				
				local char = hit.Parent
				local hrp = char:FindFirstChild("HumanoidRootPart")
				
				if hrp and char == LocalPlayer.Character then
					local destPortal = obterPortalDestino()
					if destPortal then
						local destCFrame = getPortalCFrame(destPortal)
						if destCFrame then
							cooldownTeleport = true
							hrp.CFrame = destCFrame * CFrame.new(0, 0, -4)
							task.wait(2)
							cooldownTeleport = false
						end
					end
				end
			end)
		end
	end

	aplicarGatilho(portal1, function() return portal2 end)
	aplicarGatilho(portal2, function() return portal1 end)
end

-- Disparo da Bola Roxa com Cronômetro Máximo de 3 Segundos
local function dispararBolaRoxa(etapa)
	local char = LocalPlayer.Character
	if not char or not char:FindFirstChild("HumanoidRootPart") then 
		executandoDisparo = false
		return 
	end
	
	local mouse = LocalPlayer:GetMouse()
	local targetPos = mouse.Hit and mouse.Hit.Position or (char.HumanoidRootPart.CFrame * CFrame.new(0, 0, -50)).Position
	local startPos = char.HumanoidRootPart.Position + Vector3.new(0, 1.5, 0)
	local direction = (targetPos - startPos).Unit
	
	local bola = Instance.new("Part")
	bola.Shape = Enum.PartType.Ball
	bola.Size = Vector3.new(1.5, 1.5, 1.5)
	bola.Color = Color3.fromRGB(140, 0, 255)
	bola.Material = Enum.Material.Neon
	bola.CanCollide = true
	bola.Anchored = false
	bola.CFrame = CFrame.new(startPos, startPos + direction)
	
	local bv = Instance.new("BodyVelocity")
	bv.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
	bv.Velocity = direction * 150
	bv.Parent = bola
	
	bola.Parent = Workspace
	
	local impactoProcessado = false
	local conect = nil
	
	local function criarPortalNoImpacto(hitCFrame)
		if impactoProcessado then return end
		impactoProcessado = true
		
		if conect then
			conect:Disconnect()
		end
		
		if bola and bola.Parent then
			bola:Destroy()
		end
		
		if etapa == 1 then
			if portal1 then portal1:Destroy() end
			portal1 = carregarModeloPortal(hitCFrame, NOME_PORTAL_1)
		elseif etapa == 2 then
			if portal2 then portal2:Destroy() end
			portal2 = carregarModeloPortal(hitCFrame, NOME_PORTAL_2)
			configurarGatilhosDeTeleport()
		end
		
		executandoDisparo = false
	end
	
	-- Timer limite de 3 segundos para spawnar o portal caso dispare no céu
	task.delay(3, function()
		if not impactoProcessado and bola and bola.Parent then
			local finalCFrame = CFrame.new(bola.Position, bola.Position + direction)
			criarPortalNoImpacto(finalCFrame)
		end
	end)
	
	bola.Touched:Connect(function(hit)
		if hit and not hit:IsDescendantOf(char) and hit.Name ~= NOME_PORTAL_1 and hit.Name ~= NOME_PORTAL_2 then
			local raycastParams = RaycastParams.new()
			raycastParams.FilterDescendantsInstances = {char, bola}
			raycastParams.FilterType = Enum.RaycastFilterType.Exclude
			
			local result = Workspace:Raycast(bola.Position, direction * 5, raycastParams)
			local surfaceNormal = result and result.Normal or Vector3.new(0, 1, 0)
			local hitPos = result and result.Position or bola.Position
			
			local finalCFrame = CFrame.new(hitPos + (surfaceNormal * 0.5), hitPos + surfaceNormal) * CFrame.Angles(math.rad(90), 0, 0)
			criarPortalNoImpacto(finalCFrame)
		end
	end)
	
	conect = game:GetService("RunService").Heartbeat:Connect(function()
		if impactoProcessado or not bola or not bola.Parent then
			if conect then conect:Disconnect() end
			return
		end
		
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {char, bola}
		raycastParams.FilterType = Enum.RaycastFilterType.Exclude
		
		local result = Workspace:Raycast(bola.Position, direction * 4, raycastParams)
		if result then
			if conect then conect:Disconnect() end
			local finalCFrame = CFrame.new(result.Position + (result.Normal * 0.5), result.Position + result.Normal) * CFrame.Angles(math.rad(90), 0, 0)
			criarPortalNoImpacto(finalCFrame)
		end
	end)
end

-- Processador da Ação
local function processarClique()
	if executandoDisparo then return end
	
	cliqueCount = cliqueCount + 1
	
	if cliqueCount == 1 then
		executandoDisparo = true
		dispararBolaRoxa(1)
	elseif cliqueCount == 2 then
		executandoDisparo = true
		dispararBolaRoxa(2)
	elseif cliqueCount >= 3 then
		if portal1 then portal1:Destroy() portal1 = nil end
		if portal2 then portal2:Destroy() portal2 = nil end
		cliqueCount = 0
	end
end

-- Criador da Tool
local function criarPortalGun()
	local backpack = LocalPlayer:WaitForChild("Backpack")
	local character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
	
	for _, item in ipairs(backpack:GetChildren()) do
		if item.Name == TOOL_NAME or item.Name == "gun" or item.Name == "Gun" then
			item:Destroy()
		end
	end
	for _, item in ipairs(character:GetChildren()) do
		if item.Name == TOOL_NAME or item.Name == "gun" or item.Name == "Gun" then
			item:Destroy()
		end
	end
	
	local tool = Instance.new("Tool")
	tool.Name = TOOL_NAME
	tool.TextureId = "rbxassetid://" .. tostring(TOOL_ICON_ID)
	tool.RequiresHandle = true
	
	local handle = Instance.new("Part")
	handle.Name = "Handle"
	handle.Size = Vector3.new(0.2, 0.2, 0.2)
	handle.Transparency = 1
	ajustarFisicaDaPart(handle)
	handle.Parent = tool
	
	tool.Parent = backpack
	local modelo3D = nil
	
	tool.Equipped:Connect(function()
		local char = LocalPlayer.Character
		if not char then return end
		
		local success, result = pcall(function()
			return game:GetObjects("rbxassetid://" .. WEAPON_ASSET_ID)[1]
		end)
		
		if success and result then
			if result:IsA("Tool") then
				local visualContainer = Instance.new("Model")
				visualContainer.Name = "VisualModel"
				for _, child in ipairs(result:GetChildren()) do
					if child:IsA("BasePart") or child:IsA("Model") or child:IsA("Accessory") then
						child.Parent = visualContainer
					end
				end
				result:Destroy()
				modelo3D = visualContainer
			else
				modelo3D = result
			end
			
			soldarModeloEPreparar(modelo3D)
			
			local rightHand = char:FindFirstChild("RightHand") or char:FindFirstChild("Right Arm")
			if rightHand then
				local offsetCFrame = CFrame.new(POSITION_OFFSET) * ROTATION_OFFSET
				local mainPart = modelo3D:IsA("Model") and (modelo3D.PrimaryPart or modelo3D:FindFirstChildWhichIsA("BasePart")) or modelo3D
				
				if mainPart then
					if modelo3D:IsA("Model") then
						modelo3D:PivotTo(rightHand.CFrame * offsetCFrame)
					else
						mainPart.CFrame = rightHand.CFrame * offsetCFrame
					end
					local weldToHand = Instance.new("WeldConstraint")
					weldToHand.Part0 = rightHand
					weldToHand.Part1 = mainPart
					weldToHand.Parent = mainPart
				end
			end
			modelo3D.Parent = char
		end
	end)
	
	tool.Activated:Connect(function()
		processarClique()
	end)
	
	tool.Unequipped:Connect(function()
		if modelo3D then
			modelo3D:Destroy()
			modelo3D = nil
		end
	end)
end

-- Limpeza e Verificação de Portais
local function verificarELimparPortais()
	local pGui = LocalPlayer:WaitForChild("PlayerGui")
	
	local portaisEncontrados = {}
	for _, obj in ipairs(Workspace:GetChildren()) do
		if obj.Name == NOME_PORTAL_1 or obj.Name == NOME_PORTAL_2 or obj.Name == "Portal1" or obj.Name == "Portal2" then
			table.insert(portaisEncontrados, obj)
		end
	end
	
	local totalPortais = #portaisEncontrados
	
	local redGui = Instance.new("ScreenGui")
	redGui.Name = "RedPortalCheckGUI"
	redGui.ResetOnSpawn = false
	redGui.Parent = pGui
	
	local frameRed = Instance.new("Frame")
	frameRed.Size = UDim2.new(0, 220, 0, 70)
	frameRed.Position = UDim2.new(0.5, -110, 0.5, -35)
	frameRed.BackgroundColor3 = Color3.fromRGB(180, 40, 40)
	frameRed.BorderSizePixel = 0
	frameRed.Parent = redGui
	
	local corner = Instance.new("UICorner")
	corner.CornerRadius = UDim.new(0, 8)
	corner.Parent = frameRed
	
	local lblStatus = Instance.new("TextLabel")
	lblStatus.Size = UDim2.new(1, 0, 1, 0)
	lblStatus.BackgroundTransparency = 1
	lblStatus.Text = "Verificando Portais... 0/" .. totalPortais
	lblStatus.TextColor3 = Color3.fromRGB(255, 255, 255)
	lblStatus.TextSize = 16
	lblStatus.Font = Enum.Font.SourceSansBold
	lblStatus.Parent = frameRed
	
	task.wait(0.5)
	
	if totalPortais > 0 then
		for i, pObj in ipairs(portaisEncontrados) do
			lblStatus.Text = "Limpando Portais... " .. i .. "/" .. totalPortais
			pObj:Destroy()
			task.wait(0.5)
		end
	end
	
	redGui:Destroy()
	criarPortalGun()
end

-- Janela Principal (GUI)
local function iniciarGUI()
	mostrarNotificacaoDireita()
	
	local pGui = LocalPlayer:WaitForChild("PlayerGui")
	local mainGui = Instance.new("ScreenGui")
	mainGui.Name = "PortalGunMainGUI"
	mainGui.ResetOnSpawn = false
	mainGui.Parent = pGui
	
	local frame = Instance.new("Frame")
	frame.Size = UDim2.new(0, 320, 0, 180)
	frame.Position = UDim2.new(0.5, -160, 0.5, -90)
	frame.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
	frame.BorderSizePixel = 0
	frame.Parent = mainGui
	
	local corner = Instance.new("UICorner")
	corner.CornerRadius = UDim.new(0, 10)
	corner.Parent = frame
	
	local title = Instance.new("TextLabel")
	title.Size = UDim2.new(1, 0, 0, 40)
	title.BackgroundTransparency = 1
	title.Text = "Portal gun foi iniciado você está na versão 1.2"
	title.TextColor3 = Color3.fromRGB(255, 255, 255)
	title.TextSize = 13
	title.Font = Enum.Font.SourceSansBold
	title.Parent = frame
	
	local bugs = Instance.new("TextLabel")
	bugs.Size = UDim2.new(1, 0, 0, 50)
	bugs.Position = UDim2.new(0, 0, 0, 40)
	bugs.BackgroundTransparency = 1
	bugs.Text = "Bugs consertados✅\nÍcone no inventário alterado✅"
	bugs.TextColor3 = Color3.fromRGB(180, 255, 180)
	bugs.TextSize = 14
	bugs.Font = Enum.Font.SourceSansBold
	bugs.Parent = frame
	
	local btnOk = Instance.new("TextButton")
	btnOk.Size = UDim2.new(0, 100, 0, 35)
	btnOk.Position = UDim2.new(0.5, -50, 1, -45)
	btnOk.BackgroundColor3 = Color3.fromRGB(0, 150, 255)
	btnOk.Text = "OK"
	btnOk.TextColor3 = Color3.fromRGB(255, 255, 255)
	btnOk.Font = Enum.Font.SourceSansBold
	btnOk.TextSize = 16
	btnOk.Parent = frame
	
	local btnCorner = Instance.new("UICorner")
	btnCorner.CornerRadius = UDim.new(0, 6)
	btnCorner.Parent = btnOk
	
	btnOk.MouseButton1Click:Connect(function()
		mainGui:Destroy()
		verificarELimparPortais()
	end)
end

-- Execução do Script
iniciarGUI()

Features & Information

Portal gun Update 1.1 Update: Bugs fixed ✅ Image of the changed inventory item ✅ Bug fixed: now when you click on the sky with the portal, the script waits 3 seconds and then opens the portal high up Image of the changed inventory item: the item has been changed.

Community Comments (0)

No comments yet for this script.

More Scripts for Universal Scripts