196 lines
7.6 KiB
C#
196 lines
7.6 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using Cysharp.Threading.Tasks;
|
|
using Dreamteck.Splines;
|
|
using Net.Project.B.Interaction;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
|
|
namespace Net.Project.B.WorldNode
|
|
{
|
|
public class UnitySubwayService:IDisposable
|
|
{
|
|
private readonly IWorldInteractionService _interactionService;
|
|
private readonly IEntitiesService _entitiesService;
|
|
private readonly IFixedTicker _ticker;
|
|
|
|
private readonly Dictionary<int, int> _prevPlatform = new();
|
|
private readonly Dictionary<int, SplineComputer> _splineComputers = new();
|
|
private readonly Dictionary<int, float> _distances = new();
|
|
private readonly Dictionary<int, float> _lengths = new();
|
|
private readonly Dictionary<int, float> _vehicleLength=new();
|
|
private readonly HashSet<int> _isBusy = new();
|
|
|
|
public UnitySubwayService(IEntitiesService entitiesService, IFixedTicker ticker, IWorldInteractionService interactionService)
|
|
{
|
|
_entitiesService = entitiesService;
|
|
_ticker = ticker;
|
|
_interactionService = interactionService;
|
|
|
|
_ticker.Add(OnTick);
|
|
_entitiesService.OnAdd += OnAdd;
|
|
}
|
|
|
|
private void OnAdd(IEntity obj)
|
|
{
|
|
if (obj.ServiceProvider.QueryComponents(out UnitySubwayNode subwayNode, out Transform transform))
|
|
{
|
|
var colliders = transform.GetComponentsInChildren<Collider>();
|
|
foreach (var x in colliders)
|
|
{
|
|
foreach (var y in colliders)
|
|
{
|
|
Physics.IgnoreCollision(x, y, true);
|
|
}
|
|
}
|
|
var spline = _splineComputers[obj.Id] = subwayNode.Spline.GetComponent<SplineComputer>();
|
|
var sample = spline.Project(transform.position);
|
|
var distance = Mathf.Lerp(0, _lengths[obj.Id]=spline.CalculateLength(),(float)sample.percent);
|
|
|
|
subwayNode.Subway.isKinematic = true;
|
|
subwayNode.Subway.interpolation = RigidbodyInterpolation.Interpolate;
|
|
|
|
_distances[obj.Id] = distance;
|
|
|
|
if(subwayNode.FrontWheel && subwayNode.BackWheel)
|
|
{
|
|
var localFrontPosition = subwayNode.FrontWheel.localPosition;
|
|
var localBackPosition = subwayNode.BackWheel.localPosition;
|
|
|
|
_vehicleLength[obj.Id] = Vector3.Distance(localFrontPosition, localBackPosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnTick(float obj)
|
|
{
|
|
var gc = GC.GetTotalMemory(false);
|
|
|
|
var stopNodes = _entitiesService.QueryComponents<IEntity,UnitySubwayPlatformNode, Transform>();
|
|
|
|
foreach (var (entity, transform, subwayNode) in _entitiesService
|
|
.QueryComponents<IEntity, Transform, UnitySubwayNode>())
|
|
{
|
|
if (_isBusy.Contains(entity.Id)) continue;
|
|
var spline = _splineComputers[entity.Id];
|
|
foreach (var (platformEntity, platformNode, platformTransform) in stopNodes)
|
|
{
|
|
var sample = spline.Project(platformTransform.position);
|
|
var subwayPosition = transform.position;
|
|
if (Vector3.Distance(sample.position, subwayPosition) < 1)
|
|
{
|
|
if (_prevPlatform.TryGetValue(entity.Id, out var prevPlatform) is false ||
|
|
prevPlatform != platformEntity.Id)
|
|
{
|
|
subwayNode.Subway.isKinematic = true;
|
|
|
|
_prevPlatform[entity.Id] = platformEntity.Id;
|
|
|
|
Arrived(entity.Id, platformNode.StopTime);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
var distance = _distances[entity.Id];
|
|
var length = _lengths[entity.Id];
|
|
distance = (distance + subwayNode.Speed * obj) % length;
|
|
_distances[entity.Id] = distance;
|
|
|
|
var percentage = distance<=0 ? 0 : distance / length;
|
|
|
|
sample= spline.Evaluate(percentage,SplineComputer.EvaluateMode.Calculate);
|
|
|
|
if (subwayNode.Offset.sqrMagnitude > 0.1f)
|
|
{
|
|
sample.position += sample.rotation * subwayNode.Offset;
|
|
}
|
|
|
|
|
|
|
|
if (_vehicleLength.TryGetValue(entity.Id, out var vehicleLength))
|
|
{
|
|
var sampleFront =spline.Evaluate(GetPercent(distance + vehicleLength / 2)) ;
|
|
var sampleBack =spline.Evaluate(GetPercent(distance - vehicleLength / 2)) ;
|
|
|
|
var up = Vector3.Cross(sample.forward, sample.right);
|
|
|
|
var rotation = quaternion.LookRotation(sampleFront.position - sampleBack.position, up);
|
|
|
|
subwayNode.Subway.MoveRotation(rotation);
|
|
|
|
var newPosition = Vector3.Lerp(sampleBack.position, sampleFront.position, 0.5f);
|
|
|
|
subwayNode.Subway.MovePosition(newPosition);
|
|
|
|
//_distances[entity.Id] = (float)spline.Project(newPosition).percent * length;
|
|
}
|
|
else
|
|
{
|
|
subwayNode.Subway.MovePosition(sample.position); //sample.position);
|
|
subwayNode.Subway.MoveRotation(sample.rotation);
|
|
}
|
|
|
|
continue;
|
|
float GetPercent(float d)
|
|
{
|
|
d %= length;
|
|
return d<=0 ? 0 : d / length;
|
|
}
|
|
}
|
|
}
|
|
|
|
var after = GC.GetTotalMemory(false);
|
|
|
|
if (gc != after)
|
|
{
|
|
// Debug.Log($"GC消耗:{gc}=>{after}");
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_ticker.Remove(OnTick);
|
|
}
|
|
|
|
private async void Arrived(int id, float stopTime)
|
|
{
|
|
if (_entitiesService.TryGetEntity(id, out var entity) is false) return;
|
|
if (entity.ServiceProvider.QueryComponents(out Transform transform,out UnitySubwayNode subwayNode) is false) return;
|
|
|
|
Door();
|
|
|
|
try
|
|
{
|
|
_isBusy.Add(entity.Id);
|
|
|
|
await UniTask.Delay(TimeSpan.FromSeconds(stopTime),cancellationToken: entity.CancellationToken);
|
|
|
|
Door();
|
|
|
|
await UniTask.Delay(TimeSpan.FromSeconds(4),cancellationToken: entity.CancellationToken);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
|
|
}
|
|
_isBusy.Remove(entity.Id);
|
|
return;
|
|
void Door()
|
|
{
|
|
foreach (var x in transform.GetComponentsInChildren<IEntity>())
|
|
{
|
|
if (x.ServiceProvider.QueryComponents(out UnityDoorNode doorNode,
|
|
out IWorldInteractable interactable))
|
|
{
|
|
_interactionService.Interaction(this, interactable, WorldInteractionProcess.System);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|