trace
Модуль trace пускает трассы движка — лучи, сферы, капсулы, коробки — и трассу пули с пробитием. Результат показывает, во что попала трасса.
Общие правила#
- Векторные аргументы —
vector. - Если трасса ни во что не попала, это не ошибка:
fraction = 1. - Трассы запрещены внутри события
mouse_inputи внутри колбэкаshould_hit_entityфильтра.
trace.ray(from: vector, to: vector, filter: trace_filter)#
Линейная трасса (луч).
| Параметр | Тип | Описание |
|---|---|---|
from |
vector |
начало |
to |
vector |
конец |
filter |
trace_filter |
фильтр из trace.filter (обязателен) |
Возвращает: trace_result.
-- Видит ли локальный игрок врага (луч от глаз до глаз)
local function is_visible(me, enemy)
local r = trace.ray(me:eye_position(), enemy:eye_position(), trace.filter(me, __mask.shot))
return r.fraction == 1 or r.enthit == enemy
end
events.pre_render:set(function()
local me = entity.local_pawn()
if not me or not me:is_alive() then return end
for _, enemy in ipairs(entity.pawns(true)) do
if is_visible(me, enemy) then
-- враг на виду
end
end
end)
trace.sphere(from: vector, to: vector, radius: number, filter: trace_filter)#
Трасса сферой. При radius <= 0 — обычный луч.
| Параметр | Тип | Описание |
|---|---|---|
from |
vector |
начало |
to |
vector |
конец |
radius |
number |
радиус сферы |
filter |
trace_filter |
фильтр |
Возвращает: trace_result.
local me = entity.local_pawn()
if me then
local eye = me:eye_position()
local r = trace.sphere(eye, eye + me:eye_angles():forward() * 500, 4, trace.filter(me))
print("Сфера прошла ", math.floor(r.fraction * 100), "%")
end
trace.capsule(from: vector, to: vector, center0: vector, center1: vector, radius: number, filter: trace_filter)#
Трасса капсулой.
| Параметр | Тип | Описание |
|---|---|---|
from |
vector |
начало |
to |
vector |
конец |
center0 |
vector |
центр первой полусферы капсулы |
center1 |
vector |
центр второй полусферы |
radius |
number |
радиус капсулы |
filter |
trace_filter |
фильтр |
Возвращает: trace_result.
local me = entity.local_pawn()
if me then
local o = me:origin()
local r = trace.capsule(o, o + vector(0, 0, -64), vector(0, 0, 0), vector(0, 0, 8), 2, trace.filter(me))
print("Пол под ногами на расстоянии ", r.fraction * 64)
end
trace.aabb(from: vector, to: vector, mins: vector, maxs: vector, filter: trace_filter)#
Трасса коробкой (hull). Если mins == maxs, это луч, смещённый на mins.
| Параметр | Тип | Описание |
|---|---|---|
from |
vector |
начало |
to |
vector |
конец |
mins |
vector |
нижний угол коробки |
maxs |
vector |
верхний угол коробки |
filter |
trace_filter |
фильтр |
Возвращает: trace_result.
-- Поместится ли игрок, если присесть на 64 юнита вперёд
local me = entity.local_pawn()
if me then
local o = me:origin()
local fwd = me:eye_angles():forward()
local to = o + vector(fwd.x, fwd.y, 0) * 64
local r = trace.aabb(o, to, vector(-16, -16, 0), vector(16, 16, 54), trace.filter(me))
print(r.fraction == 1 and "проход свободен" or "впереди препятствие")
end
trace.convex_hull(from: vector, to: vector, points: table, filter: trace_filter)#
Трасса выпуклой фигурой из точек.
| Параметр | Тип | Описание |
|---|---|---|
from |
vector |
начало |
to |
vector |
конец |
points |
table |
вершины фигуры {vector, ...} относительно позиции |
filter |
trace_filter |
фильтр |
Возвращает: trace_result.
local me = entity.local_pawn()
if me then
local eye = me:eye_position()
local pts = { vector(-2, -2, 0), vector(2, -2, 0), vector(0, 2, 0), vector(0, 0, 4) }
local r = trace.convex_hull(eye, eye + vector(0, 0, -100), pts, trace.filter(me))
print(r.hitpos)
end
trace.filter(arg?: entity|table, mask?: number, group?: number, set_mask?: number)#
Создаёт фильтр трассы.
| Параметр | Тип | Описание |
|---|---|---|
arg |
entity или table |
сущность — игнорировать её; массив сущностей — игнорировать их; таблица-словарь — задать поля фильтра (см. ниже) |
mask |
number или 64-битное целое |
с чем сталкиваться, биты __contents; по умолчанию 0x1C300B |
group |
number |
группа столкновений, по умолчанию 3 |
set_mask |
number |
маска наборов объектов, по умолчанию 0x0F |
Если arg — таблица-словарь ({interacts_with = ...}), её поля записываются в фильтр, и функция сразу возвращает его: аргументы 2–4 и умолчания не применяются. Неизвестный ключ — ошибка field not found.
Возвращает: trace_filter.
local me = entity.local_pawn()
if me then
local f1 = trace.filter(me) -- игнорировать себя
local f2 = trace.filter(me, __mask.shot) -- маска выстрела
local f3 = trace.filter({ interacts_with = __mask.shot_hull }) -- только заданное поле
end
Поля trace_filter#
| Поле | Чтение | Запись |
|---|---|---|
interacts_with |
64-битное целое | число или 64-битное целое — с чем сталкиваться |
interacts_exclude |
64-битное целое | что исключить |
interacts_as |
64-битное целое | как сама трасса выглядит для объектов |
collision_group |
number |
группа столкновений |
object_set_mask |
number |
маска наборов объектов |
ignore_entities |
ошибка field is write-only |
массив сущностей; заменяет список игнора целиком |
should_hit_entity |
ошибка field is write-only |
функция fn(ent) -> boolean; не функция — снять |
should_hit_entity вызывается для каждой задетой сущности, кроме игнорируемых. true — задевать; любой другой результат или ошибка внутри — не задевать.
-- Трасса, которая проходит сквозь союзников
local me = entity.local_pawn()
if me then
local f = trace.filter(me, __mask.shot)
f.should_hit_entity = function(ent)
return ent:is_enemy()
end
local eye = me:eye_position()
local r = trace.ray(eye, eye + me:eye_angles():forward() * 8192, f)
print(r.enthit)
end
Поля trace_result#
Объект результата только для чтения.
| Поле | Тип | Описание |
|---|---|---|
fraction |
number |
доля пройденного пути (1 — ни во что не попала) |
startpos |
vector |
начало |
endpos |
vector |
конец |
hitpos |
vector |
точка попадания |
normal |
vector |
нормаль поверхности попадания |
offset |
number |
расстояние плоскости попадания |
contents |
64-битное целое | содержимое поверхности, биты __contents |
startsolid |
boolean |
трасса началась внутри твёрдого |
type |
number |
форма трассы: 0 — луч, 1 — сфера, 2 — коробка, 3 — капсула, 4 — выпуклая фигура |
triangle |
number |
номер треугольника поверхности |
damage |
number |
у trace.bullet — оставшийся урон; у обычных трасс −1 |
damage_unscaled |
number |
урон без учёта хитгруппы; у обычных трасс −1 |
transform |
CTransform |
преобразование задетого тела |
surface |
declared_class или nil |
свойства поверхности |
hitbox |
declared_class или nil |
задетый хитбокс |
body |
lightuserdata или nil |
физическое тело |
shape |
lightuserdata или nil |
физическая форма |
enthit |
entity или nil |
задетая сущность |
local me = entity.local_pawn()
if me then
local eye = me:eye_position()
local r = trace.ray(eye, eye + me:eye_angles():forward() * 8192, trace.filter(me))
if bit.band(r.contents, __contents.window) ~= 0 then
print("Смотрим на стекло")
end
end
trace.bullet(from: vector, to: vector, pawn: entity, vdata?: declared_class, filter?: trace_filter)#
Трасса пули с пробитием (до 4 слоёв), как при выстреле.
| Параметр | Тип | Описание |
|---|---|---|
from |
vector |
точка выстрела |
to |
vector |
задаёт только направление; длина равна дальности оружия |
pawn |
entity |
стрелок (C_CSPlayerPawn) |
vdata |
declared_class |
данные оружия; по умолчанию — активное оружие стрелка |
filter |
trace_filter |
фильтр; по умолчанию trace.filter(pawn) |
- Возвращает по результату на каждое место контакта, по порядку от первого. Если контактов нет или у стрелка нет оружия — ничего не возвращает.
damageкаждого результата — урон, оставшийся после контакта. Если контакт — игрок, урон учитывает хитгруппу.
Возвращает: trace_result, ... — несколько значений.
-- Сколько урона пройдёт сквозь стену туда, куда смотрим
local me = entity.local_pawn()
if me and me:weapon() then
local eye = me:eye_position()
local hits = { trace.bullet(eye, eye + me:eye_angles():forward(), me) }
for i, r in ipairs(hits) do
print(i, ": ", r.enthit, " урон ", math.floor(r.damage))
end
end
Константы __contents и __mask#
Глобальные таблицы битов для масок трасс. Значения — 64-битные целые; объединяйте через bit.bor.
__contents: empty, solid, hitbox, trigger, sky, player_clip, npc_clip, block_los, ladder, pickup, block_sound, window, grate, world_geometry, touch_triggers, player, debris, physics_prop, nav_local_ignore, postprocessing_volume, carried_object, pushaway, server_entity_on_client, carried_weapon, static_level, team1, grenadeclip, moveable, monster, chicken, thrown_grenade, dropped_hostage.
__mask: all, shot, shot_brushonly, shot_hull, defaultplayersolid, npcsolid, water, opaque_and_npcs, blocklos, blocklos_and_npcs, visible, visible_and_npcs, solid_brushonly, defaultplayersolid_brushonly, npcsolid_brushonly, npcworldstatic, npcworldstatic_fluid, playersolid_brushonly, floortrace.
local me = entity.local_pawn()
if me then
-- стрельба, но без стёкол
local mask = bit.band(__mask.shot, bit.bnot(__contents.window))
local f = trace.filter(me, mask)
print(f.interacts_with)
end