El wall running, los deslizamientos y las trepadas definen los mejores juegos de acción. Intentar implementarlos con el Humanoid por defecto provoca colisiones toscas y caídas indeseadas.
Combinando las restricciones de Luau (`LinearVelocity` y `VectorForce`) con el trazado de rayos (Raycast), puedes crear un sistema de plataformas ágil y robusto en móviles, PC y consolas.
1. Sobrescribir Estados del Humanoid para Parkour Fluido
Diseño de la máquina de estados de movimiento:
- Desactivar Estados en Conflicto: Al iniciar el wall run, llama a
Humanoid:SetStateEnabled(Enum.HumanoidStateType.Climbing, false)para evitar que la caída libre interfiera. - Propiedad de Red: Asigna la propiedad de red del RootPart al jugador en el servidor para evitar latencia de entrada.
- Modularidad: Estructura el movimiento en una máquina de estados finitos (Caminar, Correr, WallRun, Colgado, Salto).
2. Trazado de Rayos y Alineación con la Normal
Detección de superficies y cálculo de trayectorias:
- Sondas Horizontales: Dispara rayos desde la cadera y hombros hacia los lados (3.5 studs) para detectar muros.
- Ángulo de la Normal: Comprueba que el muro sea vertical (75° a 105° respecto a la vertical) para descartar rampas.
- Producto Vectorial: Calcula la dirección de avance mediante
wallNormal:Cross(Vector3.yAxis).
3. Restricciones Físicas: LinearVelocity y VectorForce
Sustituyendo los antiguos BodyMovers por restricciones modernas:
- LinearVelocity para Velocidad Constante: Mantiene la velocidad requerida venciendo la fricción lateral.
- VectorForce Antigravedad: Aplica una fuerza ascendente que compense los 196.2 studs/s² de la gravedad estándar.
- Decaimiento Gradual: Reduce la fuerza vertical tras 1.5–2 segundos para provocar una caída parabólica natural.
-- Controlador de Wall Running en el cliente
local RunService = game:GetService("RunService")
local WallRun = {}
WallRun.__index = WallRun
function WallRun.new(character)
local self = setmetatable({}, WallRun)
self.Char = character
self.RootPart = character:WaitForChild("HumanoidRootPart")
self.Humanoid = character:WaitForChild("Humanoid")
local att = Instance.new("Attachment", self.RootPart)
local lv = Instance.new("LinearVelocity")
lv.Attachment0 = att
lv.MaxForce = 15000
lv.RelativeTo = Enum.ActuatorRelativeTo.World
lv.Enabled = false
lv.Parent = self.RootPart
self.Attachment = att
self.LinearVelocity = lv
self.IsRunning = false
return self
end
function WallRun:CheckWall(side)
local rightVec = self.RootPart.CFrame.RightVector
local rayDir = (side == "Left" and -rightVec or rightVec) * 3.5
local params = RaycastParams.new()
params.FilterDescendantsInstances = {self.Char}
params.FilterType = Enum.RaycastFilterType.Exclude
return workspace:Raycast(self.RootPart.Position, rayDir, params)
end
function WallRun:Start(hitNormal, forwardDir)
self.IsRunning = true
self.LinearVelocity.VectorVelocity = forwardDir * 32 + Vector3.new(0, 4, 0)
self.LinearVelocity.Enabled = true
self.Humanoid:ChangeState(Enum.HumanoidStateType.Physics)
end
function WallRun:Stop()
self.IsRunning = false
self.LinearVelocity.Enabled = false
self.Humanoid:ChangeState(Enum.HumanoidStateType.Freefall)
end
return WallRun
4. Agarre de Bordes y Transición de Subida (Mantle)
Detección de cornisas y animación de escalada:
- Doble Raycast: Un rayo frontal al pecho detecta la pared y otro vertical descendente ubica el filo superior.
- Alineación Suave: Usa
AlignPositionpara clavar al personaje en el borde al descolgarse. - Curva Bézier: Al pulsar salto, interpola la posición del RootPart en un arco suave sobre la superficie.
5. Controles Táctiles y Validación en Servidor
Accesibilidad móvil y seguridad contra exploits:
- Botones Táctiles Amplios: Enlaza saltos y trepadas a botones en pantalla de al menos 48x48 píxeles.
- Límites de Velocidad: El servidor comprueba la velocidad entre fotogramas y bloquea desplazamientos anómalos.
- Comprobación de Muros: El servidor lanza rayos para verificar que existía un muro real junto al jugador.
Frequently Asked Questions
¿Por qué usar LinearVelocity en lugar de BodyVelocity?
BodyVelocity está obsoleto. LinearVelocity forma parte del motor de restricciones moderno, es más estable y respeta la masa del avatar.
¿Cómo evitar que el avatar se resbale por la pared?
Aplicando una fuerza vertical compensatoria con VectorForce que anule la gravedad del juego durante unos segundos.
¿Cómo se calcula el vector de avance junto a la pared?
Haciendo el producto vectorial entre la normal de la pared devuelta por el raycast y el vector vertical (0, 1, 0).
¿Cómo se evitan trampas de velocidad en el servidor?
Comprobando en el servidor que haya paredes reales cerca y verificando que la velocidad no sobrepase los límites establecidos.