318 lines
9.4 KiB
C#
318 lines
9.4 KiB
C#
using System;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace AibisDream
|
|
{
|
|
public class ShaftGraph
|
|
{
|
|
// 顶点数量
|
|
private readonly int _vertexSize;
|
|
|
|
// 顶点Map
|
|
private readonly Shaft[] _vertexArray;
|
|
|
|
private Shaft[] _panelShafts;
|
|
|
|
// 邻接表
|
|
private float[,] _edgeTable;
|
|
|
|
// 遍历记录
|
|
private readonly bool[] _vertexRecordArray;
|
|
|
|
// 动力轴序号
|
|
private readonly int _rootIdx;
|
|
|
|
public ShaftGraph(Shaft[] shafts, Shaft[] panelShafts)
|
|
{
|
|
// 为轴赋值
|
|
_vertexSize = shafts.Length;
|
|
_vertexRecordArray = new bool[_vertexSize];
|
|
_vertexArray = shafts;
|
|
_panelShafts = panelShafts;
|
|
foreach (var shaft in _vertexArray)
|
|
{
|
|
shaft.InitShaft();
|
|
}
|
|
|
|
foreach (var shaft in _panelShafts)
|
|
{
|
|
shaft.InitShaft();
|
|
}
|
|
|
|
// 寻找唯一的驱动轴序号
|
|
_rootIdx = FindDriverIdx();
|
|
|
|
// 生成边邻接表
|
|
GeneEdgeTable();
|
|
|
|
UpdateSpeed();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新轴
|
|
/// </summary>
|
|
/// <param name="panelShafts"></param>
|
|
public void UpdatePanel(Shaft[] panelShafts)
|
|
{
|
|
_panelShafts = panelShafts;
|
|
Array.ForEach(panelShafts, shaft => shaft.InitShaft());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 是否所有齿轮都在运行
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool AllRunning()
|
|
{
|
|
return _vertexArray.All(shaft => Mathf.Abs(shaft.speed) > 0.01f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 是否所有齿轮都是新的
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool AllNewGear()
|
|
{
|
|
return _vertexArray.Where(shaft => shaft.shaftType != ShaftType.Driver).All(shaft =>
|
|
shaft.childGear != null && shaft.childGear.gearProp == "NewGear");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 初始化速度
|
|
/// </summary>
|
|
/// <param name="initSpeed">初始速度</param>
|
|
public void StartRotate(float initSpeed)
|
|
{
|
|
_vertexArray[_rootIdx].speed = initSpeed;
|
|
UpdateSpeed();
|
|
}
|
|
|
|
public void Accelerate(float originSpeed, float speed)
|
|
{
|
|
foreach (var shaft in _vertexArray)
|
|
{
|
|
if (shaft.HasChildGear()) shaft.UpdateSpeedScale(speed);
|
|
}
|
|
}
|
|
|
|
private int FindDriverIdx()
|
|
{
|
|
for (int i = 0; i < _vertexSize; i++)
|
|
{
|
|
if (_vertexArray[i].shaftType == ShaftType.Driver)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成边邻接表
|
|
/// </summary>
|
|
private void GeneEdgeTable()
|
|
{
|
|
_edgeTable = new float[_vertexSize, _vertexSize];
|
|
|
|
for (int i = 0; i < _vertexSize - 1; i++)
|
|
{
|
|
for (int j = i + 1; j < _vertexSize; j++)
|
|
{
|
|
// 判断两个Shaft是否临接
|
|
if (Shaft.IsShaftConnected(_vertexArray[i], _vertexArray[j]))
|
|
{
|
|
_edgeTable[i, j] = Shaft.CalcAngularVelocityRatio(_vertexArray[i], _vertexArray[j]);
|
|
_edgeTable[j, i] = Shaft.CalcAngularVelocityRatio(_vertexArray[j], _vertexArray[i]);
|
|
}
|
|
else
|
|
{
|
|
_edgeTable[i, j] = 0;
|
|
_edgeTable[j, i] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 某个轴上齿轮发生变化时更新临接关系
|
|
/// </summary>
|
|
/// <param name="instanceID">轴ID</param>
|
|
public void ChangeVertex(int instanceID)
|
|
{
|
|
// 找到对应idx
|
|
int idx = TranInstanceIDToIdx(instanceID);
|
|
if (idx == -1) return;
|
|
|
|
// 更新该节点对应的邻接表
|
|
for (int i = 0; i < _vertexSize; i++)
|
|
{
|
|
// 遇到自身跳过
|
|
if (i == idx)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// 判断两个Shaft是否临接
|
|
if (Shaft.IsShaftConnected(_vertexArray[idx], _vertexArray[i]))
|
|
{
|
|
_edgeTable[idx, i] = Shaft.CalcAngularVelocityRatio(_vertexArray[idx], _vertexArray[i]);
|
|
_edgeTable[i, idx] = Shaft.CalcAngularVelocityRatio(_vertexArray[i], _vertexArray[idx]);
|
|
}
|
|
else
|
|
{
|
|
_edgeTable[idx, i] = 0;
|
|
_edgeTable[i, idx] = 0;
|
|
}
|
|
}
|
|
|
|
UpdateSpeed();
|
|
}
|
|
|
|
private int TranInstanceIDToIdx(int instanceID)
|
|
{
|
|
// 查找对应的序号
|
|
int idx = -1;
|
|
for (int i = 0; i < _vertexSize; i++)
|
|
{
|
|
if (instanceID == _vertexArray[i].GetInstanceID())
|
|
{
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新当前所有轴的速度
|
|
/// </summary>
|
|
private void UpdateSpeed()
|
|
{
|
|
// 清除遍历记录
|
|
Array.Clear(_vertexRecordArray, 0, _vertexSize);
|
|
// 从驱动轴开始计算速度
|
|
_vertexRecordArray[_rootIdx] = true;
|
|
UpdateShaftSpeedByIdx(_rootIdx);
|
|
UpdateUnreachableShafts();
|
|
|
|
// 更新完速度后统一更新动画
|
|
foreach (var shaft in _vertexArray)
|
|
{
|
|
shaft.ChangeRotateState();
|
|
}
|
|
}
|
|
|
|
private void UpdateShaftSpeedByIdx(int idx)
|
|
{
|
|
// 已知当前齿轮速度
|
|
float currentSpeed = _vertexArray[idx].speed;
|
|
|
|
for (int i = 0; i < _vertexSize; i++)
|
|
{
|
|
// 遍历临接齿轮
|
|
if (i != idx && _edgeTable[idx, i] > 0)
|
|
{
|
|
// 已遍历过就跳过
|
|
if (_vertexRecordArray[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// 更新速度
|
|
_vertexArray[i].speed = -currentSpeed * _edgeTable[idx, i];
|
|
|
|
// 已遍历的轴加上标记
|
|
_vertexRecordArray[i] = true;
|
|
// 如果当前齿轮未破碎,继续更新相邻齿轮
|
|
if (!_vertexArray[i].IsBroken)
|
|
{
|
|
UpdateShaftSpeedByIdx(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateUnreachableShafts()
|
|
{
|
|
// 从Driver开始相连的齿轮全部更新后,剩下的齿轮置空
|
|
for (int i = 0; i < _vertexSize; i++)
|
|
{
|
|
if (!_vertexRecordArray[i])
|
|
{
|
|
_vertexArray[i].speed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询可吸附的轴
|
|
/// </summary>
|
|
/// <param name="pos">齿轮位置</param>
|
|
/// <param name="gearRadius">齿轮半径</param>
|
|
/// <returns>吸附轴</returns>
|
|
public Shaft QuerySnapShaft(Vector3 pos, float gearRadius)
|
|
{
|
|
if (_vertexArray == null || _vertexArray.Length == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// 查询距离最近的,可吸附的Shaft
|
|
Shaft closestShaft = null;
|
|
float minDistance = -1;
|
|
|
|
var totalArray = _vertexArray.Concat(_panelShafts);
|
|
foreach (var vertex in totalArray)
|
|
{
|
|
if (!vertex.HasChildGear())
|
|
{
|
|
float tempDis = Vector3.Distance(vertex.transform.position, pos);
|
|
if (minDistance < 0 || tempDis < minDistance)
|
|
{
|
|
closestShaft = vertex;
|
|
minDistance = tempDis;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 没查到就返回空
|
|
if (!closestShaft)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// 查到了就返回是否吸附
|
|
return minDistance < gearRadius ? closestShaft : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 判断齿轮能不能放进轴内
|
|
/// </summary>
|
|
/// <param name="sourceShaft">当前轴</param>
|
|
/// <param name="gearRadius">齿轮半径</param>
|
|
/// <returns>是否可用</returns>
|
|
public bool CheckGearSuitable(Shaft sourceShaft, float gearRadius)
|
|
{
|
|
// 获取目标idx
|
|
int idx = TranInstanceIDToIdx(sourceShaft.GetInstanceID());
|
|
|
|
bool isShaftAvailable = true;
|
|
// 寻找所有临接轴
|
|
for (int i = 0; i < _vertexSize; i++)
|
|
{
|
|
if (i == idx) continue; // 不需要计算和自身的关系
|
|
float availableDis = Shaft.CalcShaftAvailableDis(sourceShaft.transform.position, _vertexArray[i]);
|
|
if (availableDis < gearRadius - 0.2f)
|
|
{
|
|
isShaftAvailable = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return isShaftAvailable;
|
|
}
|
|
}
|
|
} |