local PushSystem = {}
-- Services
local TweenService = game:GetService("TweenService")
local Debris = game:GetService("Debris")
local RunService = game:GetService("RunService")
-- Active pushes tracking
local activePushes = {}
-- Force Types
PushSystem.FORCE_TYPES = {
VECTOR_FORCE = "VectorForce", -- Força direcional realística
ALIGN_POSITION = "AlignPosition", -- Movimento preciso
BODY_VELOCITY = "BodyVelocity", -- Velocidade (legacy mas funcional)
IMPULSE = "Impulse", -- Impulso instantâneo
ASSEMBLY_VELOCITY = "AssemblyVelocity" -- Velocidade moderna
}
-- Push Styles
[Link] = {
LINEAR = "Linear", -- Push reto
ARC = "Arc", -- Push com arco
SPIRAL = "Spiral" -- Push em espiral
}
-- Default config
local DEFAULT_CONFIG = {
forceType = PushSystem.FORCE_TYPES.VECTOR_FORCE,
style = [Link],
-- Force settings
force = 50000, -- Força em Newtons
duration = 2, -- Duração
maxForce = [Link], -- Força máxima
-- Physics
applyAtCenterOfMass = true,
relativeSpace = [Link],
-- AlignPosition specific
responsiveness = 50,
maxVelocity = 100,
-- Arc settings
arcHeight = 0,
-- Spiral settings
spiralRadius = 8,
spiralSpeed = 2,
-- Raycast detection
useRaycast = true,
raycastDistance = 200,
raycastParams = nil, -- Will be set automatically
-- Optional settings
targetPosition = nil, -- Posição específica
direction = nil, -- Direção específica
-- Callbacks
onStart = nil, -- function(character, startPos, targetPos)
onHit = nil, -- function(pushedChar, hitResult) -- hitResult
from raycast
onComplete = nil -- function(character, finalPos)
}
-- Função para criar raycast params
local function createRaycastParams(character)
local params = [Link]()
[Link] = [Link]
[Link] = {character}
return params
end
-- Função para calcular massa do character
local function getCharacterMass(character)
local mass = 0
for _, part in pairs(character:GetChildren()) do
if part:IsA("BasePart") then
mass = mass + [Link]
end
end
return mass
end
-- Função para criar VectorForce
local function createVectorForce(character, direction, config)
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then return nil end
local attachment = [Link]("Attachment")
[Link] = "PushForceAttachment"
[Link] = humanoidRootPart
local vectorForce = [Link]("VectorForce")
vectorForce.Attachment0 = attachment
[Link] = direction * [Link]
[Link] = [Link]
[Link] = [Link]
[Link] = humanoidRootPart
return {
force = vectorForce,
attachment = attachment,
type = "VectorForce"
}
end
-- Função para criar AlignPosition
local function createAlignPosition(character, targetPos, config)
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then return nil end
local attachment0 = [Link]("Attachment")
[Link] = "PushAlignAttachment0"
[Link] = humanoidRootPart
local attachment1 = [Link]("Attachment")
[Link] = "PushAlignAttachment1"
[Link] = targetPos
[Link] = [Link]
local alignPosition = [Link]("AlignPosition")
alignPosition.Attachment0 = attachment0
alignPosition.Attachment1 = attachment1
[Link] = [Link]
[Link] = [Link]
[Link] = [Link]
[Link] = humanoidRootPart
return {
align = alignPosition,
attachment0 = attachment0,
attachment1 = attachment1,
type = "AlignPosition"
}
end
-- Função para criar BodyVelocity
local function createBodyVelocity(character, velocity, config)
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then return nil end
local bodyVelocity = [Link]("BodyVelocity")
[Link] = velocity
[Link] = [Link]([Link], [Link],
[Link])
[Link] = humanoidRootPart
return {
velocity = bodyVelocity,
type = "BodyVelocity"
}
end
-- Função para criar movimento em arco
local function createArcMovement(character, targetPos, config)
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then return nil end
local startPos = [Link]
local direction = (targetPos - startPos).Unit
local distance = (targetPos - startPos).Magnitude
-- Calcular velocidade para arco
local gravity = [Link]
local time = [Link]
local deltaY = targetPos.Y - startPos.Y + [Link]
local velocityY = (deltaY + 0.5 * gravity * time^2) / time
local horizontalDistance = [Link](targetPos.X - startPos.X, 0,
targetPos.Z - startPos.Z).Magnitude
local velocityXZ = horizontalDistance / time
local initialVelocity = [Link](
direction.X * velocityXZ,
velocityY,
direction.Z * velocityXZ
)
return createBodyVelocity(character, initialVelocity, config)
end
-- Função para criar movimento espiral
local function createSpiralMovement(character, direction, config)
local forceObject = createVectorForce(character, direction, config)
if not forceObject then return nil end
local connection
local elapsed = 0
connection = [Link]:Connect(function(dt)
elapsed = elapsed + dt
local progress = elapsed / [Link]
if progress >= 1 then
connection:Disconnect()
return
end
local angle = elapsed * [Link] * [Link] * 2
local spiralOffset = [Link](
[Link](angle) * [Link],
0,
[Link](angle) * [Link]
)
local newDirection = (direction + spiralOffset).Unit
[Link] = newDirection * [Link] * (1 - progress *
0.3)
end)
[Link] = connection
return forceObject
end
-- Função para setup raycast detection
local function setupRaycastDetection(character, config)
if not [Link] then return end
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then return end
local raycastParams = [Link] or createRaycastParams(character)
local lastPosition = [Link]
local connection
connection = [Link]:Connect(function()
if not [Link] then
connection:Disconnect()
return
end
local currentPosition = [Link]
local direction = (currentPosition - lastPosition)
if [Link] > 0.1 then
local rayResult = workspace:Raycast(lastPosition, [Link]
* [Link], raycastParams)
if rayResult then
local hitPart = [Link]
local hitCharacter = [Link]
-- Check se atingiu um character
if hitCharacter:FindFirstChild("Humanoid") and hitCharacter
~= character then
if [Link] then
[Link](character, rayResult)
end
end
end
end
lastPosition = currentPosition
end)
-- Cleanup automático
[Link](function()
[Link]([Link] + 1)
if connection then
connection:Disconnect()
end
end)
return connection
end
-- Função principal
function [Link](args)
--[[
args = {
Character = character, -- Character a ser empurrado
Caster = casterCharacter, -- Quem fez o push (opcional)
Direction = vector3, -- Direção (opcional)
Config = {
forceType = FORCE_TYPES.VECTOR_FORCE,
force = 50000,
duration = 2,
onStart = function(char, startPos, targetPos) end,
onHit = function(pushedChar, rayResult) end,
onComplete = function(char, finalPos) end
}
}
--]]
local character = [Link]
local caster = [Link]
local direction = [Link]
local config = [Link] or {}
-- Merge com config padrão
for key, value in pairs(DEFAULT_CONFIG) do
if config[key] == nil then
config[key] = value
end
end
-- Validações
if not character or not character:FindFirstChild("HumanoidRootPart") then
warn("PushSystem: Character inválido")
return false
end
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
local startPos = [Link]
-- Calcular direção se não fornecida
if not direction then
if caster and caster:FindFirstChild("HumanoidRootPart") then
direction = (startPos - [Link]).Unit
else
direction = [Link]
end
end
-- Calcular posição alvo
local targetPos = [Link]
if not targetPos then
local distance = [Link] / 2000 -- Conversão aproximada
targetPos = startPos + (direction * distance)
end
-- Registrar push ativo
local pushId = [Link] .. "_" .. tick()
local executionState = {
character = character,
config = config,
startTime = tick(),
forceObjects = {},
connections = {}
}
activePushes[pushId] = executionState
-- Callback onStart
if [Link] then
[Link](character, startPos, targetPos)
end
-- Setup raycast detection
local raycastConnection = setupRaycastDetection(character, config)
if raycastConnection then
[Link][#[Link] + 1] =
raycastConnection
end
-- Criar força baseada no tipo e estilo
local forceObject
if [Link] == [Link] then
forceObject = createArcMovement(character, targetPos, config)
elseif [Link] == [Link] then
forceObject = createSpiralMovement(character, direction, config)
else
-- Linear push
if [Link] == PushSystem.FORCE_TYPES.VECTOR_FORCE then
forceObject = createVectorForce(character, direction, config)
elseif [Link] == PushSystem.FORCE_TYPES.ALIGN_POSITION then
forceObject = createAlignPosition(character, targetPos, config)
elseif [Link] == PushSystem.FORCE_TYPES.BODY_VELOCITY then
local velocity = direction * ([Link] / 1000)
forceObject = createBodyVelocity(character, velocity, config)
elseif [Link] == PushSystem.FORCE_TYPES.IMPULSE then
humanoidRootPart:ApplyImpulse(direction * [Link] *
getCharacterMass(character))
forceObject = {type = "Impulse", applied = true}
elseif [Link] == PushSystem.FORCE_TYPES.ASSEMBLY_VELOCITY
then
[Link] = direction * ([Link] / 1000)
forceObject = {type = "AssemblyVelocity", applied = true}
end
end
if not forceObject then
warn("PushSystem: Falha ao criar força")
activePushes[pushId] = nil
return false
end
[Link][#[Link] + 1] = forceObject
-- Cleanup automático
[Link](function()
[Link]([Link])
[Link](character)
if [Link] then
[Link](character, [Link])
end
end)
return true, pushId
end
-- Função para parar push
function [Link](character)
for pushId, pushData in pairs(activePushes) do
if [Link] == character then
-- Limpar forças
for _, forceObject in pairs([Link]) do
if [Link] == "VectorForce" then
if [Link] then [Link]:Destroy()
end
if [Link] then
[Link]:Destroy() end
if [Link] then
[Link]:Disconnect() end
elseif [Link] == "AlignPosition" then
if [Link] then [Link]:Destroy()
end
if forceObject.attachment0 then
forceObject.attachment0:Destroy() end
if forceObject.attachment1 then
forceObject.attachment1:Destroy() end
elseif [Link] == "BodyVelocity" then
if [Link] then
[Link]:Destroy() end
end
end
-- Limpar connections
for _, connection in pairs([Link]) do
if connection then
connection:Disconnect()
end
end
activePushes[pushId] = nil
return true
end
end
return false
end
-- Quick push function
function [Link](character, caster, force, forceType)
return [Link]({
Character = character,
Caster = caster,
Config = {
forceType = forceType or PushSystem.FORCE_TYPES.VECTOR_FORCE,
force = force or 50000,
duration = 1.5
}
})
end
-- Presets simples
[Link] = {
STRONG = {
forceType = PushSystem.FORCE_TYPES.VECTOR_FORCE,
force = 75000,
duration = 1.5
},
PRECISE = {
forceType = PushSystem.FORCE_TYPES.ALIGN_POSITION,
responsiveness = 80,
duration = 2
},
INSTANT = {
forceType = PushSystem.FORCE_TYPES.IMPULSE,
force = 100000,
duration = 0.1
},
ARC = {
forceType = PushSystem.FORCE_TYPES.BODY_VELOCITY,
style = [Link],
force = 60000,
arcHeight = 30,
duration = 2.5
},
SPIRAL = {
forceType = PushSystem.FORCE_TYPES.VECTOR_FORCE,
style = [Link],
force = 50000,
spiralRadius = 10,
duration = 3
}
}
return PushSystem
--[[
=== USO BÁSICO ===
local PushSystem = require([Link])
-- 1. Push simples
[Link](target, caster, 60000)
-- 2. Push com config
[Link]({
Character = target,
Caster = caster,
Config = {
forceType = PushSystem.FORCE_TYPES.VECTOR_FORCE,
force = 80000,
duration = 2,
onStart = function(char, startPos, targetPos)
print("Push iniciado!")
end,
onHit = function(pushedChar, rayResult)
print("Atingiu:", [Link])
end,
onComplete = function(char, finalPos)
print("Push completo!")
end
}
})
-- 3. Usando presets
[Link]({
Character = target,
Caster = caster,
Config = [Link]
})
-- 4. Push para posição específica
[Link]({
Character = target,
Config = {
forceType = PushSystem.FORCE_TYPES.ALIGN_POSITION,
targetPosition = [Link](100, 5, 100),
duration = 3
}
})
--]]