Files
aibis-dream/Assets/Scripts/MiniGame/Gear/ShaftGraph.cs
T
2024-11-23 21:20:10 +08:00

212 lines
6.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AibisDream
{
public class ShaftGraph
{
// 顶点数量
private readonly int _vertexSize;
// 顶点Map
private readonly Shaft[] _vertexArray;
// 邻接表
private float[,] _edgeTable;
// 遍历记录
private readonly bool[] _vertexRecordArray;
// 动力轴序号
private readonly int _rootIdx;
public ShaftGraph(Shaft[] shafts)
{
// 为轴赋值
_vertexSize = shafts.Length;
_vertexRecordArray = new bool[_vertexSize];
_vertexArray = shafts;
foreach (var shaft in _vertexArray)
{
shaft.InitShaft();
}
// 寻找唯一的驱动轴序号
_rootIdx = FindDriverIdx();
// 生成边邻接表
GeneEdgeTable();
UpdateSpeed();
}
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);
// 更新该节点对应的邻接表
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>
public void UpdateSpeed()
{
// 清除遍历记录
Array.Clear(_vertexRecordArray, 0, _vertexSize);
// 从驱动轴开始计算速度
_vertexRecordArray[_rootIdx] = true;
UpdateShaftSpeedByIdx(_rootIdx);
// 更新完速度后统一更新动画
foreach (var shaft in _vertexArray)
{
shaft.UpdateSpeed();
}
}
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;
// 继续寻找相邻齿轮
UpdateShaftSpeedByIdx(i);
}
}
}
/// <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;
foreach (var vertex in _vertexArray)
{
if (vertex.shaftType == ShaftType.Pluggable && !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;
}
}
}