Projectile: a round is told of its shot by its manager's one subscription, and first seen where its barrel was when the sim fired it inside the step
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
95b7aeb7a2
commit
de9e1ba2f9
3 changed files with 39 additions and 15 deletions
|
|
@ -159,7 +159,7 @@ namespace Aetheria.EditorTools
|
|||
MaxRange = 1e6f, FireRange = 1e6f, CommitTime = 1e5f, ArrivalTime = 2e5f
|
||||
};
|
||||
var projectile = new GameObject("Wiring Round").AddComponent<Projectile>();
|
||||
projectile.Launch(zone, shot, new Vector3(0, 0, 0));
|
||||
projectile.Launch(null, zone, shot, new Vector3(0, 0, 0));
|
||||
yield return null;
|
||||
|
||||
zone.Update(.5f);
|
||||
|
|
|
|||
|
|
@ -24,19 +24,16 @@ public class Projectile : MonoBehaviour
|
|||
private CultMath.float3 _barrel;
|
||||
private ShotOutcome _known;
|
||||
private bool _alive;
|
||||
private CompositeDisposable _binding;
|
||||
private ProjectileManager _owner;
|
||||
|
||||
// Takes the shot as the sim holds it, the zone whose sim time it is drawn at, and where the barrel is as this round is first seen.
|
||||
public void Launch(Zone zone, PendingShot shot, Vector3 barrel)
|
||||
public void Launch(ProjectileManager owner, Zone zone, PendingShot shot, Vector3 barrel)
|
||||
{
|
||||
_owner = owner;
|
||||
_zone = zone;
|
||||
_shot = shot;
|
||||
_barrel = new CultMath.float3(barrel.x, barrel.y, barrel.z);
|
||||
_known = null;
|
||||
_binding?.Dispose();
|
||||
_binding = new CompositeDisposable(
|
||||
zone.ShotCommitted.Where(o => o.ShotId == shot.ShotId).Subscribe(Committed),
|
||||
zone.ShotResolved.Where(o => o.ShotId == shot.ShotId).Subscribe(Resolve));
|
||||
_alive = true;
|
||||
transform.forward = new Vector3(shot.TravelDirection.x, 0, shot.TravelDirection.y);
|
||||
Draw();
|
||||
|
|
@ -56,14 +53,14 @@ public class Projectile : MonoBehaviour
|
|||
}
|
||||
|
||||
// The sim's commit: the record it holds now (a contact burst's arrival is shortened here) and what it decided.
|
||||
private void Committed(ShotOutcome outcome)
|
||||
internal void Committed(ShotOutcome outcome)
|
||||
{
|
||||
if (_zone.TryGetShot(outcome.ShotId, out var record)) _shot = record;
|
||||
_known = outcome;
|
||||
}
|
||||
|
||||
// The simulation's verdict. A round that hit or burst is drawn at its end and stops; a miss keeps flying.
|
||||
private void Resolve(ShotOutcome outcome)
|
||||
internal void Resolve(ShotOutcome outcome)
|
||||
{
|
||||
if (!_alive) return;
|
||||
_known = outcome;
|
||||
|
|
@ -78,16 +75,14 @@ public class Projectile : MonoBehaviour
|
|||
private void Finish()
|
||||
{
|
||||
_alive = false;
|
||||
_binding?.Dispose();
|
||||
_binding = null;
|
||||
_owner?.Forget(_shot.ShotId);
|
||||
StartCoroutine(Fade());
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
_alive = false;
|
||||
_binding?.Dispose();
|
||||
_binding = null;
|
||||
_owner?.Forget(_shot.ShotId);
|
||||
}
|
||||
|
||||
IEnumerator Fade()
|
||||
|
|
|
|||
|
|
@ -1,17 +1,46 @@
|
|||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
|
||||
public class ProjectileManager : InstantWeaponEffectManager
|
||||
{
|
||||
public Prototype ProjectilePrototype;
|
||||
|
||||
// The rounds this manager has in the air by shot id, told of the sim's commit and verdict by one subscription per zone: a
|
||||
// gun that fires hundreds of rounds in a step costs the dictionary an entry per round and nothing else (no subscription,
|
||||
// closure or disposable per round).
|
||||
private readonly Dictionary<int, Projectile> _live = new Dictionary<int, Projectile>();
|
||||
private readonly CompositeDisposable _listening = new CompositeDisposable();
|
||||
private Zone _zone;
|
||||
|
||||
// The round is drawn by DrawAhead from what the simulation publishes, so there is nothing to aim, jitter
|
||||
// or inherit here: spread is priced by FireControl, and the sim's round inherits nothing from its shooter.
|
||||
// A round the sim fired inside the step (rounds per step) is first seen where its shooter's barrel was at that moment:
|
||||
// the barrel as it is now, carried back along the shooter's motion for the time since.
|
||||
public override void Fire(InstantWeapon weapon, EquippedItem item, EntityInstance source, EntityInstance target, int shotId)
|
||||
{
|
||||
var zone = source.Entity.Zone;
|
||||
if (!zone.TryGetShot(shotId, out var shot)) return;
|
||||
Listen(zone);
|
||||
var age = (float) (zone.ExactTime - shot.FireTime);
|
||||
var velocity = source.Entity.Velocity;
|
||||
var p = ProjectilePrototype.Instantiate<Projectile>();
|
||||
p.Launch(zone, shot, source.GetBarrel(item.Hardpoint).position);
|
||||
_live[shotId] = p;
|
||||
p.Launch(this, zone, shot, source.GetBarrel(item.Hardpoint).position - new Vector3(velocity.x, 0, velocity.y) * age);
|
||||
p.Trail.Clear();
|
||||
}
|
||||
|
||||
internal void Forget(int shotId) => _live.Remove(shotId);
|
||||
|
||||
private void Listen(Zone zone)
|
||||
{
|
||||
if (_zone == zone) return;
|
||||
_listening.Clear();
|
||||
_live.Clear();
|
||||
_zone = zone;
|
||||
zone.ShotCommitted.Subscribe(outcome => { if (_live.TryGetValue(outcome.ShotId, out var p)) p.Committed(outcome); }).AddTo(_listening);
|
||||
zone.ShotResolved.Subscribe(outcome => { if (_live.TryGetValue(outcome.ShotId, out var p)) p.Resolve(outcome); }).AddTo(_listening);
|
||||
}
|
||||
|
||||
void OnDestroy() => _listening.Dispose();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue