Raycast лучи как ими пользоваться зачем и вводные данные перед основной статьей
перед тем как выпустить основую статью про создание шутера bloodtide когда я разрабатывал оружие и мне нужно было использовать Raycast я задумался над тем что легче сначало изложить эту тему в отдельной статье а потом уже вам будет более понятно о чем вообще идет речь в основе:
Raycast в Roblox Studio — это метод, который позволяет выявить объекты в игровом мире, используя луч (ray). Луч излучается из определенной точки и направляется в заданном направлении, проверяя столкновение с объектами, которые находятся на его пути. Этот процесс часто используется для реализации различных механик, таких как стрельба, взаимодействие с объектами, проверки расстояния или определения того, попадает ли объект в линию видимости.
Основные моменты:
- Происхождение: Луч начинается в заданной точке в пространстве, которая может быть позиционирована вручную или определена программно.
- Направление: Луч имеет направление, обычно заданное векторами, которые могут определять движение вперед, назад, вверх и т. д.
- Длина: Луч может иметь определенную длину, которая ограничивает его радиус действия.
- Коллизия: Raycast проверяет столкновение с объектами, которые находятся в пути луча. Это может включать как игровые объекты, так и элементы, установленные в мире (например, стены или другие преграды).
вот собственно сам луч мы задали место из которого он исходит и его направление и в будущем ну точнее уже в следующей статье с помощью этой технологии мы с вами сделаем пули
сейчас посмотрим как задать луч:
вот собственно такой синтаксис задание луча и также нам необходимо внутри нашем методе обьекта workspace по имени RayCast задать опеределенные параметры посмотрите внимательно на первый блок где для удобства написана подсказка от роблокса
origin - это откуда собственно исходит луч
direction - это направление,цель в которую движется луч
RayCastParams - это определенные характеристики луча туда можно записать какие предметы игнорить и прочие модификации
также кто то кто не знаком с другими языками программирования спросит почему Raycast это метод а не функция и почему Workspace это обьект
Обьект это структура данных которая вмещает себя сразу и функции и переменные и многое другое и функции внутри обьекта являются методами это является частью одной из главных концепий с которой вы много столкнетесь
ООП- обьектно ориентированное программирование и это подход к программированию где данные и функции обьединяются в обьекты
мы не будем особо давать этому большее определение просто если когда нибудь в какой нибудь беседе кто то скажет что в Lua нету ООП то смело сможете заткнуть невежество
origin - это откуда собственно исходит луч
в общем мы указали стартовую позицию луча origin
дальше осталось указать направления луча
что нужно вот здесь в переменной direction?
пожалуйста не читайте дальше подумайте и напишите ответ в коментариях будет очень интересно посмотреть догадался ли кто то или нет
после того как написали и посмотрите дальше ответ скорее всего вас удивит!
90% процентов кто читает подумали что в direction надо записать part2.Position
вот яркий пример что будет если использовать вот нашу запись
В методе Raycast() второй аргумент — это вектор направления луча, который указывает, в какую сторону и на какое расстояние должен двигаться луч от начальной точки (origin). part2.Position — это просто координаты целевой точки, а не вектор, который определяет путь луча.
Когда вы передаете координаты точки (part2.Position) вместо вектора направления, результат будет неверным. Roblox интерпретирует part2.Position как вектор направления, и это не то, что вам нужно.
Как правильно указать направление?
Чтобы правильно задать вектор направления, вам нужно вычислить разницу между координатами начальной точки и целевой точки. Разница между двумя точками дает вам вектор, который указывает точное направление, по которому будет двигаться луч.
local part1 = workspace.Part1
local part2 = workspace.Part2
— Параметры для Raycast
local origin = part1.Position
local direction = part2.Position - part1.Position — Здесь мы вычисляем разницу между точками
local ray = workspace:Raycast(origin, direction)
Вектор, вычисленный как разница между part2.Position и part1.Position:
определяет точное направление луча. Это означает, что луч будет двигаться от точки part1.Position в направлении part2.Position.
Например, если part1.Position = (2, 3, 4) и part2.Position = (8, 6, 4), то разница между этими точками будет:
Таким образом, луч будет двигаться на 6 единиц по оси X и на 3 единицы по оси Y.
Заключение
Необходимо помнить: передача координат целевой точки (например, part2.Position) в качестве вектора направления — это ошибка. Это не задает направление луча, а просто указывает координаты точки в пространстве. Для корректной работы луча необходимо вычислить разницу между начальной и конечной точкой, которая и будет вектором направления луча.
### Оси в 3D-пространстве:
1. X — это горизонтальная ось, которая идет влево и вправо.
- Положительное значение (X > 0): движение вправо.
- Отрицательное значение (X < 0): движение влево.
2Y — это вертикальная ось, которая идет вверх и вниз.
- Положительное значение (Y > 0): движение вверх.
- Отрицательное значение (Y < 0): движение вниз.
3. Z — это ось глубины, которая идет вперед и назад.
- Положительное значение (Z > 0): движение вперед (к экрану).
- Отрицательное значение (Z < 0): движение назад (от экрана).
### Пример:
Вектор, например, `Vector3.new(10, 5, -3)`:
-X = 10— движение вправо на 10 единиц.
- Y = 5 — движение вверх на 5 единиц.
- Z = -3 — движение назад (от камеры) на 3 единицы.
Таким образом:
- X — это влево/вправ.
-Y — это вверх/вниз.
- Z — это вперед/назад.
теперь настало время погооврить о 3 параметре э
теперь осталось поговорить о 3 параметре это raycastparams собственно это параметры нашего луча
теперь обьявляем вот такую вот переменную
собственно она и будет олицетворять набор параметров и характеристик для данного луча
мы обьявляем таблицу которая содержит элементы которые будут фильтроваться по определенному признаку
таблица это просто список каких либо обьектов или элементов просто линейный набор данных который можно представить как полку на которой лежат ящики
теперь собственно укажем тип фильтра
собственно Exclude это обьекты которые луч будет игнорировать
Когда говорят, что **"луч будет игнорировать"** какой-либо объект, это означает, что объект не будет участвовать в процессе столкновения или взаимодействия с лучом. В результате луч не остановится или не взаимодействует с этим объектом, а продолжит двигаться в своем направлении.
### Как это работает в Roblox:
1. **Raycast** — это механизм, который позволяет проверять, сталкивается ли луч с объектами в игровом мире. Когда луч сталкивается с объектом, он может вернуться с результатом, содержащим информацию о пересечении, такую как:
- Имя объекта, с которым произошло пересечение.
- Позиция пересечения.
- Точка на объекте, с которой луч взаимодействует.
2. **Игнорировать объект** — это значит, что если объект находится в **списке исключений** (например, через `FilterDescendantsInstances` и `RaycastParams`), то луч **не будет учитывать** этот объект при поиске пересечений. То есть, если луч встретит объект, который был добавлен в список игнорируемых, он его проигнорирует и продолжит движение, не прерываясь.
Если у нас есть несколько объектов (например, `part1`, `part2`, и `part3`) и мы хотим, чтобы луч **игнорировал `part2`**, это может быть сделано с использованием `RaycastParams` с параметром **`FilterType`**:
```lua
local part1 = workspace.Part1
local part2 = workspace.Part2
local part3 = workspace.Part3
-- Настроим параметры для Raycast
local raycastParams = RaycastParams.new()
-- Указываем объекты, которые нужно игнорировать (в данном случае part2)
raycastParams.FilterDescendantsInstances = {part3}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude -- Исключаем часть из пересечения лучом
-- Выполняем Raycast
local origin = part1.Position
local direction = part2.Position - part1.Position
local rayResult = workspace:Raycast(origin, direction, raycastParams)
if rayResult then
print("Луч пересек объект: " .. rayResult.Instance.Name)
else
print("Луч не пересек ни одного объекта")
end
```
### В этом примере:
- **Луч** будет двигаться от `part1` к `part2`.
- **`part3`** будет **игнорироваться** лучом, благодаря установке фильтрации с `FilterType = Enum.RaycastFilterType.Exclude`.
- Это значит, что даже если луч пересекает `part3`, он не "заметит" его и не остановится. Луч продолжит движение и, возможно, пересечет другие объекты.
### Что происходит при игнорировании:
- **Игнорирование** объекта приводит к тому, что луч не будет "замечать" этот объект, и:
- Луч не остановится при его пересечении.
- Результат **Raycast** не будет включать информацию о пересечении с этим объектом.
- Луч будет двигаться дальше, как если бы этого объекта не существовало на его пути.
Таким образом, игнорирование объекта позволяет исключить его из взаимодействия с лучом и продолжить работу с другими объектами, с которыми луч может взаимодействовать.
Если использовать **`Enum.RaycastFilterType.Whitelist`** (включить объекты, или "Whitelist"), то луч будет **взаимодействовать только с теми объектами, которые находятся в списке `FilterDescendantsInstances`**.
Это означает, что **луч будет взаимодействовать только с указанными объектами**, а все остальные объекты будут **игнорироваться**.
### Пример с **Whitelist** (включение объектов):
```lua
local part1 = workspace.Part1
local part2 = workspace.Part2
local part3 = workspace.Part3
-- Настроим параметры для Raycast
local raycastParams = RaycastParams.new()
-- Указываем объекты, с которыми луч будет взаимодействовать (в данном случае part1 и part2)
raycastParams.FilterDescendantsInstances = {part1, part2}
raycastParams.FilterType = Enum.RaycastFilterType.Whitelist -- Включаем объекты из списка
-- Выполняем Raycast
local origin = part1.Position
local direction = part3.Position - part1.Position
local rayResult = workspace:Raycast(origin, direction, raycastParams)
if rayResult then
print("Луч пересек объект: " .. rayResult.Instance.Name)
else
print("Луч не пересек ни одного объекта")
end
```
### В этом примере:
- **Луч** будет двигаться от `part1` в направлении `part3`.
- **`part1` и `part2`** находятся в **Whitelist**, это значит, что луч будет взаимодействовать **только с этими частями**.
- Если луч столкнется с `part3` или любыми другими объектами, которые не входят в белый список, он **будет их игнорировать** и продолжит движение.
- **`part1` и `part2`** — это те объекты, с которыми луч будет "взаимодействовать" (пересекаться).
### Что происходит при использовании **Whitelist**:
1. Луч **взаимодействует только с теми объектами, которые находятся в списке** `FilterDescendantsInstances`.
2. Все другие объекты, которые **не находятся в этом списке**, **игнорируются** и не будут приниматься во внимание при расчетах столкновений.
3. **Raycast** возвращает результат только если луч пересекает объекты из белого списка. Если луч пересекает что-то, что не входит в этот список, результат не будет найден (возвращается `nil`).
### Важные моменты:
- **Whitelist** полезен, когда нужно работать с определенными объектами (например, только с игроками, определенными частями или каким-то конкретным набором объектов).
- Все объекты, не входящие в этот список, будут проигнорированы.
также вы увидите еще последние две надписи WhiteList и BlackList
поясню что WhiteList и Include это одно и тоже как и BlackList и Exclude просто в одном из обновлений добавили новые функции и использования старых теперь не рекомендуется но их по прежнемум можно использовать
также если что part3 это кирпич по середине
видите луч игнорируют все парты кроме 3 так как мы добавили фильтр игнорировать все предметы кроме тех что в таблице а в таблице у нас парт3
давайте теперь наоборот теперь он будет игнорировать все предметы которые в таблице
теперь он в сообщение игнорирует part3
1. Оптимизация производительности
Использование include и exclude позволяет уменьшить количество объектов, с которыми raycast будет взаимодействовать. Это важно, так как проверка на пересечения с большим количеством объектов может негативно сказаться на производительности игры. Ограничивая выбор объектов, вы можете сделать raycast более эффективным.
Часто в играх есть объекты, которые не должны реагировать на raycast. Например, вы можете не хотеть, чтобы луч взаимодействовал с декоративными объектами или определенными частями игрового мира, такими как стены или пол. Используя exclude, вы можете избежать неожиданных взаимодействий.
3. Создание уникального игрового опыта
В некоторых случаях вам может понадобиться, чтобы raycast реагировал только на определенные объекты. Например, в игре вы можете создать систему, где игроки могут стрелять по врагам, но не должны зацеплять свои собственные объекты или союзников. В этом случае вы можете использовать include для указания, что луч должен взаимодействовать только с вражескими объектами.
1. Стрельба из оружия:
Если в вашей игре есть оружие, которое стреляет, вы можете использовать raycast для определения, попал ли игрок в противника. Вы можете использовать include, чтобы указать, что луч должен взаимодействовать только с объектами, имеющими тег "Враг". В то же время, используя exclude, вы можете игнорировать объекты с тегом "Игрок", чтобы предотвратить случайные попадания в союзников.
2. Проверка линии видимости:
Вы можете использовать raycast, чтобы проверить, видит ли игрок определенный объект. Используя exclude, вы можете игнорировать объекты, которые блокируют линию видимости, например, стены или другие преграды.
3. Система квестов:
В играх с квестами вы можете использовать raycast для определения, взаимодействует ли игрок с объектом квеста. С помощью include вы можете указать, что луч должен реагировать только на объекты с тегом "Квест".
теперь поговорим про вывод состояние луча и работы с обьектом которого он коснулся
если rayResult равен true тогда
Доступ к свойствам объекта: Как только вы получили объект через raycastResult.Instance, вы можете получить доступ ко всем его свойствам и методам. Например, вы можете изменять свойства, взаимодействовать с объектом или проверять его характеристики.
в данном случае мы выводим его имя
а во втором принте мы выводим позицию луча
Зачем используется tostring()?
В данном случае, tostring() используется для преобразования значения rayResult.Position в строку. Это важно по нескольким причинам:
- Тип данных:
rayResult.Positionявляется вектором (объектом типаVector3), который представляет координаты в 3D пространстве. Когда вы пытаетесь конкатенировать (..) этот вектор с строкой, Lua требует, чтобы оба элемента были строками.- Если вы попытаетесь просто использовать
rayResult.Positionбезtostring(), возникнет ошибка, так как вы не можете объединить строку и объект типаVector3напрямую. - Форматирование вывода:
- Используя
tostring(), вы можете получить строковое представление вектора, которое будет выглядеть какVector3(1, 2, 3)(где 1, 2 и 3 — это значения по осям X, Y и Z соответственно). Это делает вывод более понятным и удобным для чтения. - конкатенирование значит сложение или соеденение двух строк
в данном случае чтобы вектор не является строкой следовательно мы не можем выполнить конкатенацию следовательно мы вызываем функцию tostring() для превращения вектора в строку а потом в следующее очередь их уже сконкатенировать