2026-10-22 02:27:30 +02:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2020-12-22 03:13:43 +00:00
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
|
|
using System;
|
2020-03-22 19:05:26 +00:00
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
2026-08-10 14:57:50 +01:00
|
|
|
using MessagePack;
|
|
|
|
|
using Newtonsoft.Json;
|
2026-09-14 17:39:12 +02:00
|
|
|
using CultMath;
|
|
|
|
|
using static CultMath.math;
|
|
|
|
|
using quaternion = CultMath.quaternion;
|
2020-03-22 19:05:26 +00:00
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
[MessagePackObject]
|
2020-04-09 10:33:16 +01:00
|
|
|
public class Ship : Entity
|
2020-03-22 19:05:26 +00:00
|
|
|
{
|
2026-10-16 02:35:07 +02:00
|
|
|
public override float LayerHeight => ItemManager.GameplaySettings.ShipLayerHeight;
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
|
|
|
// [Key("bindings")] public Dictionary<KeyCode,Guid> Bindings = new Dictionary<KeyCode,Guid>();
|
|
|
|
|
//[IgnoreMember] public int HullHardpointCount;
|
|
|
|
|
|
|
|
|
|
// [IgnoreMember] public Dictionary<Targetable, float> Contacts = new Dictionary<Targetable, float>();
|
|
|
|
|
// [IgnoreMember] public Targetable Target;
|
2020-12-10 23:20:38 +00:00
|
|
|
public Entity HomeEntity;
|
2026-10-22 02:27:30 +02:00
|
|
|
// The pilot-controlled hull fields. PilotApplier, in the zone step, is their pilot-side writer, from the command the
|
|
|
|
|
// pilot (player input or the ship's agent) gave the entity; no Unity script can set them. Runtime only, never packed.
|
|
|
|
|
public float2 MovementDirection { get; internal set; }
|
|
|
|
|
// The one facing command, -1..1, positive clockwise; a heading becomes a demand only through Steering.Toward.
|
|
|
|
|
public float Turn { get; internal set; }
|
2021-03-15 11:40:46 +00:00
|
|
|
public bool IsPlayerShip;
|
2021-03-03 01:53:23 +00:00
|
|
|
|
2021-01-05 02:56:17 +00:00
|
|
|
private Thruster[] _allThrusters;
|
2026-10-10 13:40:06 +02:00
|
|
|
// One column per thruster (its effect per unit throttle, in the body frame) and the throttles the allocator answers with.
|
|
|
|
|
private float3[] _columns;
|
|
|
|
|
private float[] _throttles;
|
|
|
|
|
private readonly ThrustAllocator _allocator = new ThrustAllocator();
|
2021-03-05 14:31:18 +00:00
|
|
|
|
|
|
|
|
private bool _exitingWormhole = false;
|
|
|
|
|
private bool _enteringWormhole = false;
|
|
|
|
|
private float _wormholeAnimationProgress;
|
2026-08-10 14:57:50 +01:00
|
|
|
private float2 _wormholeEntryPosition;
|
|
|
|
|
private float2 _wormholeEntryDirection;
|
|
|
|
|
private float2 _wormholePosition;
|
|
|
|
|
private float2 _wormholeExitVelocity;
|
2021-03-05 14:31:18 +00:00
|
|
|
|
2021-05-14 03:03:28 +01:00
|
|
|
public bool WormholeAnimationInProgress => _enteringWormhole || _exitingWormhole;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
2021-03-05 14:31:18 +00:00
|
|
|
public event Action OnExitedWormhole;
|
|
|
|
|
public event Action OnEnteredWormhole;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
|
|
|
public quaternion Rotation { get; private set; }
|
2026-06-13 04:56:50 +01:00
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
public void ExitWormhole(float2 wormholePosition, float2 exitVelocity)
|
2021-03-05 14:31:18 +00:00
|
|
|
{
|
|
|
|
|
_exitingWormhole = true;
|
|
|
|
|
_wormholeAnimationProgress = 0;
|
|
|
|
|
_wormholePosition = wormholePosition;
|
|
|
|
|
_wormholeExitVelocity = exitVelocity;
|
2026-08-10 14:57:50 +01:00
|
|
|
Direction = normalize(exitVelocity);
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
public void EnterWormhole(float2 wormholePosition)
|
2021-03-05 14:31:18 +00:00
|
|
|
{
|
Mining Cut 3: a chunk is a target, detected by reflected light
- Entity.Target is one slot of TargetRef, read-only from outside
(IReadOnlyReactiveProperty); Entity.SetTarget is its one writer. A chunk is
taken only while the entity can see it, so a rock in darkness cannot be
picked. Every handler, agent, turret and test writes through SetTarget.
- Entity.ChunkInfo (Q14 A): the value the per-tick sensor rule settles at,
computed on demand through Sensor.PassiveRate/Sensor.Gain -- sum of the
active sensors' passive rates over (sensors x TargetInfoDecay), capped at 1.
Stored nowhere; no per-tick loop over chunks. ChunkVisible is the detection
threshold through the chunk path.
- The lost-track rule reads through the chunk path: Activate's reconciliation
and a per-tick check of the one slot drop a chunk target that has gone dark.
- Entity.VisibleChunksInReach (Q13 A): visible chunks within the longest range
among active weapons -- the one reach rule for cycling and programmatic picks.
- Entity-only readers take .Entity: TargetedBy/TargetedByCount, target items,
the stance gate (a chunk has no stance), lock (Q12 A: never on a chunk),
turrets, Combat, Minion, FireControl (a chunk fires untargeted until Cut 4).
TargetRange and the arc gate read a chunk's planar position.
- ActionGameManager: the reticle and next/previous offer visible ships and
visible chunks in reach; nearest stays enemies-only; the target panel,
indicator and fire-control debug take TargetRef. EntityInstance reads .Entity.
- MiningCut3Tests pin parity, darkness, monotone brightness, wear and break,
reach, the chunk query, target survival and loss, TargetRef equality, lock,
and field-kind assignment at generation and first load.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:56:39 +02:00
|
|
|
SetTarget(TargetRef.None);
|
2021-03-05 14:31:18 +00:00
|
|
|
_wormholeAnimationProgress = 0;
|
|
|
|
|
_enteringWormhole = true;
|
2026-08-10 14:57:50 +01:00
|
|
|
_wormholeEntryPosition = Position.xz;
|
|
|
|
|
_wormholeEntryDirection = normalize(_wormholeEntryPosition-wormholePosition);
|
2021-03-05 14:31:18 +00:00
|
|
|
_wormholePosition = wormholePosition;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
public override void Activate()
|
2021-01-05 02:56:17 +00:00
|
|
|
{
|
2021-02-26 19:01:47 +00:00
|
|
|
base.Activate();
|
2021-04-14 03:29:14 +01:00
|
|
|
|
2021-01-05 02:56:17 +00:00
|
|
|
_allThrusters = GetBehaviors<Thruster>().ToArray();
|
2026-10-10 13:40:06 +02:00
|
|
|
_columns = new float3[_allThrusters.Length];
|
|
|
|
|
_throttles = new float[_allThrusters.Length];
|
2021-01-05 02:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-14 03:56:49 +00:00
|
|
|
public Ship(ItemManager itemManager, Zone zone, EquippableItem hull, EntitySettings settings) : base(itemManager, zone, hull, settings)
|
2020-04-09 10:33:16 +01:00
|
|
|
{
|
2021-02-11 03:14:20 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-05 14:31:18 +00:00
|
|
|
#region ThrustCalculation
|
2021-04-14 03:29:14 +01:00
|
|
|
|
2026-10-11 00:14:31 +02:00
|
|
|
// What this ship can do at this instant (see ManoeuvreEnvelope): the box extremes of the thrusters' columns at their
|
2026-10-11 04:08:09 +02:00
|
|
|
// live thrust (zero when unpowered or not Active), because it reports what the ship can do now. The allocator solves
|
|
|
|
|
// with Column(NominalThrust), the full-grant column, because a column promises what a thruster does at a full grant
|
|
|
|
|
// and the allocator must not reshape its answer as the grant moves. Same geometry (Thruster.Column), different thrust.
|
|
|
|
|
// Derived each update, never saved.
|
Evasion term: reachable spread from the thrust and turn envelope, realised by changes of vector
Every hit price gains one factor, PDeviation(Evasion, Tracking): how far the target can
and does move off the line of fire within SolutionWindow (0.75 s). Capability is Reach, an
eight-face closed form over the ship's ManoeuvreEnvelope (summed from what each live
thruster and aether drive reports with its own Execute arithmetic, read live: a thruster's
Thrust property is stale until it fires, which is why the Djinni moved 1.6 times its stats,
M25). Behaviour is ManoeuvreTrack, observed once per Entity.Update from the measured
acceleration; a steady burn, coasting and a dither much faster than the window do not
evade, and sideways speed alone does not (ruling evasion-speed). The commit price adds the
term at any flight time, so an instant weapon feels a jinking target. Forecast owns the
term for HitProbability and Inspect, which gain Evasion and PEvasion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 00:48:27 +02:00
|
|
|
public ManoeuvreEnvelope Envelope { get; private set; }
|
|
|
|
|
|
|
|
|
|
private void RecalculateEnvelope()
|
|
|
|
|
{
|
2026-10-11 00:14:31 +02:00
|
|
|
float forward = 0, back = 0, left = 0, right = 0, clockwise = 0, counterClockwise = 0;
|
|
|
|
|
foreach (var thruster in _allThrusters)
|
|
|
|
|
{
|
|
|
|
|
var column = thruster.Column(thruster.Item != null && thruster.Item.PowerSupply > 1e-4f ? thruster.Thrust : 0f);
|
|
|
|
|
forward += max(column.y, 0f);
|
|
|
|
|
back += max(-column.y, 0f);
|
|
|
|
|
left += max(-column.x, 0f);
|
|
|
|
|
right += max(column.x, 0f);
|
|
|
|
|
clockwise += max(column.z, 0f);
|
|
|
|
|
counterClockwise += max(-column.z, 0f);
|
|
|
|
|
}
|
|
|
|
|
Envelope = new ManoeuvreEnvelope(forward, back, left, right, clockwise, counterClockwise);
|
Evasion term: reachable spread from the thrust and turn envelope, realised by changes of vector
Every hit price gains one factor, PDeviation(Evasion, Tracking): how far the target can
and does move off the line of fire within SolutionWindow (0.75 s). Capability is Reach, an
eight-face closed form over the ship's ManoeuvreEnvelope (summed from what each live
thruster and aether drive reports with its own Execute arithmetic, read live: a thruster's
Thrust property is stale until it fires, which is why the Djinni moved 1.6 times its stats,
M25). Behaviour is ManoeuvreTrack, observed once per Entity.Update from the measured
acceleration; a steady burn, coasting and a dither much faster than the window do not
evade, and sideways speed alone does not (ruling evasion-speed). The commit price adds the
term at any flight time, so an instant weapon feels a jinking target. Forecast owns the
term for HitProbability and Inspect, which gain Evasion and PEvasion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 00:48:27 +02:00
|
|
|
}
|
|
|
|
|
|
2021-03-05 14:31:18 +00:00
|
|
|
#endregion
|
|
|
|
|
|
2026-10-29 08:22:04 +01:00
|
|
|
// The player's turn axis as a fraction of the hull's yaw extreme, banded so each thruster joins over an equal share of
|
|
|
|
|
// the input. The allocator serves a turn by the thrusters with the least translation per unit of yaw first and brings in
|
|
|
|
|
// the next as they saturate; here the thrusters yawing the asked way are ranked by that ratio, equal ratios form one band,
|
|
|
|
|
// and band i fills over input [i/k, (i+1)/k]. A hull whose best-ratio thrusters hold a small share of its yaw then gets
|
|
|
|
|
// half the travel of a two-band turn before its drives join, instead of the first tenth. Full input is still full yaw.
|
|
|
|
|
public float BandedTurn(float axis)
|
|
|
|
|
{
|
|
|
|
|
axis = clamp(axis, -1f, 1f);
|
|
|
|
|
if (axis == 0 || _allThrusters == null) return axis;
|
|
|
|
|
var direction = axis > 0 ? 1f : -1f;
|
|
|
|
|
var thrusters = new List<(float ratio, float yaw)>();
|
|
|
|
|
var total = 0f;
|
|
|
|
|
foreach (var thruster in _allThrusters)
|
|
|
|
|
{
|
|
|
|
|
var column = thruster.Column(thruster.NominalThrust);
|
|
|
|
|
var yaw = column.z * direction;
|
|
|
|
|
if (!(yaw > 0)) continue;
|
|
|
|
|
thrusters.Add((length(float2(column.x, column.y)) / yaw, yaw));
|
|
|
|
|
total += yaw;
|
|
|
|
|
}
|
|
|
|
|
if (!(total > 0)) return axis;
|
|
|
|
|
thrusters.Sort((a, b) => a.ratio.CompareTo(b.ratio));
|
|
|
|
|
var bands = new List<float>();
|
|
|
|
|
var bandRatio = float.NaN;
|
|
|
|
|
foreach (var (ratio, yaw) in thrusters)
|
|
|
|
|
{
|
|
|
|
|
if (bands.Count > 0 && abs(ratio - bandRatio) <= .02f * max(bandRatio, 1e-6f)) bands[bands.Count - 1] += yaw;
|
|
|
|
|
else { bands.Add(yaw); bandRatio = ratio; }
|
|
|
|
|
}
|
|
|
|
|
var travel = abs(axis) * bands.Count;
|
|
|
|
|
var band = min((int)travel, bands.Count - 1);
|
|
|
|
|
var served = 0f;
|
|
|
|
|
for (var i = 0; i < band; i++) served += bands[i];
|
|
|
|
|
served += (travel - band) * bands[band];
|
|
|
|
|
return direction * min(served / total, 1f);
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-10 19:26:49 +02:00
|
|
|
// Called by Entity.Update once the items' performance is current and before the power bus is stepped and the items
|
|
|
|
|
// execute: liveness, thrust and the throttles they decide are one phase, the one Execute acts on. The lock is a
|
|
|
|
|
// bound on the allocator's solve; intent reaches the allocator here and nowhere else.
|
|
|
|
|
protected override void UpdateThrottles()
|
2020-03-22 19:05:26 +00:00
|
|
|
{
|
2026-10-10 19:26:49 +02:00
|
|
|
if (_exitingWormhole || _enteringWormhole) return;
|
|
|
|
|
RecalculateEnvelope();
|
|
|
|
|
for (var i = 0; i < _allThrusters.Length; i++)
|
|
|
|
|
_columns[i] = _allThrusters[i].Column(_allThrusters[i].NominalThrust);
|
|
|
|
|
_allocator.Allocate(_columns, MovementDirection, Turn, _throttles, ThrottleLocked);
|
|
|
|
|
for (var i = 0; i < _allThrusters.Length; i++) _allThrusters[i].Axis = _throttles[i];
|
|
|
|
|
}
|
2021-04-14 03:29:14 +01:00
|
|
|
|
2026-10-10 19:26:49 +02:00
|
|
|
public override void Update(float delta)
|
|
|
|
|
{
|
2026-10-29 08:33:26 +01:00
|
|
|
// No drag below top speed: ships coast and orbits do not decay; drag bleeds off only the excess over the hull's top
|
|
|
|
|
// speed (aetheria-gravity:ruling:no-drag-below-top-speed). The VelocityLimit clamp still caps it, so the excess is
|
|
|
|
|
// what this step's forces added; a soft cap, where surfing the beat is a temporary boost, is the ruling's other half.
|
2026-10-29 10:18:20 +01:00
|
|
|
// A docked ship has no flight of its own: its parent owns its pose (Entity.Update).
|
|
|
|
|
if (Parent == null)
|
|
|
|
|
{
|
|
|
|
|
var velocityMagnitude = length(Velocity);
|
|
|
|
|
var topSpeed = float.PositiveInfinity;
|
|
|
|
|
foreach (var limit in GetBehaviors<VelocityLimit>()) topSpeed = min(topSpeed, limit.Limit);
|
|
|
|
|
if (velocityMagnitude > topSpeed)
|
|
|
|
|
Velocity = normalize(Velocity) * (topSpeed + decay(velocityMagnitude - topSpeed, HullData.Drag * ItemManager.GameplaySettings.DragScale, delta));
|
|
|
|
|
|
|
|
|
|
Position.xz += Velocity * delta;
|
|
|
|
|
|
|
|
|
|
Velocity += Zone.GetForce(Position.xz) * delta;
|
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
var normal = Zone.GetNormal(Position.xz);
|
|
|
|
|
var shipRight = Direction.Rotate(ItemRotation.Clockwise);
|
|
|
|
|
var forward = cross(float3(shipRight.x, 0, shipRight.y), normal);
|
|
|
|
|
Rotation = quaternion.LookRotation(forward, normal);
|
|
|
|
|
|
2020-04-09 10:33:16 +01:00
|
|
|
base.Update(delta);
|
2021-03-05 14:31:18 +00:00
|
|
|
|
|
|
|
|
if (_exitingWormhole)
|
|
|
|
|
{
|
|
|
|
|
_wormholeAnimationProgress += delta / ItemManager.GameplaySettings.WormholeAnimationDuration;
|
|
|
|
|
if(_wormholeAnimationProgress < 1)
|
|
|
|
|
{
|
|
|
|
|
if (_wormholeAnimationProgress < ItemManager.GameplaySettings.WormholeExitCurveStart)
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
Position.xz = _wormholePosition;
|
|
|
|
|
Rotation = quaternion.LookRotation(float3(0, 1, 0), float3(-Direction.x, 0, -Direction.y));
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-03-05 21:45:32 +00:00
|
|
|
var exitLerp = (_wormholeAnimationProgress - ItemManager.GameplaySettings.WormholeExitCurveStart) /
|
|
|
|
|
(1 - ItemManager.GameplaySettings.WormholeExitCurveStart);
|
Delete AetheriaMath in favour of CultMath
AetheriaMath predates the CultMath swap and re-implemented helpers CultMath
now owns. Callers use CultMath directly: decay (Ship, AetherDrive, Entity),
damp (VelocityConversion, FieldTester, FieldDriver), first_order_intercept
(TurretController, Combat, GuidedProjectile), quadratic_bezier (FieldDriver)
and smootherstep (Ship). Parameter order matches in every case, and those
formulas have the same float evaluation order, so behaviour is unchanged.
Galaxy's commented-out segment check names distance_to_segment.
The other overloads had no callers and are dropped without a CultMath
counterpart being needed: the double Damp overloads, FindDistanceToSegment,
GetCatmullRomPosition, GetCubicSplinePosition, Smoothstep(x), and the
Deg2Rad/Rad2Deg constants.
AetherDb census, factions and hardpoint-fit are byte-identical to the
pre-cut captures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 18:02:41 +02:00
|
|
|
exitLerp = smootherstep(exitLerp); // Square the interpolation variable to produce curve with zero slope at start
|
2026-08-10 14:57:50 +01:00
|
|
|
Position.xz = _wormholePosition + normalize(_wormholeExitVelocity) * exitLerp * ItemManager.GameplaySettings.WormholeExitRadius;
|
|
|
|
|
Rotation = quaternion.LookRotation(
|
|
|
|
|
lerp(float3(0, 1, 0), forward, exitLerp),
|
|
|
|
|
lerp(float3(-Direction.x, 0, -Direction.y), normal, exitLerp));
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
Position.y = Position.y - lerp(ItemManager.GameplaySettings.WormholeDepth, 0, _wormholeAnimationProgress);
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_exitingWormhole = false;
|
|
|
|
|
OnExitedWormhole?.Invoke();
|
|
|
|
|
OnExitedWormhole = null;
|
2026-08-10 14:57:50 +01:00
|
|
|
Velocity = _wormholeExitVelocity;
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_enteringWormhole)
|
|
|
|
|
{
|
|
|
|
|
_wormholeAnimationProgress += delta / ItemManager.GameplaySettings.WormholeAnimationDuration;
|
|
|
|
|
if(_wormholeAnimationProgress < 1)
|
|
|
|
|
{
|
|
|
|
|
if (_wormholeAnimationProgress < 1 - ItemManager.GameplaySettings.WormholeExitCurveStart)
|
|
|
|
|
{
|
|
|
|
|
var enterLerp = _wormholeAnimationProgress / (1 - ItemManager.GameplaySettings.WormholeExitCurveStart);
|
Delete AetheriaMath in favour of CultMath
AetheriaMath predates the CultMath swap and re-implemented helpers CultMath
now owns. Callers use CultMath directly: decay (Ship, AetherDrive, Entity),
damp (VelocityConversion, FieldTester, FieldDriver), first_order_intercept
(TurretController, Combat, GuidedProjectile), quadratic_bezier (FieldDriver)
and smootherstep (Ship). Parameter order matches in every case, and those
formulas have the same float evaluation order, so behaviour is unchanged.
Galaxy's commented-out segment check names distance_to_segment.
The other overloads had no callers and are dropped without a CultMath
counterpart being needed: the double Damp overloads, FindDistanceToSegment,
GetCatmullRomPosition, GetCubicSplinePosition, Smoothstep(x), and the
Deg2Rad/Rad2Deg constants.
AetherDb census, factions and hardpoint-fit are byte-identical to the
pre-cut captures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 18:02:41 +02:00
|
|
|
enterLerp = smootherstep(enterLerp); // Square the interpolation variable to produce curve with zero slope at vertical
|
2026-08-10 14:57:50 +01:00
|
|
|
Position.xz = lerp(_wormholeEntryPosition, _wormholePosition, enterLerp);
|
|
|
|
|
Rotation = quaternion.LookRotation(
|
|
|
|
|
lerp(forward, float3(0, -1, 0), enterLerp),
|
|
|
|
|
lerp(normal, float3(-_wormholeEntryDirection.x, 0, -_wormholeEntryDirection.y), enterLerp));
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
Position.xz = _wormholePosition;
|
|
|
|
|
Rotation = quaternion.LookRotation(float3(0, -1, 0),
|
|
|
|
|
float3(-_wormholeEntryDirection.x, 0, -_wormholeEntryDirection.y));
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
Position.y = Position.y - lerp(0, ItemManager.GameplaySettings.WormholeDepth, _wormholeAnimationProgress);
|
2021-03-05 14:31:18 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_enteringWormhole = false;
|
|
|
|
|
OnEnteredWormhole?.Invoke();
|
|
|
|
|
OnEnteredWormhole = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-22 19:05:26 +00:00
|
|
|
}
|
2020-04-09 07:48:45 +01:00
|
|
|
}
|
|
|
|
|
|