Верити: второй преследователь, общая сеть преследователей
- models/verity: модель verity2, звук из видео (verity.ogg), сцена с тем же мозгом, что у камня. В Backrooms вместо камня — Верити; в песочнице — Верити и камень. - Сеть: синхронизация любого числа преследователей по имени (Net.chasers, submit_chasers/recv_chasers) вместо одного камня. - rock-follow.gd: chaser_id, model_scale, emission_energy (чисто светящийся материал). - Экспорт: models/verity только в пакетах карт. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
extends Node3D
|
||||
# Камень преследует ближайшего живого игрока, обходя препятствия по навмешу, и ловит его.
|
||||
# Преследователь (камень, Верити…): гонится за ближайшим живым игроком, обходя препятствия по навмешу, и ловит его.
|
||||
# С sight_limited он замечает игрока лишь вблизи или в поле зрения без стен между ними;
|
||||
# потеряв из виду, идёт к последнему месту, где видел, и дальше бродит по карте.
|
||||
# В сети камень считает один клиент (владелец, его назначает сервер), остальные
|
||||
# плавно повторяют его позицию — поэтому у всех игроков камень один и тот же.
|
||||
|
||||
@export var chaser_id := "rock" # Имя в сети: по нему владелец и остальные клиенты сопоставляют преследователей
|
||||
@export var model_scale := 1.0 # Масштаб узла Model (если он есть): уменьшаем в тесных картах
|
||||
@export var emission_energy := -1.0 # Модель светится сама (чёрная основа, цвет = свечение × это число); меньше 0 — как в модели
|
||||
@export var speed := 15.0 # Скорость движения
|
||||
@export var turn_speed := 6.0 # Как быстро разворачивается к игроку
|
||||
@export var catch_distance := 3.0 # С какого расстояния (по горизонтали) ловит игрока
|
||||
@@ -43,14 +46,31 @@ func _ready() -> void:
|
||||
agent.target_desired_distance = 1.0
|
||||
agent.path_desired_distance = 1.5
|
||||
agent.path_height_offset = 0.25 # Навмеш лежит чуть выше пола
|
||||
var model := get_node_or_null("Model")
|
||||
if model != null and model_scale != 1.0:
|
||||
model.scale = Vector3.ONE * model_scale
|
||||
if emission_energy >= 0.0:
|
||||
_set_emission(emission_energy)
|
||||
for body in find_children("*", "CollisionObject3D", true, false):
|
||||
_own_rids.append(body.get_rid()) # Луч зрения не должен упираться в сам камень
|
||||
Net.rock = self
|
||||
Net.chasers[chaser_id] = self
|
||||
Net.peer_respawned.connect(_on_respawned)
|
||||
|
||||
# Копируем материалы модели (они общие для всех её экземпляров) и делаем их чисто светящимися:
|
||||
# без белой основы лицо не выгорает на ярком свету и не пропадает при слабом свечении
|
||||
func _set_emission(energy: float) -> void:
|
||||
for mi in find_children("*", "MeshInstance3D", true, false):
|
||||
for s in mi.mesh.get_surface_count():
|
||||
var mat := mi.get_active_material(s) as BaseMaterial3D
|
||||
if mat != null and mat.emission_enabled:
|
||||
var copy := mat.duplicate() as BaseMaterial3D
|
||||
copy.albedo_color = Color.BLACK
|
||||
copy.emission_energy_multiplier = energy
|
||||
mi.set_surface_override_material(s, copy)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if Net.rock == self:
|
||||
Net.rock = null
|
||||
if Net.chasers.get(chaser_id) == self:
|
||||
Net.chasers.erase(chaser_id)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if player == null:
|
||||
@@ -223,13 +243,14 @@ func _move_to(dest: Vector3, spd: float, stop_dist: float, delta: float) -> bool
|
||||
|
||||
# Камень считает другой клиент — плавно идём к тому, что он прислал
|
||||
func _follow_owner(delta: float) -> void:
|
||||
if not Net.rock_has_state:
|
||||
var state = Net.chaser_states.get(chaser_id)
|
||||
if state == null:
|
||||
return
|
||||
if global_position.distance_to(Net.rock_pos) > snap_distance:
|
||||
global_position = Net.rock_pos
|
||||
if global_position.distance_to(state.pos) > snap_distance:
|
||||
global_position = state.pos
|
||||
else:
|
||||
global_position = global_position.lerp(Net.rock_pos, 1.0 - exp(-sync_smoothing * delta))
|
||||
rotation.y = lerp_angle(rotation.y, Net.rock_yaw, 1.0 - exp(-sync_smoothing * delta))
|
||||
global_position = global_position.lerp(state.pos, 1.0 - exp(-sync_smoothing * delta))
|
||||
rotation.y = lerp_angle(rotation.y, state.yaw, 1.0 - exp(-sync_smoothing * delta))
|
||||
|
||||
# Кто-то (мы или другой игрок) возродился. Если камень рядом с точкой возрождения —
|
||||
# уводим его на старт, чтобы не поймал снова сразу. Решает только владелец камня.
|
||||
|
||||
Reference in New Issue
Block a user