Interesting question.
It strikes me as the easiest way to implement it would be to record transform history for every unit and then let any ship observe position of others by looking back into their history based on distance between them (to calc time delta). It’s not accurate but approximates the effect.
white paths - transform history
meshes - real positions
wire boxes - observed positions
note how the observed object position vary and depends on distance:
Zero optimizations, just a barely working, late-night sketch of an idea.
SpaceShip.cs
using System.Collections.Generic;
using UnityEngine;
public class SpaceShip : MonoBehaviour
{
const float k_speed_of_light = 1f;// world units per second
const int k_max_past = 100;// seconds to buffer
[SerializeField] float _speed = 1f;// world units per second
static List<SpaceShip> _instances = new List<SpaceShip>();
RingBuffer<Matrix4x4> _past = new RingBuffer<Matrix4x4>( k_max_past );
Vector3 _destination;
#if UNITY_EDITOR
void OnDrawGizmos ()
{
Vector3 position = transform.position;
{
Gizmos.color = Color.HSVToRGB( Mathf.Abs((float)GetHashCode()%17f)/17f , 1 , 1 );
int numInstances = _instances.Count;
for( int i=0 ; i<numInstances ; i++ )
{
var other = _instances[i];
if( other!=this )
{
float distance = Vector3.Magnitude( other.transform.position - position );
float seconds = distance / k_speed_of_light;
var enumerator = other._past.GetEnumeratorBackward();
int secondsInt = Mathf.FloorToInt( seconds );
for( int step=0 ; step<=secondsInt ; step++ )
enumerator.MoveNext();
Gizmos.DrawLine( position , enumerator.Current.GetColumn(3) );
Gizmos.matrix = enumerator.Current;//Matrix4x4.TRS( pos , enumerator.Current.rotation , Vector3.one );
Gizmos.DrawWireCube( Vector3.zero , Vector3.one/2f );
Gizmos.matrix = Matrix4x4.identity;
}
}
}
{
var enumerator = _past.GetEnumeratorBackward();
enumerator.MoveNext();
int i = 0;
Vector3 p0 = enumerator.Current.GetColumn(3);
while( enumerator.MoveNext() )
{
Vector3 p1 = enumerator.Current.GetColumn(3);
Gizmos.color = new Color{ r=1 , g=1 , b=1 , a=1f-((float)(i++)/(float)k_max_past) };
Gizmos.DrawLine( p0 , p1 );
p0 = p1;
}
}
}
#endif
void OnEnable () => _instances.Add( this );
void OnDisable () => _instances.Remove( this );
void Start ()
{
var ltw = transform.localToWorldMatrix;
for( int i=_past.Capacity-1 ; i!=-1 ; i-- )
_past.Push( ltw );
InvokeRepeating( nameof(Tick) , 0f , 1f );
InvokeRepeating( nameof(RandomDestination) , 0f , 1.77f );
}
void FixedUpdate ()
{
float dt = Time.fixedDeltaTime;
Vector3 pos = transform.position;
Vector3 dir = _destination - pos;
transform.position = Vector3.MoveTowards( pos , _destination , _speed * dt );
transform.rotation = Quaternion.Lerp( transform.rotation , Quaternion.LookRotation(dir.normalized) , dt );
}
void Tick () => _past.Push( transform.localToWorldMatrix );
void RandomDestination () => _destination = Random.insideUnitSphere * 10f;
}
RingBuffer.cs
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class RingBuffer <T> : IEnumerable, IEnumerable<T>
{
readonly T[] _array;
public readonly int Capacity;
/// <summary> Current index </summary>
/// <remarks> (not next one) </remarks>
int _index;
public int Index => _index;
[System.Obsolete("don't",true)]
public RingBuffer () {}
public RingBuffer ( int capacity )
{
this._array = new T[ capacity ];
this.Capacity = capacity;
this._index = 0;
}
public void Push ( T value )
{
_array[ _index++ ] = value;
if( _index==Capacity ) _index = 0;
}
public T Peek () => _array[_index];
public T this [ int index ] => _array[index];
IEnumerator IEnumerable.GetEnumerator ()
{
for( int i=_index ; i<Capacity ; i++ ) yield return _array[i];
for( int i=0 ; i<_index ; i++ ) yield return _array[i];
}
public IEnumerator<T> GetEnumerator ()
{
for( int i=_index ; i<Capacity ; i++ ) yield return _array[i];
for( int i=0 ; i<_index ; i++ ) yield return _array[i];
}
public IEnumerator<T> GetEnumeratorBackward ()
{
for( int i=_index ; i!=-1 ; i-- ) yield return _array[i];
for( int i=Capacity-1 ; i>_index ; i-- ) yield return _array[i];
}
public T[] AsArray () => _array;
}