Kolizja występuje, gdy dwa obiekty 3D stykają się w świecie 3D. Dla dostosowanej obsługi kolizji, BasePart ma zestaw zdarzeń kolizji oraz technik filtrowania kolizji, dzięki czemu możesz kontrolować, które fizyczne zespoły kolidują z innymi.
Zdarzenia kolizji
Zdarzenia kolizji zdarzają się, gdy dwa BaseParts dotykają się lub przestają się dotykać w świecie 3D. Możesz wykrywać te kolizje za pomocą zdarzeń Touched i TouchEnded, które występują niezależnie od wartości właściwości CanCollide któregokolwiek z części. Przy rozważaniu obsługi kolizji na częściach, zwróć uwagę na następujące kwestie:
- Właściwość CanTouch części określa, czy wyzwala zdarzenia kolizji. Jeśli jest ustawiona na false, ani Touched, ani TouchEnded nie zostaną wywołane.
- Właściwość CanCollide części wpływa na to, czy będzie ona fizycznie kolidować z innymi częściami i powodować działanie sił na nie. Nawet jeśli CanCollide jest wyłączone dla części, możesz wykrywać dotyk i brak dotyku za pomocą zdarzeń Touched i TouchEnded.
- Zdarzenia Touched i TouchEnded wyzwalają się tylko w wyniku ruchu fizycznego, a nie z powodu zmian Position lub CFrame, które powodują, że część wchodzi w interakcję lub przestaje wchodzić w interakcję z inną częścią.
Dotknięcie
Zdarzenie Touched wyzwala się, gdy BasePart stykają się z innym lub z wokselem Terrain. Wyzwala się tylko w wyniku symulacji fizycznej i nie wyzwala się, gdy Position lub CFrame jest jawnie ustawione tak, aby wchodziło w interakcję z inną częścią lub wokselem.
Poniższy wzór kodu pokazuje, jak zdarzenie Touched może być połączone z niestandardową funkcją onTouched(). Zauważ, że zdarzenie przesyła argument otherPart do funkcji, wskazując na drugą część zaangażowaną w kolizję.
local part = workspace.Part
local function onTouched(otherPart)
print(part.Name .. " zderzył się z " .. otherPart.Name)
end
part.Touched:Connect(onTouched)Zauważ, że zdarzenie Touched może wyzwalać się wielokrotnie w szybkim odstępie czasu w oparciu o subtelne kolizje fizyczne, takie jak gdy poruszający się obiekt "osiada" w pozycji spoczynkowej lub gdy kolizja dotyczy modelu wieloczęściowego. Aby uniknąć wyzwalania większej liczby zdarzeń Touched niż to konieczne, możesz wdrożyć prosty system debouncing, który wymusza okres "cooldown" za pomocą atrybutu instancji.
local part = workspace.Part
local COOLDOWN_TIME = 1
local function onTouched(otherPart)
if not part:GetAttribute("Touched") then
print(part.Name .. " zderzył się z " .. otherPart.Name)
part:SetAttribute("Touched", true) -- Ustaw atrybut na true
task.wait(COOLDOWN_TIME) -- Czekaj na czas cooldown
part:SetAttribute("Touched", false) -- Zresetuj atrybut
end
end
part.Touched:Connect(onTouched)TouchEnded
Zdarzenie TouchEnded wyzwala się, gdy całe pole kolizji BasePart opuszcza pole innej BasePart lub wypełnionego wokselu Terrain. Wyzwala się tylko w wyniku symulacji fizycznej i nie wyzwala się, gdy Position lub CFrame jest jawnie ustawione tak, aby przestało wchodzić w interakcję z inną częścią lub wokselem.
Poniższy wzór kodu pokazuje, jak zdarzenie TouchEnded może być połączone z niestandardową funkcją onTouchEnded(). Podobnie jak Touched, zdarzenie przesyła argument otherPart do funkcji, wskazując na drugą część zaangażowaną.
local part = workspace.Part
local function onTouchEnded(otherPart)
print(part.Name .. " już nie dotyka " .. otherPart.Name)
end
part.TouchEnded:Connect(onTouchEnded)Podsumowania kolizji
Touched informuje cię że kolizja miała miejsce, ale nie gdzie miała miejsce, z jakiego kierunku pochodziła ani jak mocno. Aby uzyskać szczegółowe dane kontaktowe z silnika fizycznego, wywołaj BindToCollisionSummaries() na części. Przyjmuje to funkcję zwrotną i zwraca RBXScriptConnection, którą możesz odłączyć, gdy nie potrzebujesz już danych. Jest to osobne API od Touched, więc nie wywołuj go wewnątrz handlera Touched.
Funkcja zwrotna uruchamia się raz na klatkę, po zakończeniu kroku fizyki. Otrzymuje tabelę z podsumowaniem każdej kolizji, w której część brała udział w danej klatce. Każda podsumowanie opisuje jeden punkt kontaktowy między subskrybowaną częścią a inną częścią. Podsumowania są zamrożone i nie mogą być zmieniane. Każde z nich ma następujące pola:
| Pole | Typ | Opis |
|---|---|---|
| Czas | number | Czas symulacji podetapu. |
| Part0 | BasePart | Subskrybowana część. |
| Part1 | BasePart | Druga część w parze. |
| Punkt | Vector3 | Uśredniony punkt kontaktowy, w przestrzeni świata. |
| Normal | Vector3 | Normalna jednostkowa. Zawsze wskazuje od Part0. |
| RelativeVelocity | Vector3 | Prędkość Part1 w stosunku do Part0 w punkcie kontaktowym, mierzona przed rozwiązaniem kolizji przez solver. |
| Area | number | Szacowana powierzchnia punktu kontaktowego. |
Aby uzyskać prędkość uderzenia, weź iloczyn skalarny RelativeVelocity i Normal. Aby wykryć uderzenia boczne lub ślizganie, użyj komponentu stycznego RelativeVelocity. Jeśli chcesz uzyskać wartość bliższą sile, połącz prędkość z AssemblyMass części.
local part = workspace.Part
local function onCollision(summaries)
for _, summary in summaries do
local impactSpeed = summary.RelativeVelocity:Dot(summary.Normal)
if impactSpeed > 10 then
print("Silne uderzenie w", summary.Point, "z prędkością", impactSpeed)
end
end
end
local connection = part:BindToCollisionSummaries(onCollision)
-- Później, gdy nie potrzebujesz już podsumowań
connection:Disconnect()Pamiętaj o następujących kwestiach, gdy używasz podsumowań kolizji:
- Podsumowania są generowane tylko na właścicielu sieci, który prowadzi symulację fizyki, co może być klientem lub serwerem. Nie są replikowane. Jeśli inni klienci muszą wiedzieć o kolizji, przetwórz podsumowanie i wyślij tylko dane, których potrzebują, za pomocą własnego zdarzenia zdalnego.
- Części z ustawioną CanCollide na false nie generują podsumowań kolizji.
- Złożone części niekonwencjonalne mogą generować więcej niż jedno podsumowanie dla tej samej pary części.
- Kontakty między dwiema śpiącymi częściami nie są rejestrowane.
- Koszt przetwarzania rośnie wraz z liczbą subskrybowanych części, a nie z całkowitą liczbą kolizji w miejscu.
Filtrowanie kolizji
Filtrowanie kolizji definiuje, które fizyczne części kolidują z innymi. Możesz skonfigurować filtrowanie dla wielu obiektów za pomocą grup kolizji lub możesz kontrolować kolizje na zasadzie część-do-części za pomocą instancji NoCollisionConstraint.
Grupy kolizji
Grupy kolizji pozwalają przypisać BaseParts do dedykowanych grup i określić, czy kolidują one z obiektami w innych grupach. Części w grupach, które nie kolidują, przechodzą przez siebie całkowicie, nawet jeśli obie części mają ustawioną właściwość CanCollide na true. Grupy kolizji są tworzone i konfigurowane na poziomie Workspace lub WorldModel.
Możesz łatwo skonfigurować grupy kolizji za pomocą edytora Grupy kolizji w Studio, dostępnego w menu Okno ⟩ 3D.
Rejestracja grup
Workspace przechowuje swój własny konfigurowalny stan grup kolizji. Dodatkowo, każdy WorldModel może zdecydować się na użycie własnych grup kolizji do zapytań.
Edytor zawiera jedną grupę kolizji Domyślną, której nie można zmienić nazwy ani usunąć. Wszystkie BaseParts automatycznie należą do tej domyślnej grupy, chyba że przypisano je do innej grupy, co oznacza, że będą kolidować ze wszystkimi innymi obiektami w grupie Domyślnej.
Aby utworzyć nową grupę kolizji:
Domyślnie grupy są rejestrowane w Workspace, ale jeśli masz przynajmniej jeden WorldModel w swoim miejscu, na górze edytora grup kolizji pojawi się rozwijane menu. Użyj rozwijanego menu, aby skonfigurować grupy kolizji w różnych instancjach WorldModel.

Dla dowolnego WorldModel możesz włączyć Użyj grup kolizji Workspace, aby używał grup kolizji Workspace do swoich zapytań.

Kliknij przycisk Dodaj grupę na górze panelu edytora, wprowadź nową nazwę grupy i naciśnij Enter. Nowa grupa pojawi się w obu kolumnach widoku listy lub w lewej kolumnie i górnym wierszu widoku tabeli.

Powtórz proces w razie potrzeby, wybierając unikalną i opisową nazwę dla każdej grupy. Zauważ, że możesz zmienić nazwę grupy w trakcie rozwoju, klikając w jej pole lub wybierając ją i klikając przycisk zmień nazwę.

Konfiguracja kolizji grup
Podczas domyślnej konfiguracji obiekty w wszystkich grupach kolidują ze sobą. Aby zapobiec kolizjom obiektów w jednej grupie z obiektami w innej grupie, odznacz pole w odpowiednim wierszu/kolumnie.
W poniższym przykładzie obiekty w grupie Kostki nie będą kolidować z obiektami w grupie Drzwi.

Przypisywanie obiektów do grup
Aby przypisać obiekty do grup, które zarejestrowałeś za pomocą edytora Studio:
Wybierz jeden lub więcej BaseParts, które kwalifikują się jako część grupy kolizji.
Przypisz je do grupy, klikając przycisk ⊕ dla jej wiersza. Obiekty mogą należeć tylko do jednej grupy kolizji w danym czasie, więc umieszczenie ich w nowej grupie usuwa je z ich bieżącej grupy.

Po przypisaniu nowa grupa jest odzwierciedlana w właściwości CollisionGroup obiektu.

Grupa StudioSelectable
Narzędzia w Studio używają systemu filtrowania kolizji, aby określić, które obiekty są kandydatami do wyboru podczas klikania w widoku 3D. Obiekty, których przypisana grupa kolizji nie koliduje z StudioSelectable, będą ignorowane.
Na przykład, jeśli masz punkty kontrolne w grze wyścigowej, których efektywne obszary są definiowane przez duże przezroczyste części, możesz przypisać je do grupy kolizji Punkty kontrolne, a następnie uczynić tę grupę niekolidującą z StudioSelectable, aby nie przeszkadzały podczas edytowania podstawowej geometrii mapy.

Dla kodu wtyczki zaleca się przypisanie "StudioSelectable" jako filtr grupy kolizji twojego RaycastParams podczas znajdowania części pod kursorem. Umożliwia to twoim wtyczkom dopasowanie mechaniki wyboru, której twórcy nauczyli się oczekiwać od wbudowanych narzędzi Studio.
local UserInputService = game:GetService("UserInputService")
local raycastParams = RaycastParams.new()
raycastParams.CollisionGroup = "StudioSelectable" -- Aby podążać za konwencją
raycastParams.BruteForceAllSlow = true -- Aby części z CanQuery równym "false" mogły być wybierane
local mouseLocation = UserInputService:GetMouseLocation()
local mouseRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
local filteredSelectionHit = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 10000, raycastParams)Filtrowanie część-do-części
Aby zapobiec kolizjom między dwoma konkretnymi częściami bez konfigurowania grup kolizji, takich jak między kołem pojazdu a jego podwoziem, rozważ użycie ograniczenia No Collision. Zalety obejmują:
- Nie są wymagane grupy kolizji i/lub skrypty konfiguracyjne, więc możesz łatwo tworzyć i udostępniać modele z dostosowanym filtrowaniem kolizji.
- Połączone części nie będą kolidować ze sobą, ale nadal mogą kolidować z innymi obiektami.
Wyłączenie kolizji postaci
Postacie graczy Roblox kolidują ze sobą domyślnie. Może to prowadzić do interesującej, ale niezamierzonej rozgrywki, takiej jak postacie skaczące na siebie, aby dotrzeć do określonych obszarów. Jeśli to zachowanie jest niepożądane, możesz je zablokować za pomocą następującego Script w ServerScriptService.
local Players = game:GetService("Players")
workspace:RegisterCollisionGroup("Postacie")
workspace:CollisionGroupSetCollidable("Postacie", "Postacie", false)
local function onDescendantAdded(descendant)
-- Ustaw grupę kolizji dla każdego potomka części
if descendant:IsA("BasePart") then
descendant.CollisionGroup = "Postacie"
end
end
local function onCharacterAdded(character)
-- Przetwórz istniejące i nowe potomki w celu ustawienia fizyki
for _, descendant in character:GetDescendants() do
onDescendantAdded(descendant)
end
character.DescendantAdded:Connect(onDescendantAdded)
end
Players.PlayerAdded:Connect(function(player)
-- Wykryj, kiedy dodawana jest postać gracza
player.CharacterAdded:Connect(onCharacterAdded)
end)Kolizje modeli
Obiekty Model są kontenerami dla części, a nie dziedziczą z BasePart, więc nie mogą bezpośrednio łączyć się z zdarzeniami BasePart.Touched lub BasePart.TouchEnded. Aby określić, czy model wyzwala zdarzenia kolizji, musisz przejść przez jego dzieci i połączyć niestandardowe funkcje onTouched() i onTouchEnded() z każdą dziecinną BasePart.
Poniższy przykład kodu łączy wszystkie BaseParts modelu wieloczęściowego z zdarzeniami kolizji i śledzi całkowitą liczbę kolizji z innymi częściami.
local model = script.Parent
local numTouchingParts = 0
local function onTouched(otherPart)
-- Ignoruj instancje modelu wchodzące w interakcję z samym sobą
if otherPart:IsDescendantOf(model) then return end
-- Zwiększ liczbę części modelu dotykających
numTouchingParts += 1
print(model.Name, "wchodzi w interakcję z", otherPart.Name, "| Części modelu dotykające:", numTouchingParts)
end
local function onTouchEnded(otherPart)
-- Ignoruj instancje modelu przestające wchodzić w interakcję z samym sobą
if otherPart:IsDescendantOf(model) then return end
-- Zmniejsz liczbę części modelu dotykających
numTouchingParts -= 1
print(model.Name, "przestał wchodzić w interakcję z", otherPart.Name, "| Części modelu dotykające:", numTouchingParts)
end
for _, child in model:GetChildren() do
if child:IsA("BasePart") then
child.Touched:Connect(onTouched)
child.TouchEnded:Connect(onTouchEnded)
end
endKolizje modeli siatkowych i stałych
Obiekty MeshPart i PartOperation (części połączone przez modelowanie stałe) są podklasami BasePart, więc siatki i części modelowane stałe dziedziczą te same zdarzenia kolizji i opcje filtrowania kolizji co zwykłe części. Jednak ponieważ siatki i części modelowane stałe mają zazwyczaj bardziej złożoną geometrię, mają charakterystyczną właściwość CollisionFidelity, która określa, jak dokładnie fizyczne granice są zgodne z wizualną reprezentacją do obsługi kolizji.
Właściwość CollisionFidelity ma następujące opcje, w kolejności od najniższej do najwyższej dokładności i wpływu na wydajność:
- Box — Tworzy ograniczającą kolizję w postaci pudełka, idealną dla małych lub nieinteraktywnych obiektów.
- Hull — Generuje wypukły huls, odpowiedni dla obiektów z mniej wyraźnymi wcięciami lub wnękami.
- Domyślny — Produkuje przybliżony kształt kolizji, który wspiera konkawność, odpowiedni dla złożonych obiektów z półszczegółowymi potrzebami interakcji.
- PreciseConvexDecomposition — Oferuje najwyższą dokładność, ale nadal nie jest 1:1 reprezentacją wizualną. Ta opcja ma najwyższy koszt wydajności i zajmuje więcej czasu na obliczenia przez silnik.

Aby uzyskać więcej informacji na temat wpływu wydajności opcji dokładności kolizji i jak je złagodzić, zobacz optymalizację wydajności.