Некротехнолог: работа духа - расходники коллекторов и готовое из станций

Раз в 3 с одно дело: (1) пополнить из ящиков зоны и сумки урны ячейки
расходников любого коллектора (банки, цветы, корм, сферы) и катализатора
(куры, по одной в пустую ячейку); (2) забрать готовое из коллекторов и
станций (верстак, кузня, химстанция, костёр...) в ящики зоны - сначала
к таким же, потом в пустое, ящики полны - в сумку урны; некуда - дух
чернеет и замирает, оживает сам. Модификации, инструменты, топливо и
сырьё станций не трогаются; открытое у игрока и закреплённые ячейки -
тоже. Модель духа плывёт к месту работы и обратно. Грядки - позже.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-16 15:43:36 +03:00
co-authored by Claude Opus 5.5
parent 0558f46069
commit 0890ffe1e9
4 changed files with 369 additions and 2 deletions
+69 -2
View File
@@ -139,6 +139,51 @@ namespace NecromancerTome
{
float _yaw;
float _phase;
/// <summary>Полёт к месту работы и обратно: точка в координатах модели урны и сколько осталось.</summary>
Vector3 _visit;
float _visitLeft;
public const float VisitSeconds = 2.2f;
/// <summary>Почернел и замер (готовое класть некуда, решение 06.10).</summary>
bool _stuck;
static readonly MaterialPropertyBlock _mpb = new MaterialPropertyBlock();
static readonly int ColorId = Shader.PropertyToID("_Color");
/// <summary>_worldUnity - точка в координатах сцены (без Origin): низ блока, где дух работал.</summary>
public void Visit(Vector3 _worldUnity)
{
if (transform.parent == null)
{
return;
}
_visit = transform.parent.InverseTransformPoint(_worldUnity);
_visitLeft = VisitSeconds;
}
public void SetStuck(bool _on)
{
if (_stuck == _on)
{
return;
}
_stuck = _on;
foreach (Renderer r in GetComponentsInChildren<Renderer>(true))
{
if (r.name.Contains("eye"))
{
continue;
}
if (_on)
{
r.GetPropertyBlock(_mpb);
_mpb.SetColor(ColorId, new Color(0.04f, 0.035f, 0.045f, Mathf.Max(CinerariumGenie.Alpha, 0.6f)));
r.SetPropertyBlock(_mpb);
}
else
{
r.SetPropertyBlock(null);
}
}
}
void OnEnable()
{
@@ -154,11 +199,33 @@ namespace NecromancerTome
void Update()
{
_yaw = (_yaw + CinerariumGenie.TurnSpeed * Time.deltaTime) % 360f;
if (_stuck)
{
return; // замер как был
}
Vector3 home = new Vector3(0f, CinerariumGenie.OffsetY, 0f);
float yawTarget = _yaw + CinerariumGenie.TurnSpeed * Time.deltaTime;
if (_visitLeft > 0f)
{
// Туда и обратно по синусу: на полпути - над местом работы, лицом к нему.
_visitLeft -= Time.deltaTime;
float k = Mathf.Sin(Mathf.Clamp01(1f - _visitLeft / VisitSeconds) * Mathf.PI);
Vector3 over = _visit + new Vector3(0f, CinerariumGenie.OffsetY + 0.6f, 0f);
transform.localPosition = Vector3.Lerp(home, over, k);
Vector3 d = _visit - home;
if (d.x * d.x + d.z * d.z > 0.01f)
{
yawTarget = Mathf.LerpAngle(_yaw, Mathf.Atan2(d.x, d.z) * Mathf.Rad2Deg, Time.deltaTime * 4f);
}
_yaw = yawTarget % 360f;
transform.localRotation = Quaternion.Euler(0f, _yaw, 0f);
return;
}
_yaw = yawTarget % 360f;
float bob = CinerariumGenie.BobPeriod > 0.01f
? Mathf.Sin((Time.time + _phase) * Mathf.PI * 2f / CinerariumGenie.BobPeriod) * CinerariumGenie.BobHeight
: 0f;
transform.localPosition = new Vector3(0f, CinerariumGenie.OffsetY + bob, 0f);
transform.localPosition = home + new Vector3(0f, bob, 0f);
transform.localRotation = Quaternion.Euler(0f, _yaw, 0f);
}
}