Una colisión ocurre cuando dos objetos 3D entran en contacto dentro del mundo 3D. Para un manejo de colisiones personalizado, BasePart tiene un conjunto de eventos de colisión y técnicas de filtrado de colisión, para que puedas controlar qué ensamblajes físicos colisionan con otros.
Eventos de colisión
Los eventos de colisión ocurren cuando dos BaseParts tocan o dejan de tocarse en el mundo 3D. Puedes detectar estas colisiones a través de los eventos Touched y TouchEnded, que ocurren independientemente del valor de la propiedad CanCollide de cualquiera de las partes. Al considerar el manejo de colisiones en partes, ten en cuenta lo siguiente:
- La propiedad CanTouch de una parte determina si activa eventos de colisión. Si se establece en false, ni Touched ni TouchEnded se activarán.
- La propiedad CanCollide de una parte afecta si colisionará físicamente con otras partes y causará fuerzas que actúen sobre ellas. Incluso si CanCollide está deshabilitado para una parte, puedes detectar el toque y la no‑interacción a través de los eventos Touched y TouchEnded.
- Los eventos Touched y TouchEnded solo se activan como resultado de un movimiento físico, no de cambios en Position o CFrame que causen que una parte interseccione o deje de interseccionar otra parte.
Tocado
El evento Touched se activa cuando un BasePart entra en contacto con otro, o con un vóxel de Terrain. Solo se activa como resultado de una simulación física y no se activará cuando la Position o CFrame de la parte se establezca explícitamente de tal manera que interseccione con otra parte o vóxel.
El siguiente patrón de código muestra cómo el evento Touched puede conectarse a una función personalizada onTouched(). Ten en cuenta que el evento envía el argumento otherPart a la función, indicando la otra parte involucrada en la colisión.
local part = workspace.Part
local function onTouched(otherPart)
print(part.Name .. " colisionó con " .. otherPart.Name)
end
part.Touched:Connect(onTouched)Ten en cuenta que el evento Touched puede activarse múltiples veces en rápida sucesión debido a colisiones físicas sutiles, como cuando un objeto en movimiento "se asienta" en una posición de reposo o cuando una colisión involucra un modelo de múltiples partes. Para evitar activar más eventos Touched de los necesarios, puedes implementar un sistema de debounce simple que imponga un período de "enfriamiento" a través de un atributo de instancia.
local part = workspace.Part
local COOLDOWN_TIME = 1
local function onTouched(otherPart)
if not part:GetAttribute("Touched") then
print(part.Name .. " colisionó con " .. otherPart.Name)
part:SetAttribute("Touched", true) -- Establecer atributo en verdadero
task.wait(COOLDOWN_TIME) -- Esperar la duración del enfriamiento
part:SetAttribute("Touched", false) -- Reiniciar atributo
end
end
part.Touched:Connect(onTouched)TouchEnded
El evento TouchEnded se activa cuando los límites de colisión completos de un BasePart salen de los límites de otro BasePart o de un vóxel de Terrain lleno. Solo se activa como resultado de una simulación física y no se activará cuando la Position o CFrame de la parte se establezca explícitamente de tal manera que deje de interseccionar con otra parte o vóxel.
El siguiente patrón de código muestra cómo el evento TouchEnded puede conectarse a una función personalizada onTouchEnded(). Al igual que Touched, el evento envía el argumento otherPart a la función, indicando la otra parte involucrada.
local part = workspace.Part
local function onTouchEnded(otherPart)
print(part.Name .. " ya no está tocando " .. otherPart.Name)
end
part.TouchEnded:Connect(onTouchEnded)Filtrado de colisiones
El filtrado de colisiones define qué partes físicas colisionan con otras. Puedes configurar el filtrado para numerosos objetos a través de grupos de colisión o puedes controlar las colisiones en una base parte a parte con instancias de NoCollisionConstraint.
Grupos de colisión
Los grupos de colisión te permiten asignar BaseParts a grupos dedicados y especificar si colisionan o no con aquellos en otros grupos. Las partes dentro de grupos no colisionantes pasan completamente a través de cada una, incluso si ambas partes tienen su propiedad CanCollide establecida en true. Los grupos de colisión se crean y configuran en base a Workspace o WorldModel.
Puedes configurar fácilmente grupos de colisión a través del editor de Grupos de Colisión de Studio, accesible a través del menú Ventana ⟩ 3D de Studio.
Registrar grupos
Workspace almacena su propio estado configurable de grupos de colisión. Además, cualquier WorldModel puede optar por usar sus propios grupos de colisión para consultas.
El editor incluye un grupo de colisión Predeterminado que no se puede renombrar ni eliminar. Todos los BaseParts pertenecen automáticamente a este grupo predeterminado a menos que se les asigne a otro grupo, lo que significa que colisionarán con todos los demás objetos en el grupo Predeterminado.
Para crear un nuevo grupo de colisión:
Por defecto, los grupos se registran en Workspace, pero si tienes al menos un WorldModel en tu lugar, aparecerá un menú desplegable de selección en la parte superior del editor de grupos de colisión. Usa el menú desplegable para configurar grupos de colisión a través de diferentes instancias de WorldModel.

Para cualquier WorldModel, puedes activar Usar grupos de colisión de Workspace para hacer que use los grupos de colisión de Workspace para sus consultas.

Haz clic en el botón Agregar Grupo en la parte superior del panel del editor, ingresa un nuevo nombre de grupo y presiona Enter. El nuevo grupo aparece en ambas columnas de la vista de lista, o en la columna izquierda y la fila superior de la vista de tabla.

Repite el proceso si es necesario, eligiendo un nombre único y descriptivo para cada grupo. Ten en cuenta que puedes cambiar el nombre de un grupo durante el desarrollo haciendo clic en su campo, o seleccionándolo y haciendo clic en el botón renombrar.

Configurar colisiones de grupos
Bajo la configuración predeterminada, los objetos en todos los grupos colisionan entre sí. Para evitar que los objetos en un grupo colisionen con objetos en otro grupo, desmarca la casilla en la fila/columna respectiva.
En el siguiente ejemplo, los objetos en el grupo Cubes no colisionarán con objetos en el grupo Doors.

Asignar objetos a grupos
Para asignar objetos a grupos que has registrado a través del editor de Studio:
Selecciona uno o más BaseParts que califiquen como parte de un grupo de colisión.
Asígnalos al grupo haciendo clic en el botón ⊕ para su fila. Los objetos solo pueden pertenecer a un grupo de colisión a la vez, por lo que colocarlos en un nuevo grupo los elimina de su grupo actual.

Una vez asignado, el nuevo grupo se refleja en la propiedad CollisionGroup del objeto.

Grupo StudioSelectable
Las herramientas en Studio utilizan el sistema de filtrado de colisiones para determinar qué objetos son candidatos para la selección al hacer clic en el viewport 3D. Los objetos cuyo grupo de colisión asignado no colisiona con StudioSelectable serán ignorados.
Por ejemplo, si tienes puntos de control en un juego de carreras cuyos áreas efectivas están definidas por grandes partes transparentes, puedes asignarlos a un grupo de colisión Checkpoints y luego hacer que ese grupo no sea colisionable con StudioSelectable para que no interfieran cuando estés editando la geometría del mapa subyacente.

Para el código de plugins, se recomienda que asignes "StudioSelectable" como el filtro de grupo de colisión de tus RaycastParams al encontrar partes bajo el cursor. Esto permite que tus plugins coincidan con la mecánica de selección que los creadores han aprendido a esperar de las herramientas integradas de Studio.
local UserInputService = game:GetService("UserInputService")
local raycastParams = RaycastParams.new()
raycastParams.CollisionGroup = "StudioSelectable" -- Para seguir la convención
raycastParams.BruteForceAllSlow = true -- Para que las partes con CanQuery de "false" puedan ser seleccionadas
local mouseLocation = UserInputService:GetMouseLocation()
local mouseRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
local filteredSelectionHit = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 10000, raycastParams)Filtrado de parte a parte
Para evitar colisiones entre dos partes específicas sin configurar grupos de colisión, como entre la rueda de un vehículo y su chasis, considera la No Collision constraint. Las ventajas incluyen:
- No se requieren grupos de colisión y/o scripts de configuración, por lo que puedes crear y compartir modelos fácilmente con filtrado de colisión personalizado.
- Las partes conectadas no colisionarán entre sí, pero aún pueden colisionar con otros objetos.
Deshabilitar colisiones de personajes
Los personajes de los jugadores de Roblox colisionan entre sí por defecto. Esto puede llevar a jugabilidad interesante pero no intencionada, como personajes saltando unos sobre otros para alcanzar áreas específicas. Si este comportamiento es indeseable, puedes prevenirlo a través del siguiente Script en ServerScriptService.
local Players = game:GetService("Players")
workspace:RegisterCollisionGroup("Characters")
workspace:CollisionGroupSetCollidable("Characters", "Characters", false)
local function onDescendantAdded(descendant)
-- Establecer grupo de colisión para cualquier parte descendiente
if descendant:IsA("BasePart") then
descendant.CollisionGroup = "Characters"
end
end
local function onCharacterAdded(character)
-- Procesar descendientes existentes y nuevos para la configuración de física
for _, descendant in character:GetDescendants() do
onDescendantAdded(descendant)
end
character.DescendantAdded:Connect(onDescendantAdded)
end
Players.PlayerAdded:Connect(function(player)
-- Detectar cuando se agrega el personaje del jugador
player.CharacterAdded:Connect(onCharacterAdded)
end)Colisiones de modelos
Los objetos Model son contenedores para partes en lugar de heredar de BasePart, por lo que no pueden conectarse directamente a los eventos BasePart.Touched o BasePart.TouchEnded. Para determinar si un modelo activa eventos de colisión, necesitas recorrer sus hijos y conectar las funciones personalizadas onTouched() y onTouchEnded() a cada BasePart hijo.
El siguiente ejemplo de código conecta todas las BaseParts de un modelo de múltiples partes a eventos de colisión y rastrea el número total de colisiones con otras partes.
local model = script.Parent
local numTouchingParts = 0
local function onTouched(otherPart)
-- Ignorar instancias del modelo que intersecan consigo mismas
if otherPart:IsDescendantOf(model) then return end
-- Aumentar el conteo de partes del modelo tocando
numTouchingParts += 1
print(model.Name, "intersectó con", otherPart.Name, "| Partes del modelo tocando:", numTouchingParts)
end
local function onTouchEnded(otherPart)
-- Ignorar instancias del modelo que dejan de intersecarse consigo mismas
if otherPart:IsDescendantOf(model) then return end
-- Disminuir el conteo de partes del modelo tocando
numTouchingParts -= 1
print(model.Name, "dejó de intersectar con", otherPart.Name, "| Partes del modelo tocando:", numTouchingParts)
end
for _, child in model:GetChildren() do
if child:IsA("BasePart") then
child.Touched:Connect(onTouched)
child.TouchEnded:Connect(onTouchEnded)
end
endColisiones de mallas y modelos sólidos
MeshPart y PartOperation (partes unidas por modelado sólido) son subclases de BasePart, por lo que las mallas y las partes modeladas sólidamente heredan los mismos eventos de colisión y opciones de filtrado de colisión que las partes regulares. Sin embargo, dado que las mallas y las partes modeladas sólidamente suelen tener geometrías más complejas, tienen una propiedad distintiva CollisionFidelity que determina cuán precisamente los límites físicos se alinean con la representación visual para el manejo de colisiones.
La propiedad CollisionFidelity tiene las siguientes opciones, en orden de fidelidad e impacto en el rendimiento de menor a mayor:
- Caja — Crea una caja de colisión delimitadora, ideal para objetos pequeños o no interactivos.
- Casco — Genera un casco convexo, adecuado para objetos con indentaciones o cavidades menos pronunciadas.
- Predeterminado — Produce una forma de colisión aproximada que admite concavidad, adecuada para objetos complejos con necesidades de interacción semi-detalladas.
- Descomposición Convexa Precisa — Ofrece la fidelidad más precisa pero aún no es una representación 1:1 de lo visual. Esta opción tiene el costo de rendimiento más alto y toma más tiempo para que el motor lo calcule.

Para más información sobre el impacto en el rendimiento de las opciones de fidelidad de colisión y cómo mitigarlas, consulta optimización del rendimiento.