
Key RequiredUniversal

--[[
TELEKINESIS V4.4
PC + MOBILE UNIFICADO
CAMBIOS DE ESTA VERSIÓN
- Ctrl derecho = mostrar / ocultar interfaz en PC
- Supr deja de controlar la interfaz
- Ocultar interfaz NO desactiva el sistema
- Móvil puede ocultar / mostrar correctamente
- Botón de mostrar móvil arriba a la izquierda
- Highlights se restauran al mostrar
- Imán:
- controles arriba
- Desactivar abajo izquierda
- Anclar todo abajo derecha
- Rotación:
- flechas abajo izquierda
- no ocupan el centro
- Cursor visual conservado
- Motor PC / móvil unificado
]]
--------------------------------------------------
-- SERVICIOS
--------------------------------------------------
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local StarterGui = game:GetService("StarterGui")
local Debris = game:GetService("Debris")
local CoreGui = game:GetService("CoreGui")
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local isMobile = UserInputService.TouchEnabled
--------------------------------------------------
-- CONFIG
--------------------------------------------------
local CONFIG = {
-- Lanzamiento
throwForce = 1000,
throwForceMin = 100,
throwForceMax = 4000,
throwForceStepPC = 100,
throwForceStepMobile = 200,
-- Imán
magnetRadius = 30,
magnetRadiusMin = 5,
magnetRadiusMax = 200,
magnetForce = 200,
magnetForceMin = 50,
magnetForceMax = 2000,
magnetForceStep = 25,
magnetRadiusStep = 2,
-- Agarre
holdDistanceDefault = 10,
holdDistanceMin = 2,
holdDistanceMax = 1000,
distanceSpeed = 0.8,
distanceKeySpeed = 0.4,
-- Rotación
rotationSpeed = 2,
-- Física
holdVelocityP = 12500,
holdGyroP = 3000,
-- Bloqueo de posición
rotationPositionP = 20000,
rotationPositionD = 1250,
-- Cursor móvil
pointerDragThreshold = 10,
}
--------------------------------------------------
-- ESTADO
--------------------------------------------------
local STATE = {
active = true,
-- IMPORTANTE:
-- guiVisible controla solo la interfaz.
guiVisible = true,
holding = false,
target = nil,
holdDistance = CONFIG.holdDistanceDefault,
anchoredWhileHolding = false,
magnetActive = false,
magnetObjects = {},
rotationMode = false,
rotationKeys = {
up = false,
down = false,
left = false,
right = false,
},
holdQ = false,
holdE = false,
holdClose = false,
holdFar = false,
rotationPosition = nil,
-- Personaje
characterVisibilityBackup = {},
characterFrozen = false,
characterBackup = nil,
-- Cursor móvil
pointerTouch = nil,
pointerTouchStart = nil,
pointerDragStarted = false,
-- Modo móvil
mobileMode = "normal",
-- Notificaciones
lastNotificationTime = 0,
notificationCooldown = 0.25,
}
--------------------------------------------------
-- PERSONAJE
--------------------------------------------------
local function getCharacter()
return player.Character
end
local function getHumanoid()
local character = getCharacter()
return character
and character:FindFirstChildOfClass("Humanoid")
end
local function getRootPart()
local character = getCharacter()
return character
and character:FindFirstChild("HumanoidRootPart")
end
--------------------------------------------------
-- FÍSICA
--------------------------------------------------
local bodyVelocity = Instance.new("BodyVelocity")
bodyVelocity.Name = "TelekinesisVelocity"
bodyVelocity.MaxForce = Vector3.new(1, 1, 1) * 1e5
bodyVelocity.P = CONFIG.holdVelocityP
bodyVelocity.Velocity = Vector3.zero
local bodyGyro = Instance.new("BodyGyro")
bodyGyro.Name = "TelekinesisGyro"
bodyGyro.MaxTorque = Vector3.new(1, 1, 1) * 1e6
bodyGyro.P = CONFIG.holdGyroP
local rotationPositionLock = Instance.new("BodyPosition")
rotationPositionLock.Name = "TelekinesisRotationPosition"
rotationPositionLock.MaxForce = Vector3.new(1, 1, 1) * 1e7
rotationPositionLock.P = CONFIG.rotationPositionP
rotationPositionLock.D = CONFIG.rotationPositionD
rotationPositionLock.Position = Vector3.zero
--------------------------------------------------
-- HIGHLIGHTS
--------------------------------------------------
local highlightHolding = Instance.new("Highlight")
highlightHolding.Name = "TelekinesisHolding"
highlightHolding.FillColor = Color3.fromRGB(0, 255, 0)
highlightHolding.OutlineColor = Color3.fromRGB(0, 255, 0)
highlightHolding.FillTransparency = 0.5
highlightHolding.OutlineTransparency = 0
highlightHolding.DepthMode = Enum.HighlightDepthMode.Occluded
highlightHolding.Enabled = true
highlightHolding.Parent = CoreGui
local highlightLooking = Instance.new("Highlight")
highlightLooking.Name = "TelekinesisLooking"
highlightLooking.FillColor = Color3.fromRGB(0, 170, 255)
highlightLooking.OutlineColor = Color3.fromRGB(0, 170, 255)
highlightLooking.FillTransparency = 0.6
highlightLooking.OutlineTransparency = 0
highlightLooking.DepthMode = Enum.HighlightDepthMode.Occluded
highlightLooking.Enabled = true
highlightLooking.Parent = CoreGui
--------------------------------------------------
-- VISUAL IMÁN
--------------------------------------------------
local usingDrawing =
Drawing
and Drawing.new
and typeof(Drawing.new) == "function"
local magnetCircle
local circleGui
local circleImage
local surfacePosition = Vector3.zero
local actualMagnetRadius = CONFIG.magnetRadius
if usingDrawing then
magnetCircle = Drawing.new("Circle")
magnetCircle.Visible = false
magnetCircle.Transparency = 1
magnetCircle.Color = Color3.fromRGB(0, 170, 255)
magnetCircle.Thickness = 2
magnetCircle.Filled = false
else
circleGui = Instance.new("BillboardGui")
circleGui.Name = "TelekinesisMagnetCircle"
circleGui.Size = UDim2.fromOffset(100, 100)
circleGui.AlwaysOnTop = true
circleGui.Enabled = false
circleGui.Parent = CoreGui
circleImage = Instance.new("ImageLabel")
circleImage.BackgroundTransparency = 1
circleImage.Image = "rbxassetid://13523341990"
circleImage.ImageColor3 = Color3.fromRGB(0, 170, 255)
circleImage.AnchorPoint = Vector2.new(0.5, 0.5)
circleImage.Position = UDim2.fromScale(0.5, 0.5)
circleImage.Size = UDim2.fromScale(1, 1)
circleImage.Parent = circleGui
end
--------------------------------------------------
-- UI
--------------------------------------------------
local UI = {}
--------------------------------------------------
-- UI HELPERS
--------------------------------------------------
local function makeCorner(object, radius)
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, radius or 12)
corner.Parent = object
return corner
end
local function makeStroke(object, transparency)
local stroke = Instance.new("UIStroke")
stroke.Color = Color3.fromRGB(255, 255, 255)
stroke.Transparency = transparency or 0.75
stroke.Thickness = 1
stroke.Parent = object
return stroke
end
local function styleButton(button)
button.AutoButtonColor = false
makeCorner(button, 14)
makeStroke(button, 0.78)
return button
end
--------------------------------------------------
-- GUI PC
--------------------------------------------------
local function createMainGUI()
local gui = Instance.new("ScreenGui")
gui.Name = "TelekinesisUI"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.Parent = CoreGui
UI.mainGui = gui
local forceLabel = Instance.new("TextLabel")
forceLabel.Name = "ForceLabel"
forceLabel.BackgroundTransparency = 0.3
forceLabel.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
forceLabel.Size = UDim2.fromOffset(220, 60)
forceLabel.Position = UDim2.new(1, -230, 1, -70)
forceLabel.TextScaled = true
forceLabel.Font = Enum.Font.GothamBold
forceLabel.TextColor3 = Color3.new(1, 1, 1)
forceLabel.TextStrokeTransparency = 0.5
forceLabel.Visible = not isMobile
makeCorner(forceLabel, 14)
makeStroke(forceLabel, 0.8)
forceLabel.Parent = gui
UI.forceLabel = forceLabel
local rotationLabel = Instance.new("TextLabel")
rotationLabel.Name = "RotationLabel"
rotationLabel.BackgroundTransparency = 0.3
rotationLabel.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
rotationLabel.Size = UDim2.fromOffset(260, 70)
rotationLabel.Position = UDim2.new(1, -270, 1, -80)
rotationLabel.TextScaled = true
rotationLabel.Font = Enum.Font.GothamBold
rotationLabel.TextColor3 = Color3.new(1, 1, 1)
rotationLabel.Text = "🔄 ROTACIÓN\nWASD / ↑↓←→"
rotationLabel.Visible = false
makeCorner(rotationLabel, 14)
makeStroke(rotationLabel, 0.8)
rotationLabel.Parent = gui
UI.rotationLabel = rotationLabel
end
--------------------------------------------------
-- UI MÓVIL
--------------------------------------------------
local function createMobileUI()
local gui = Instance.new("ScreenGui")
gui.Name = "TelekinesisMobile"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.Parent = CoreGui
UI.mobileGui = gui
--------------------------------------------------
-- CURSOR VISUAL
--------------------------------------------------
local fakePointer = Instance.new("Frame")
fakePointer.Name = "FakePointer"
fakePointer.Size = UDim2.fromOffset(35, 35)
fakePointer.Position = UDim2.new(0.5, 0, 0.4, 0)
fakePointer.AnchorPoint = Vector2.new(0.5, 0.5)
fakePointer.BackgroundColor3 =
Color3.fromRGB(0, 170, 255)
fakePointer.BackgroundTransparency = 0.4
fakePointer.Active = true
fakePointer.ZIndex = 50
fakePointer.Parent = gui
makeCorner(fakePointer, 35)
makeStroke(fakePointer, 0.25)
UI.fakePointer = fakePointer
--------------------------------------------------
-- CONTENEDOR
--------------------------------------------------
local container = Instance.new("Frame")
container.Name = "Controls"
container.Size = UDim2.fromScale(1, 1)
container.BackgroundTransparency = 1
container.Parent = gui
UI.mobileContainer = container
--------------------------------------------------
-- CABECERA
--------------------------------------------------
local header = Instance.new("Frame")
header.Name = "Header"
header.Size = UDim2.new(0, 230, 0, 55)
header.Position = UDim2.new(0.5, -115, 0, 12)
header.BackgroundColor3 =
Color3.fromRGB(25, 25, 25)
header.BackgroundTransparency = 0.18
header.ZIndex = 10
header.Parent = container
makeCorner(header, 16)
makeStroke(header, 0.7)
UI.header = header
--------------------------------------------------
-- MODO
--------------------------------------------------
local modeLabel = Instance.new("TextLabel")
modeLabel.Name = "ModeLabel"
modeLabel.BackgroundTransparency = 1
modeLabel.Size = UDim2.new(1, -55, 1, 0)
modeLabel.Position = UDim2.fromOffset(8, 0)
modeLabel.Font = Enum.Font.GothamBold
modeLabel.TextScaled = true
modeLabel.TextColor3 = Color3.new(1, 1, 1)
modeLabel.Text = "🎯 NORMAL"
modeLabel.ZIndex = 11
modeLabel.Parent = header
UI.modeLabel = modeLabel
--------------------------------------------------
-- OJO
--------------------------------------------------
local hideButton = Instance.new("TextButton")
hideButton.Name = "Hide"
hideButton.Size = UDim2.fromOffset(45, 45)
hideButton.Position = UDim2.new(1, -50, 0, 5)
hideButton.BackgroundColor3 =
Color3.fromRGB(70, 70, 70)
hideButton.BackgroundTransparency = 0.15
hideButton.Text = "👁️"
hideButton.TextScaled = true
hideButton.TextColor3 = Color3.new(1, 1, 1)
hideButton.ZIndex = 12
styleButton(hideButton)
hideButton.Parent = header
UI.hideButton = hideButton
--------------------------------------------------
-- PANEL
--------------------------------------------------
local panel = Instance.new("Frame")
panel.Name = "ModePanel"
panel.Size = UDim2.new(1, 0, 0, 300)
panel.Position = UDim2.new(0, 0, 1, -305)
panel.BackgroundTransparency = 1
panel.ZIndex = 5
panel.Parent = container
UI.panel = panel
--------------------------------------------------
-- BOTÓN CENTRAL
--------------------------------------------------
local actionButton = Instance.new("TextButton")
actionButton.Name = "Action"
actionButton.Size = UDim2.fromOffset(190, 68)
actionButton.Position =
UDim2.new(0.5, -95, 1, -80)
actionButton.BackgroundColor3 =
Color3.fromRGB(0, 190, 100)
actionButton.BackgroundTransparency = 0.05
actionButton.Text = "✋ AGARRAR"
actionButton.TextScaled = true
actionButton.Font = Enum.Font.GothamBold
actionButton.TextColor3 = Color3.new(1, 1, 1)
actionButton.ZIndex = 10
styleButton(actionButton)
actionButton.Parent = panel
UI.actionButton = actionButton
--------------------------------------------------
-- CREAR BOTÓN
--------------------------------------------------
local function makeSmallButton(
name,
position,
size,
text,
color
)
local button = Instance.new("TextButton")
button.Name = name
button.Size = size
button.Position = position
button.BackgroundColor3 = color
button.BackgroundTransparency = 0.15
button.Text = text
button.TextScaled = true
button.Font = Enum.Font.GothamBold
button.TextColor3 = Color3.new(1, 1, 1)
button.ZIndex = 10
styleButton(button)
button.Parent = panel
return button
end
--------------------------------------------------
-- NORMAL
--------------------------------------------------
UI.buttons = {}
UI.buttons.distanceDown =
makeSmallButton(
"DistanceDown",
UDim2.new(0, 12, 1, -155),
UDim2.fromOffset(72, 55),
"📏\n−",
Color3.fromRGB(60, 135, 200)
)
UI.buttons.distanceUp =
makeSmallButton(
"DistanceUp",
UDim2.new(0, 92, 1, -155),
UDim2.fromOffset(72, 55),
"📏\n+",
Color3.fromRGB(60, 135, 200)
)
UI.buttons.throw =
makeSmallButton(
"Throw",
UDim2.new(1, -92, 1, -155),
UDim2.fromOffset(80, 58),
"🔥\nLANZAR",
Color3.fromRGB(210, 70, 65)
)
UI.buttons.anchor =
makeSmallButton(
"Anchor",
UDim2.new(1, -178, 1, -155),
UDim2.fromOffset(78, 58),
"📌\nANCLAR",
Color3.fromRGB(205, 150, 45)
)
UI.buttons.forceDown =
makeSmallButton(
"ForceDown",
UDim2.new(0, 12, 1, -220),
UDim2.fromOffset(72, 50),
"🎯 −",
Color3.fromRGB(145, 70, 70)
)
UI.buttons.forceUp =
makeSmallButton(
"ForceUp",
UDim2.new(0, 92, 1, -220),
UDim2.fromOffset(72, 50),
"🎯 +",
Color3.fromRGB(65, 150, 85)
)
UI.buttons.magnet =
makeSmallButton(
"Magnet",
UDim2.new(1, -92, 1, -220),
UDim2.fromOffset(80, 50),
"🧲 IMÁN",
Color3.fromRGB(55, 130, 205)
)
UI.buttons.rotation =
makeSmallButton(
"Rotation",
UDim2.new(1, -178, 1, -220),
UDim2.fromOffset(78, 50),
"🔄 ROTAR",
Color3.fromRGB(120, 85, 190)
)
--------------------------------------------------
-- VALOR
--------------------------------------------------
local valueLabel = Instance.new("TextLabel")
valueLabel.Name = "Value"
valueLabel.Size = UDim2.fromOffset(180, 42)
valueLabel.Position =
UDim2.new(0.5, -90, 1, -140)
valueLabel.BackgroundColor3 =
Color3.fromRGB(25, 25, 25)
valueLabel.BackgroundTransparency = 0.18
valueLabel.TextScaled = true
valueLabel.Font = Enum.Font.GothamBold
valueLabel.TextColor3 = Color3.new(1, 1, 1)
valueLabel.ZIndex = 9
makeCorner(valueLabel, 12)
makeStroke(valueLabel, 0.8)
valueLabel.Parent = panel
UI.valueLabel = valueLabel
--------------------------------------------------
-- IMÁN
--------------------------------------------------
UI.magnetButtons = {}
UI.magnetButtons.forceDown =
makeSmallButton(
"MagnetForceDown",
UDim2.new(0, 12, 1, -220),
UDim2.fromOffset(90, 55),
"⚡ −",
Color3.fromRGB(145, 70, 70)
)
UI.magnetButtons.forceUp =
makeSmallButton(
"MagnetForceUp",
UDim2.new(0, 108, 1, -220),
UDim2.fromOffset(90, 55),
"⚡ +",
Color3.fromRGB(65, 150, 85)
)
UI.magnetButtons.radiusDown =
makeSmallButton(
"RadiusDown",
UDim2.new(1, -204, 1, -220),
UDim2.fromOffset(90, 55),
"📏 −",
Color3.fromRGB(60, 135, 200)
)
UI.magnetButtons.radiusUp =
makeSmallButton(
"RadiusUp",
UDim2.new(1, -108, 1, -220),
UDim2.fromOffset(90, 55),
"📏 +",
Color3.fromRGB(60, 135, 200)
)
--------------------------------------------------
-- CAMBIO PEDIDO:
-- DESACTIVAR ABAJO IZQUIERDA
--------------------------------------------------
UI.magnetButtons.exit =
makeSmallButton(
"MagnetExit",
UDim2.new(0, 20, 1, -105),
UDim2.fromOffset(175, 58),
"🧲 DESACTIVAR",
Color3.fromRGB(180, 65, 65)
)
--------------------------------------------------
-- CAMBIO PEDIDO:
-- ANCLAR TODO ABAJO DERECHA
--------------------------------------------------
UI.magnetButtons.massAnchor =
makeSmallButton(
"MassAnchor",
UDim2.new(1, -195, 1, -105),
UDim2.fromOffset(175, 58),
"📌 ANCLAR TODO",
Color3.fromRGB(200, 145, 35)
)
--------------------------------------------------
-- ROTACIÓN
--------------------------------------------------
UI.rotationButtons = {}
--------------------------------------------------
-- CAMBIO PEDIDO:
-- TODO EL PAD ABAJO IZQUIERDA
--------------------------------------------------
UI.rotationButtons.up =
makeSmallButton(
"RotateUp",
UDim2.new(0, 102, 1, -165),
UDim2.fromOffset(62, 55),
"▲",
Color3.fromRGB(100, 80, 190)
)
UI.rotationButtons.left =
makeSmallButton(
"RotateLeft",
UDim2.new(0, 34, 1, -105),
UDim2.fromOffset(62, 55),
"◀",
Color3.fromRGB(100, 80, 190)
)
UI.rotationButtons.right =
makeSmallButton(
"RotateRight",
UDim2.new(0, 170, 1, -105),
UDim2.fromOffset(62, 55),
"▶",
Color3.fromRGB(100, 80, 190)
)
UI.rotationButtons.down =
makeSmallButton(
"RotateDown",
UDim2.new(0, 102, 1, -45),
UDim2.fromOffset(62, 55),
"▼",
Color3.fromRGB(100, 80, 190)
)
UI.rotationButtons.exit =
makeSmallButton(
"RotateExit",
UDim2.new(1, -175, 1, -100),
UDim2.fromOffset(155, 55),
"✅ TERMINAR",
Color3.fromRGB(65, 145, 90)
)
--------------------------------------------------
-- OCULTAR MODOS AL INICIO
--------------------------------------------------
for _, button in pairs(UI.magnetButtons) do
button.Visible = false
end
for _, button in pairs(UI.rotationButtons) do
button.Visible = false
end
end
createMainGUI()
if isMobile then
createMobileUI()
end
--------------------------------------------------
-- NOTIFICACIONES
--------------------------------------------------
local function notify(title, text, duration)
if not STATE.active then
return
end
local now = os.clock()
if now - STATE.lastNotificationTime
< STATE.notificationCooldown then
return
end
STATE.lastNotificationTime = now
pcall(function()
StarterGui:SetCore(
"SendNotification",
{
Title = title,
Text = text,
Duration = duration or 1.2,
}
)
end)
end
--------------------------------------------------
-- UTILIDADES
--------------------------------------------------
local function isPlayerPart(part)
if not part then
return false
end
for _, otherPlayer in ipairs(
Players:GetPlayers()
) do
local character =
otherPlayer.Character
if character
and part:IsDescendantOf(character) then
return true
end
end
return false
end
local function hasUnanchoredWeld(part)
for _, connectedPart in ipairs(
part:GetConnectedParts()
) do
if connectedPart ~= part
and not connectedPart.Anchored then
return true
end
end
return false
end
--------------------------------------------------
-- VISIBILIDAD DEL PERSONAJE
--------------------------------------------------
local function hideCharacter()
local character =
player.Character
if not character then
return
end
if next(
STATE.characterVisibilityBackup
) ~= nil then
return
end
for _, object in ipairs(
character:GetDescendants()
) do
if object:IsA("BasePart") then
STATE.characterVisibilityBackup[
object
] =
object.LocalTransparencyModifier
object.LocalTransparencyModifier = 1
elseif object:IsA("Decal")
or object:IsA("Texture") then
STATE.characterVisibilityBackup[
object
] =
object.Transparency
object.Transparency = 1
end
end
end
local function showCharacter()
for object, transparency in pairs(
STATE.characterVisibilityBackup
) do
if object
and object:IsDescendantOf(workspace) then
if object:IsA("BasePart") then
object.LocalTransparencyModifier =
transparency
elseif object:IsA("Decal")
or object:IsA("Texture") then
object.Transparency =
transparency
end
end
end
STATE.characterVisibilityBackup = {}
end
--------------------------------------------------
-- CONGELAR PERSONAJE
--------------------------------------------------
local function freezeCharacter()
if STATE.characterFrozen then
return
end
local humanoid = getHumanoid()
local root = getRootPart()
if not humanoid or not root then
return
end
STATE.characterBackup = {
WalkSpeed = humanoid.WalkSpeed,
JumpPower = humanoid.JumpPower,
JumpHeight = humanoid.JumpHeight,
AutoRotate = humanoid.AutoRotate,
RootAnchored = root.Anchored,
}
STATE.characterFrozen = true
humanoid.WalkSpeed = 0
humanoid.JumpPower = 0
humanoid.JumpHeight = 0
humanoid.AutoRotate = false
root.AssemblyLinearVelocity =
Vector3.zero
root.AssemblyAngularVelocity =
Vector3.zero
root.Anchored = true
end
local function unfreezeCharacter()
if not STATE.characterFrozen then
return
end
local humanoid = getHumanoid()
local root = getRootPart()
local backup = STATE.characterBackup
STATE.characterFrozen = false
STATE.characterBackup = nil
if humanoid and backup then
humanoid.WalkSpeed =
backup.WalkSpeed
humanoid.JumpPower =
backup.JumpPower
humanoid.JumpHeight =
backup.JumpHeight
humanoid.AutoRotate =
backup.AutoRotate
end
if root and backup then
root.Anchored =
backup.RootAnchored
end
end
--------------------------------------------------
-- FÍSICA
--------------------------------------------------
local function disconnectPhysics()
bodyVelocity.Parent = nil
bodyGyro.Parent = nil
end
local function connectPhysics(target)
if not target then
return
end
bodyVelocity.Parent = target
bodyGyro.Parent = target
end
--------------------------------------------------
-- RAY
--------------------------------------------------
local function getAimRay()
if isMobile and UI.fakePointer then
local position =
UI.fakePointer.AbsolutePosition
local size =
UI.fakePointer.AbsoluteSize
local x =
position.X
+ size.X * 0.5
local y =
position.Y
+ size.Y * 0.5
local ray =
camera:ScreenPointToRay(x, y)
return Ray.new(
ray.Origin,
ray.Direction * 1000
)
end
local ray =
camera:ScreenPointToRay(
mouse.X,
mouse.Y
)
return Ray.new(
ray.Origin,
ray.Direction * 1000
)
end
local function raycastNormal()
local ray =
getAimRay()
return workspace:FindPartOnRayWithIgnoreList(
ray,
{
getCharacter()
}
)
end
local function raycastForMagnet()
local ray =
getAimRay()
local ignoreList = {
getCharacter()
}
for _ = 1, 100 do
local hit, position, normal =
workspace:FindPartOnRayWithIgnoreList(
ray,
ignoreList
)
if not hit then
return nil, nil, nil
end
if isPlayerPart(hit) then
table.insert(
ignoreList,
hit
)
elseif hit:IsA("BasePart")
and not hit.Anchored then
table.insert(
ignoreList,
hit
)
else
return hit, position, normal
end
end
return nil, nil, nil
end
--------------------------------------------------
-- HIGHLIGHTS
--------------------------------------------------
local function refreshHighlights()
if not STATE.guiVisible then
highlightHolding.Enabled = false
highlightLooking.Enabled = false
return
end
highlightHolding.Enabled = true
highlightLooking.Enabled = true
if STATE.holding and STATE.target then
highlightHolding.Adornee =
STATE.target
highlightLooking.Adornee = nil
elseif not STATE.holding then
highlightHolding.Adornee = nil
local hit = raycastNormal()
if hit
and hit:IsA("BasePart")
and not hit.Anchored
and not isPlayerPart(hit) then
highlightLooking.Adornee =
hit
else
highlightLooking.Adornee = nil
end
else
highlightHolding.Adornee = nil
highlightLooking.Adornee = nil
end
end
--------------------------------------------------
-- MOSTRAR / OCULTAR UI
--------------------------------------------------
local function setInterfaceVisible(visible)
STATE.guiVisible = visible
if not isMobile then
if UI.forceLabel then
UI.forceLabel.Visible =
visible
end
if UI.rotationLabel then
UI.rotationLabel.Visible =
visible
and STATE.rotationMode
end
else
if UI.mobileContainer then
UI.mobileContainer.Visible =
visible
end
if UI.fakePointer then
UI.fakePointer.Visible =
visible
end
end
--------------------------------------------------
-- EL CÍRCULO DEL IMÁN
-- también depende de la visibilidad.
--------------------------------------------------
if not visible then
if usingDrawing
and magnetCircle then
magnetCircle.Visible = false
elseif circleGui then
circleGui.Enabled = false
end
end
refreshHighlights()
end
local function toggleInterface()
setInterfaceVisible(
not STATE.guiVisible
)
end
--------------------------------------------------
-- MÓVIL: UI NORMAL
--------------------------------------------------
local function updateMobileNormalUI()
if not isMobile then
return
end
STATE.mobileMode =
"normal"
UI.modeLabel.Text =
"🎯 NORMAL"
--------------------------------------------------
-- NORMAL
--------------------------------------------------
UI.buttons.distanceDown.Visible = true
UI.buttons.distanceUp.Visible = true
UI.buttons.throw.Visible = true
UI.buttons.anchor.Visible = true
UI.buttons.forceDown.Visible = true
UI.buttons.forceUp.Visible = true
UI.buttons.magnet.Visible = true
UI.buttons.rotation.Visible = true
UI.actionButton.Visible = true
UI.valueLabel.Visible = true
--------------------------------------------------
-- OCULTAR OTROS MODOS
--------------------------------------------------
for _, button in pairs(
UI.magnetButtons
) do
button.Visible = false
end
for _, button in pairs(
UI.rotationButtons
) do
button.Visible = false
end
--------------------------------------------------
-- VALOR
--------------------------------------------------
UI.valueLabel.Text =
"🎯 "
.. math.floor(
CONFIG.throwForce
)
--------------------------------------------------
-- AGARRAR / SOLTAR
--------------------------------------------------
if STATE.holding then
UI.actionButton.Text =
"❌ SOLTAR"
UI.actionButton.BackgroundColor3 =
Color3.fromRGB(
190,
55,
55
)
else
UI.actionButton.Text =
"✋ AGARRAR"
UI.actionButton.BackgroundColor3 =
Color3.fromRGB(
0,
190,
100
)
end
refreshHighlights()
end
--------------------------------------------------
-- MÓVIL: UI IMÁN
--------------------------------------------------
local function updateMobileMagnetUI()
if not isMobile then
return
end
STATE.mobileMode =
"magnet"
UI.modeLabel.Text =
"🧲 MODO IMÁN"
--------------------------------------------------
-- OCULTAR NORMAL
--------------------------------------------------
UI.buttons.distanceDown.Visible = false
UI.buttons.distanceUp.Visible = false
UI.buttons.throw.Visible = false
UI.buttons.anchor.Visible = false
UI.buttons.forceDown.Visible = false
UI.buttons.forceUp.Visible = false
UI.buttons.magnet.Visible = false
UI.buttons.rotation.Visible = false
UI.actionButton.Visible = false
--------------------------------------------------
-- MOSTRAR IMÁN
--------------------------------------------------
for _, button in pairs(
UI.magnetButtons
) do
button.Visible = true
end
for _, button in pairs(
UI.rotationButtons
) do
button.Visible = false
end
--------------------------------------------------
-- VALOR
--------------------------------------------------
UI.valueLabel.Visible = true
UI.valueLabel.Text =
"⚡ "
.. math.floor(
CONFIG.magnetForce
)
.. " • 📏 "
.. math.floor(
CONFIG.magnetRadius
)
end
--------------------------------------------------
-- MÓVIL: UI ROTACIÓN
--------------------------------------------------
local function updateMobileRotationUI()
if not isMobile then
return
end
STATE.mobileMode =
"rotation"
UI.modeLabel.Text =
"🔄 MODO ROTACIÓN"
--------------------------------------------------
-- OCULTAR NORMAL
--------------------------------------------------
UI.buttons.distanceDown.Visible = false
UI.buttons.distanceUp.Visible = false
UI.buttons.throw.Visible = false
UI.buttons.anchor.Visible = false
UI.buttons.forceDown.Visible = false
UI.buttons.forceUp.Visible = false
UI.buttons.magnet.Visible = false
UI.buttons.rotation.Visible = false
UI.actionButton.Visible = false
--------------------------------------------------
-- ROTACIÓN
--------------------------------------------------
for _, button in pairs(
UI.magnetButtons
) do
button.Visible = false
end
for _, button in pairs(
UI.rotationButtons
) do
button.Visible = true
end
--------------------------------------------------
-- VALOR
--------------------------------------------------
UI.valueLabel.Visible = true
UI.valueLabel.Text = "↑ ↓ ← → • MANTÉN"
end
--------------------------------------------------
-- AGARRAR
--------------------------------------------------
local function grabOrRelease()
if not STATE.active then
return
end
if STATE.magnetActive then
return
end
if STATE.rotationMode then
return
end
--------------------------------------------------
-- SOLTAR
--------------------------------------------------
if STATE.holding then
local target =
STATE.target
STATE.holding = false
STATE.target = nil
STATE.anchoredWhileHolding = false
disconnectPhysics()
if target
and target:IsDescendantOf(workspace) then
target.AssemblyLinearVelocity =
Vector3.zero
target.AssemblyAngularVelocity =
Vector3.zero
end
if isMobile then
updateMobileNormalUI()
end
return
end
--------------------------------------------------
-- AGARRAR
--------------------------------------------------
local hit, position =
raycastNormal()
if not hit
or not hit:IsA("BasePart") then
return
end
if isPlayerPart(hit) then
return
end
if hit.Anchored then
if not hit:GetAttribute(
"TelekinesisAnchored"
) then
return
end
hit.Anchored = false
hit:SetAttribute(
"TelekinesisAnchored",
nil
)
end
STATE.target = hit
STATE.holding = true
STATE.anchoredWhileHolding = false
STATE.holdDistance =
position
and (
camera.CFrame.Position
- position
).Magnitude
or (
camera.CFrame.Position
- hit.Position
).Magnitude
bodyGyro.CFrame =
hit.CFrame
connectPhysics(hit)
if isMobile then
updateMobileNormalUI()
end
notify(
"✋ AGARRADO",
"",
0.5
)
end
--------------------------------------------------
-- LANZAR
--------------------------------------------------
local function throwObject()
if not STATE.active
or STATE.magnetActive
or STATE.rotationMode then
return
end
if not STATE.holding
or not STATE.target then
return
end
local target =
STATE.target
STATE.holding = false
STATE.target = nil
STATE.anchoredWhileHolding = false
disconnectPhysics()
if target
and target:IsDescendantOf(workspace) then
target.Anchored = false
local ray =
getAimRay()
local velocity =
Instance.new("BodyVelocity")
velocity.Name =
"TelekinesisThrow"
velocity.MaxForce =
Vector3.new(1, 1, 1) * 1e6
velocity.P =
CONFIG.holdVelocityP
velocity.Velocity =
ray.Direction.Unit
* CONFIG.throwForce
velocity.Parent =
target
Debris:AddItem(
velocity,
0.5
)
end
if isMobile then
updateMobileNormalUI()
end
notify(
"🔥 LANZADO",
"",
0.5
)
end
--------------------------------------------------
-- ANCLAR
--------------------------------------------------
local function toggleAnchored()
if not STATE.active
or STATE.magnetActive
or STATE.rotationMode then
return
end
if not STATE.holding
or not STATE.target then
return
end
local target =
STATE.target
STATE.anchoredWhileHolding =
not STATE.anchoredWhileHolding
target.Anchored =
STATE.anchoredWhileHolding
if STATE.anchoredWhileHolding then
target:SetAttribute(
"TelekinesisAnchored",
true
)
target.AssemblyLinearVelocity =
Vector3.zero
target.AssemblyAngularVelocity =
Vector3.zero
disconnectPhysics()
else
target:SetAttribute(
"TelekinesisAnchored",
nil
)
connectPhysics(target)
end
notify(
STATE.anchoredWhileHolding
and "📌 ANCLADO"
or "📎 DESANCLADO",
"",
0.5
)
end
--------------------------------------------------
-- ROTACIÓN
--------------------------------------------------
local function resetRotationKeys()
STATE.rotationKeys.up = false
STATE.rotationKeys.down = false
STATE.rotationKeys.left = false
STATE.rotationKeys.right = false
end
local function enterRotationMode()
if not STATE.holding
or not STATE.target then
notify(
"❌ NO DISPONIBLE",
"Debes agarrar un objeto primero",
2
)
return
end
if STATE.anchoredWhileHolding then
notify(
"❌ OBJETO ANCLADO",
"Desancla el objeto antes de rotarlo",
2
)
return
end
local target =
STATE.target
STATE.rotationMode =
true
STATE.rotationPosition =
target.Position
resetRotationKeys()
bodyVelocity.Parent = nil
bodyGyro.Parent = nil
rotationPositionLock.Position =
STATE.rotationPosition
rotationPositionLock.Parent =
target
target.AssemblyLinearVelocity =
Vector3.zero
target.AssemblyAngularVelocity =
Vector3.zero
freezeCharacter()
hideCharacter()
if isMobile then
updateMobileRotationUI()
else
if UI.rotationLabel then
UI.rotationLabel.Visible =
STATE.guiVisible
end
if UI.forceLabel then
UI.forceLabel.Visible = false
end
end
notify(
"🔄 MODO ROTACIÓN",
"W/A/S/D o flechas",
1.5
)
end
local function exitRotationMode()
if not STATE.rotationMode then
return
end
local target =
STATE.target
STATE.rotationMode =
false
resetRotationKeys()
rotationPositionLock.Parent =
nil
STATE.rotationPosition =
nil
showCharacter()
unfreezeCharacter()
if target
and target:IsDescendantOf(workspace) then
if not STATE.anchoredWhileHolding then
connectPhysics(target)
bodyGyro.CFrame =
target.CFrame
end
end
if isMobile then
updateMobileNormalUI()
else
if UI.rotationLabel then
UI.rotationLabel.Visible =
STATE.guiVisible
and false
end
if UI.forceLabel
and STATE.guiVisible then
UI.forceLabel.Visible = true
end
end
notify(
"🔄 ROTACIÓN TERMINADA",
"",
0.7
)
end
local function toggleRotationMode()
if STATE.rotationMode then
exitRotationMode()
else
enterRotationMode()
end
end
--------------------------------------------------
-- ACTUALIZAR ROTACIÓN
--------------------------------------------------
local function updateRotation()
if not STATE.rotationMode
or not STATE.target then
return
end
local target =
STATE.target
if STATE.rotationPosition then
rotationPositionLock.Position =
STATE.rotationPosition
end
local horizontal = 0
local vertical = 0
if STATE.rotationKeys.left then
horizontal -= 1
end
if STATE.rotationKeys.right then
horizontal += 1
end
if STATE.rotationKeys.up then
vertical += 1
end
if STATE.rotationKeys.down then
vertical -= 1
end
if horizontal == 0
and vertical == 0 then
target.AssemblyLinearVelocity =
Vector3.zero
target.AssemblyAngularVelocity =
Vector3.zero
return
end
if horizontal ~= 0 then
target.CFrame =
target.CFrame
* CFrame.Angles(
0,
math.rad(
horizontal
* CONFIG.rotationSpeed
),
0
)
end
if vertical ~= 0 then
target.CFrame =
target.CFrame
* CFrame.Angles(
math.rad(
-vertical
* CONFIG.rotationSpeed
),
0,
0
)
end
target.AssemblyLinearVelocity =
Vector3.zero
target.AssemblyAngularVelocity =
Vector3.zero
end
--------------------------------------------------
-- IMÁN
--------------------------------------------------
local function restoreMagnetPhysics()
for object in pairs(
STATE.magnetObjects
) do
if object
and object:IsDescendantOf(workspace) then
local bv =
object:FindFirstChild("ImanBV")
if bv then
bv:Destroy()
end
end
end
STATE.magnetObjects = {}
end
local function massAnchorMagnet()
if not STATE.active
or not STATE.magnetActive then
return
end
local count = 0
for object in pairs(
STATE.magnetObjects
) do
if object
and object:IsDescendantOf(workspace) then
object.Anchored = true
object:SetAttribute(
"TelekinesisAnchored",
true
)
local bv =
object:FindFirstChild("ImanBV")
if bv then
bv:Destroy()
end
count += 1
end
end
STATE.magnetObjects = {}
notify(
"📌 ANCLAJE MASIVO",
"Se anclaron "
.. count
.. " objetos",
1.5
)
end
local function activateMagnet()
if not STATE.active then
return
end
if STATE.holding then
notify(
"❌ NO DISPONIBLE",
"Suelta el objeto para usar el imán",
2
)
return
end
if STATE.rotationMode then
return
end
STATE.magnetActive = true
if isMobile then
updateMobileMagnetUI()
end
notify(
"🧲 IMÁN ACTIVADO",
"Las piezas no ancladas se atraviesan",
1.5
)
end
local function deactivateMagnet()
STATE.magnetActive = false
restoreMagnetPhysics()
if isMobile then
updateMobileNormalUI()
end
notify(
"🧲 IMÁN DESACTIVADO",
"",
0.7
)
end
local function toggleMagnet()
if STATE.magnetActive then
deactivateMagnet()
else
activateMagnet()
end
end
--------------------------------------------------
-- FUERZA
--------------------------------------------------
local function changeThrowForce(amount)
CONFIG.throwForce =
math.clamp(
CONFIG.throwForce + amount,
CONFIG.throwForceMin,
CONFIG.throwForceMax
)
if isMobile
and STATE.mobileMode == "normal" then
updateMobileNormalUI()
end
notify(
"🎯 FUERZA",
tostring(
math.floor(
CONFIG.throwForce
)
),
0.5
)
end
local function changeMagnetForce(amount)
CONFIG.magnetForce =
math.clamp(
CONFIG.magnetForce + amount,
CONFIG.magnetForceMin,
CONFIG.magnetForceMax
)
if isMobile
and STATE.mobileMode == "magnet" then
updateMobileMagnetUI()
end
end
local function changeMagnetRadius(amount)
CONFIG.magnetRadius =
math.clamp(
CONFIG.magnetRadius + amount,
CONFIG.magnetRadiusMin,
CONFIG.magnetRadiusMax
)
if isMobile
and STATE.mobileMode == "magnet" then
updateMobileMagnetUI()
end
end
--------------------------------------------------
-- DISTANCIA
--------------------------------------------------
local function updateDistance(delta)
if STATE.rotationMode then
return
end
if STATE.magnetActive then
changeMagnetRadius(delta)
return
end
if not STATE.holding then
return
end
STATE.holdDistance =
math.clamp(
STATE.holdDistance + delta,
CONFIG.holdDistanceMin,
CONFIG.holdDistanceMax
)
end
--------------------------------------------------
-- PC INPUT
--------------------------------------------------
UserInputService.InputBegan:Connect(
function(input, gameProcessed)
if not STATE.active
or gameProcessed then
return
end
if input.UserInputType ==
Enum.UserInputType.Keyboard then
local key =
input.KeyCode
--------------------------------------------------
-- ROTACIÓN
--------------------------------------------------
if STATE.rotationMode then
if key ==
Enum.KeyCode.C then
exitRotationMode()
return
end
if key ==
Enum.KeyCode.W
or key ==
Enum.KeyCode.Up then
STATE.rotationKeys.up = true
return
end
if key ==
Enum.KeyCode.S
or key ==
Enum.KeyCode.Down then
STATE.rotationKeys.down = true
return
end
if key ==
Enum.KeyCode.A
or key ==
Enum.KeyCode.Left then
STATE.rotationKeys.left = true
return
end
if key ==
Enum.KeyCode.D
or key ==
Enum.KeyCode.Right then
STATE.rotationKeys.right = true
return
end
return
end
--------------------------------------------------
-- NORMAL
--------------------------------------------------
if key == Enum.KeyCode.Q then
STATE.holdQ = true
elseif key == Enum.KeyCode.E then
STATE.holdE = true
elseif key == Enum.KeyCode.R then
if STATE.magnetActive then
massAnchorMagnet()
else
toggleAnchored()
end
elseif key == Enum.KeyCode.F then
throwObject()
elseif key == Enum.KeyCode.C then
toggleRotationMode()
elseif key == Enum.KeyCode.T then
toggleMagnet()
elseif key == Enum.KeyCode.Z then
if STATE.magnetActive then
changeMagnetForce(
-CONFIG.magnetForceStep
)
else
changeThrowForce(
-CONFIG.throwForceStepPC
)
end
elseif key == Enum.KeyCode.X then
if STATE.magnetActive then
changeMagnetForce(
CONFIG.magnetForceStep
)
else
changeThrowForce(
CONFIG.throwForceStepPC
)
end
elseif key == Enum.KeyCode.RightControl then
toggleInterface()
elseif key == Enum.KeyCode.LeftControl then
notify(
"⌨️ CONTROLES",
"Click = Agarrar\n"
.. "F = Lanzar\n"
.. "Q/E = Distancia\n"
.. "R = Anclar\n"
.. "T = Imán\n"
.. "C = Rotación\n"
.. "Ctrl derecho = Mostrar/Ocultar",
7
)
elseif key == Enum.KeyCode.LeftAlt
or key == Enum.KeyCode.RightAlt then
notify(
"⌨️ ROTACIÓN",
"W/A/S/D o flechas",
2
)
end
elseif input.UserInputType ==
Enum.UserInputType.MouseButton1 then
grabOrRelease()
end
end
)
--------------------------------------------------
-- PC INPUT END
--------------------------------------------------
UserInputService.InputEnded:Connect(
function(input)
if not STATE.active then
return
end
if input.UserInputType ==
Enum.UserInputType.Keyboard then
local key =
input.KeyCode
if STATE.rotationMode then
if key ==
Enum.KeyCode.W
or key ==
Enum.KeyCode.Up then
STATE.rotationKeys.up = false
elseif key ==
Enum.KeyCode.S
or key ==
Enum.KeyCode.Down then
STATE.rotationKeys.down = false
elseif key ==
Enum.KeyCode.A
or key ==
Enum.KeyCode.Left then
STATE.rotationKeys.left = false
elseif key ==
Enum.KeyCode.D
or key ==
Enum.KeyCode.Right then
STATE.rotationKeys.right = false
end
return
end
if key == Enum.KeyCode.Q then
STATE.holdQ = false
elseif key == Enum.KeyCode.E then
STATE.holdE = false
end
end
end
)
--------------------------------------------------
-- MÓVIL: HELPERS
--------------------------------------------------
local function connectTap(
button,
callback
)
button.Activated:Connect(
function()
if not STATE.active then
return
end
callback()
end
)
end
local function connectHold(
button,
onBegin,
onEnd
)
local activeInput = nil
button.InputBegan:Connect(
function(input)
if not STATE.active then
return
end
if input.UserInputType ==
Enum.UserInputType.Touch
or input.UserInputType ==
Enum.UserInputType.MouseButton1 then
activeInput = input
onBegin()
end
end
)
button.InputEnded:Connect(
function(input)
if input == activeInput then
activeInput = nil
onEnd()
end
end
)
end
--------------------------------------------------
-- MÓVIL: BOTONES
--------------------------------------------------
if isMobile
and UI.buttons then
local b = UI.buttons
--------------------------------------------------
-- AGARRAR
--------------------------------------------------
connectTap(
UI.actionButton,
function()
grabOrRelease()
end
)
--------------------------------------------------
-- LANZAR
--------------------------------------------------
connectTap(
b.throw,
function()
throwObject()
end
)
--------------------------------------------------
-- ANCLAR
--------------------------------------------------
connectTap(
b.anchor,
function()
toggleAnchored()
end
)
--------------------------------------------------
-- DISTANCIA
--------------------------------------------------
connectHold(
b.distanceDown,
function()
STATE.holdClose = true
end,
function()
STATE.holdClose = false
end
)
connectHold(
b.distanceUp,
function()
STATE.holdFar = true
end,
function()
STATE.holdFar = false
end
)
--------------------------------------------------
-- FUERZA
--------------------------------------------------
connectTap(
b.forceDown,
function()
changeThrowForce(
-CONFIG.throwForceStepMobile
)
end
)
connectTap(
b.forceUp,
function()
changeThrowForce(
CONFIG.throwForceStepMobile
)
end
)
--------------------------------------------------
-- IMÁN
--------------------------------------------------
connectTap(
b.magnet,
function()
activateMagnet()
end
)
--------------------------------------------------
-- ROTACIÓN
--------------------------------------------------
connectTap(
b.rotation,
function()
enterRotationMode()
end
)
--------------------------------------------------
-- OJO
--------------------------------------------------
connectTap(
UI.hideButton,
function()
setInterfaceVisible(false)
end
)
--------------------------------------------------
-- IMÁN
--------------------------------------------------
local mb =
UI.magnetButtons
connectTap(
mb.forceDown,
function()
changeMagnetForce(
-CONFIG.magnetForceStep
)
end
)
connectTap(
mb.forceUp,
function()
changeMagnetForce(
CONFIG.magnetForceStep
)
end
)
connectTap(
mb.radiusDown,
function()
changeMagnetRadius(
-CONFIG.magnetRadiusStep
)
end
)
connectTap(
mb.radiusUp,
function()
changeMagnetRadius(
CONFIG.magnetRadiusStep
)
end
)
connectTap(
mb.massAnchor,
function()
massAnchorMagnet()
end
)
connectTap(
mb.exit,
function()
deactivateMagnet()
end
)
--------------------------------------------------
-- ROTACIÓN
--------------------------------------------------
local rb =
UI.rotationButtons
connectHold(
rb.up,
function()
STATE.rotationKeys.up = true
end,
function()
STATE.rotationKeys.up = false
end
)
connectHold(
rb.down,
function()
STATE.rotationKeys.down = true
end,
function()
STATE.rotationKeys.down = false
end
)
connectHold(
rb.left,
function()
STATE.rotationKeys.left = true
end,
function()
STATE.rotationKeys.left = false
end
)
connectHold(
rb.right,
function()
STATE.rotationKeys.right = true
end,
function()
STATE.rotationKeys.right = false
end
)
connectTap(
rb.exit,
function()
exitRotationMode()
end
)
end
--------------------------------------------------
-- BOTÓN DE MOSTRAR MÓVIL
--
-- ES UN SOLO BOTÓN PERSISTENTE
-- ARRIBA A LA IZQUIERDA.
--------------------------------------------------
if isMobile then
local showButton =
Instance.new("TextButton")
showButton.Name =
"ShowInterface"
showButton.Size =
UDim2.fromOffset(55, 55)
showButton.Position =
UDim2.fromOffset(15, 15)
showButton.BackgroundColor3 =
Color3.fromRGB(35, 35, 35)
showButton.BackgroundTransparency =
0.2
showButton.Text =
"👁️"
showButton.TextScaled =
true
showButton.Font =
Enum.Font.GothamBold
showButton.TextColor3 =
Color3.new(1, 1, 1)
showButton.Visible =
false
showButton.ZIndex =
200
styleButton(showButton)
showButton.Parent =
UI.mobileGui
UI.showButton =
showButton
showButton.Activated:Connect(
function()
setInterfaceVisible(true)
showButton.Visible =
false
if STATE.mobileMode ==
"magnet"
and STATE.magnetActive then
updateMobileMagnetUI()
elseif STATE.mobileMode ==
"rotation"
and STATE.rotationMode then
updateMobileRotationUI()
else
updateMobileNormalUI()
end
end
)
--------------------------------------------------
-- SOBREESCRIBIR OCULTAR:
-- Mostrar botón arriba izquierda.
--------------------------------------------------
UI.hideButton.Activated:Connect(
function()
setInterfaceVisible(false)
showButton.Visible =
true
end
)
end
--------------------------------------------------
-- CURSOR MÓVIL
--------------------------------------------------
if isMobile
and UI.fakePointer then
UI.fakePointer.InputBegan:Connect(
function(input)
if input.UserInputType
~= Enum.UserInputType.Touch then
return
end
STATE.pointerTouch =
input
STATE.pointerTouchStart =
input.Position
STATE.pointerDragStarted =
false
end
)
UserInputService.InputChanged:Connect(
function(input)
if input.UserInputType
~= Enum.UserInputType.Touch then
return
end
if input ~=
STATE.pointerTouch then
return
end
if not STATE.pointerTouchStart then
return
end
local delta =
input.Position
- STATE.pointerTouchStart
if not STATE.pointerDragStarted then
if delta.Magnitude
< CONFIG.pointerDragThreshold then
return
end
STATE.pointerDragStarted =
true
end
UI.fakePointer.Position =
UDim2.fromOffset(
input.Position.X,
input.Position.Y
)
end
)
UserInputService.InputEnded:Connect(
function(input)
if input ~=
STATE.pointerTouch then
return
end
STATE.pointerTouch = nil
STATE.pointerTouchStart = nil
STATE.pointerDragStarted = false
end
)
UserInputService.TouchEnded:Connect(
function(input)
if input ~=
STATE.pointerTouch then
return
end
STATE.pointerTouch = nil
STATE.pointerTouchStart = nil
STATE.pointerDragStarted = false
end
)
end
--------------------------------------------------
-- RENDER
--------------------------------------------------
RunService.RenderStepped:Connect(
function()
if not STATE.active then
return
end
--------------------------------------------------
-- ROTACIÓN
--------------------------------------------------
updateRotation()
--------------------------------------------------
-- HIGHLIGHTS
--------------------------------------------------
refreshHighlights()
--------------------------------------------------
-- IMÁN VISUAL
--------------------------------------------------
if STATE.magnetActive
and not STATE.rotationMode
and STATE.guiVisible then
local hit, position =
raycastForMagnet()
if hit and position then
surfacePosition =
surfacePosition:Lerp(
position,
0.35
)
else
local ray =
getAimRay()
surfacePosition =
surfacePosition:Lerp(
ray.Origin
+ ray.Direction * 15,
0.15
)
end
actualMagnetRadius +=
(
CONFIG.magnetRadius
- actualMagnetRadius
) * 0.25
local percent =
(
CONFIG.magnetForce
- CONFIG.magnetForceMin
)
/
(
CONFIG.magnetForceMax
- CONFIG.magnetForceMin
)
local colorScale =
Color3.fromHSV(
0.58
+ percent * 0.3,
1,
1
)
if usingDrawing
and magnetCircle then
local viewport =
camera:WorldToViewportPoint(
surfacePosition
)
magnetCircle.Visible =
true
magnetCircle.Position =
Vector2.new(
viewport.X,
viewport.Y
)
magnetCircle.Radius =
actualMagnetRadius
magnetCircle.Color =
colorScale
elseif circleGui then
circleGui.Enabled =
true
circleGui.Size =
UDim2.fromOffset(
actualMagnetRadius * 2,
actualMagnetRadius * 2
)
circleGui.Position =
surfacePosition
circleImage.ImageColor3 =
colorScale
end
if UI.forceLabel
and STATE.guiVisible
and not isMobile then
UI.forceLabel.Visible =
true
UI.forceLabel.Text =
"🧲 Fuerza: "
.. math.floor(
CONFIG.magnetForce
)
.. "\n📏 Radio: "
.. math.floor(
CONFIG.magnetRadius
)
end
elseif not STATE.rotationMode
and STATE.guiVisible then
if usingDrawing
and magnetCircle then
magnetCircle.Visible = false
elseif circleGui then
circleGui.Enabled = false
end
if UI.forceLabel
and not isMobile then
UI.forceLabel.Visible =
true
UI.forceLabel.Text =
"🎯 Lanzamiento: "
.. math.floor(
CONFIG.throwForce
)
end
else
if usingDrawing
and magnetCircle then
magnetCircle.Visible = false
elseif circleGui then
circleGui.Enabled = false
end
if UI.forceLabel then
UI.forceLabel.Visible =
false
end
end
--------------------------------------------------
-- DISTANCIA
--------------------------------------------------
if STATE.holding
and not STATE.rotationMode
and not STATE.magnetActive then
if STATE.holdClose then
updateDistance(
-CONFIG.distanceSpeed
)
end
if STATE.holdFar then
updateDistance(
CONFIG.distanceSpeed
)
end
end
end
)
--------------------------------------------------
-- HEARTBEAT
--------------------------------------------------
RunService.Heartbeat:Connect(
function()
if not STATE.active then
return
end
--------------------------------------------------
-- OBJETO
--------------------------------------------------
if STATE.holding
and STATE.target then
local target =
STATE.target
if STATE.rotationMode then
target.AssemblyLinearVelocity =
Vector3.zero
target.AssemblyAngularVelocity =
Vector3.zero
if STATE.rotationPosition then
rotationPositionLock.Position =
STATE.rotationPosition
end
elseif not STATE.anchoredWhileHolding then
local ray =
getAimRay()
local desiredPosition =
ray.Origin
+ ray.Direction.Unit
* STATE.holdDistance
bodyVelocity.Velocity =
(
desiredPosition
- target.Position
) * 5
bodyGyro.CFrame =
target.CFrame
else
target.AssemblyLinearVelocity =
Vector3.zero
target.AssemblyAngularVelocity =
Vector3.zero
end
end
--------------------------------------------------
-- IMÁN
--------------------------------------------------
if STATE.magnetActive
and not STATE.rotationMode then
local center =
surfacePosition
local newObjects = {}
local scaledForce =
CONFIG.magnetForce
* (
CONFIG.magnetRadius / 30
) ^ 1.5
local diameter =
CONFIG.magnetRadius * 2
local nearby =
workspace:GetPartBoundsInBox(
CFrame.new(center),
Vector3.new(
diameter,
diameter,
diameter
)
)
for _, object in ipairs(
nearby
) do
if object:IsA("BasePart")
and not object.Anchored
and not isPlayerPart(object)
and not hasUnanchoredWeld(object)
and object.Transparency < 1
and object.CanCollide
and object ~= STATE.target then
local offset =
center - object.Position
local distance =
offset.Magnitude
if distance
<= CONFIG.magnetRadius
and distance > 0.01 then
local velocity =
object:FindFirstChild(
"ImanBV"
)
if not velocity then
velocity =
Instance.new(
"BodyVelocity"
)
velocity.Name =
"ImanBV"
velocity.MaxForce =
Vector3.new(
1,
1,
1
) * 1e5
velocity.P =
15000
velocity.Parent =
object
end
velocity.Velocity =
offset.Unit
* scaledForce
newObjects[object] =
true
end
end
end
for object in pairs(
STATE.magnetObjects
) do
if not newObjects[object] then
local bv =
object
and object:FindFirstChild(
"ImanBV"
)
if bv then
bv:Destroy()
end
end
end
STATE.magnetObjects =
newObjects
else
restoreMagnetPhysics()
end
--------------------------------------------------
-- Q / E PC
--------------------------------------------------
if not STATE.rotationMode then
if STATE.magnetActive then
if STATE.holdQ then
changeMagnetRadius(
-CONFIG.magnetRadiusStep
)
end
if STATE.holdE then
changeMagnetRadius(
CONFIG.magnetRadiusStep
)
end
else
if STATE.holdQ then
updateDistance(
-CONFIG.distanceKeySpeed
)
end
if STATE.holdE then
updateDistance(
CONFIG.distanceKeySpeed
)
end
end
end
end
)
--------------------------------------------------
-- RESPAWN
--------------------------------------------------
player.CharacterAdded:Connect(
function()
STATE.characterFrozen = false
STATE.characterBackup = nil
STATE.characterVisibilityBackup = {}
if STATE.rotationMode then
STATE.rotationMode = false
resetRotationKeys()
rotationPositionLock.Parent = nil
end
end
)
--------------------------------------------------
-- INICIO
--------------------------------------------------
if isMobile then
updateMobileNormalUI()
UI.showButton.Visible = false
else
if UI.forceLabel then
UI.forceLabel.Visible = true
end
end
print(
"[Telekinesis V4.4] "
.. "UI toggle corregido + "
.. "Ctrl derecho + "
.. "layouts de modos ajustados"
)



bom