Files
aibis-dream/Assets/Scripts/MiniGame/Gear/Shaft.cs
T
2025-08-19 20:45:12 +08:00

343 lines
10 KiB
C#

using System;
using AibisDream.FixSystem;
using AibisDream.Framework;
using DG.Tweening;
using Newtonsoft.Json;
using UnityEngine;
namespace AibisDream
{
public class Shaft : MonoBehaviour
{
[SerializeField] private int id;
[SerializeField] public ShaftType shaftType;
// 初始齿轮
[SerializeField] private bool hasGear;
[SerializeField] private string gearProp;
[SerializeField] private bool isInitGearBroken;
[SerializeField] private bool isInitGearDisc;
[SerializeField] private float initRadius;
[SerializeField] private Sprite initSprite;
[SerializeField] private int discIdx;
[SerializeField] public Gear childGear;
// 目标角速度
[SerializeField] private float targetSpeed;
// 当前角速度
public float speed;
private float _speedScale = 1;
public bool IsBroken => childGear != null && childGear.isBroken;
public bool IsDisc => childGear != null && childGear.isDisc;
/// <summary>
/// 当前齿轮半径
/// </summary>
public float GearRadius
{
get
{
if (!childGear)
{
return 0;
}
return childGear.radius;
}
}
private GearSystem GearSystem => FixSystemCenter.SystemDic.Get<GearSystem>();
/// <summary>
/// 初始化当前轴位置
/// </summary>
public void InitShaft()
{
// 如果不带齿轮
if (!hasGear) return;
// 如果带齿轮,要根据齿轮类型生成
childGear = InitGear(initRadius, initSprite, isInitGearBroken, isInitGearDisc);
childGear.UpdateRotation(speed, _speedScale);
}
private Gear InitGear(float radius, Sprite sprite, bool isBroken = false, bool isDisc = false)
{
var gear = Instantiate(GearSystem.gearPrefab, transform).GetComponent<Gear>();
gear.radius = radius;
gear.gearSprite = sprite;
gear.gearProp = gearProp;
gear.isBroken = isBroken;
gear.targetShaft = this;
gear.isDisc = isDisc;
gear.isConstant = shaftType != ShaftType.Pluggable; // TODO 驱动齿轮和目标齿轮暂时也不给动
return gear;
}
public void PlugInGear(Gear gear)
{
childGear = gear;
gear.transform.parent = transform;
GearSystem.ChangeGraphVertex(GetInstanceID());
// 面板里的齿轮才能触发
if (GearSystem.IsShaftInBox(transform))
{
OnGearPlugIn();
GearSystem.CheckGearSystemState();
}
}
private void OnGearPlugIn()
{
// 破损齿轮插进来就发一次事件,交给yarn处理
if (IsBroken)
{
DialogController.Instance?.StartDialogNode("破损齿轮插入");
}
if (IsDisc)
{
StorageSystem.Instance?.SetValue("$discIdx", discIdx);
}
// 传当前插入齿轮的Prop
StorageSystem.Instance?.SetValue("$curGearProp", childGear.gearProp);
}
public void PlugOutGear()
{
// 拔出时齿轮停转
childGear.UpdateRotation(0, _speedScale);
childGear.transform.parent = null;
childGear = null;
GearSystem.ChangeGraphVertex(GetInstanceID());
}
public void ChangeRotateState()
{
UpdateSpeedAnima();
CheckGameState();
}
/// <summary>
/// 速度修改后改变动画(可能改变方向)
/// </summary>
private void UpdateSpeedAnima()
{
// 没有齿轮的不需要旋转
if (!HasChildGear())
{
return;
}
childGear.UpdateRotation(speed, _speedScale);
}
public void UpdateSpeedScale(float newSpeedScale)
{
_speedScale = newSpeedScale;
if (!HasChildGear()) return;
childGear.UpdateSpeedScale(_speedScale);
CheckGameState();
}
private void CheckGameState()
{
// 只有目标轴判断
if (shaftType != ShaftType.Target) return;
if (targetSpeed <= Mathf.Abs(speed * _speedScale))
{
GearSystem.ReachTargetSpeed();
}
else
{
GearSystem.ResetTargetState();
}
}
/// <summary>
/// 判断是否带齿轮
/// </summary>
/// <returns>是否带齿轮</returns>
public bool HasChildGear()
{
return childGear;
}
public void PopupGear()
{
// Constant无法弹出
// if (shaftType != ShaftType.Pluggable) return;
// 没有齿轮无法弹出
if (!childGear) return;
// 播放齿轮移除动画并更新速度
var gear = childGear;
PlugOutGear();
gear.Popup();
}
/// <summary>
/// 判断两个轴是否齿轮相接
/// </summary>
/// <param name="shaft1">轴1</param>
/// <param name="shaft2">轴2</param>
/// <returns>是否相接</returns>
public static bool IsShaftConnected(Shaft shaft1, Shaft shaft2)
{
// 如果轴上无齿轮就不计算
if (!shaft1 || !shaft2)
{
return false;
}
if (!shaft1.HasChildGear() || !shaft2.HasChildGear())
{
return false;
}
// 如果两个都有齿轮,就判断是否相邻
float distance = (shaft1.transform.position - shaft2.transform.position).magnitude;
float radiusSum = shaft1.GearRadius + shaft2.GearRadius;
return distance < radiusSum;
}
/// <summary>
/// 获取可以安装齿轮的最大尺寸
/// </summary>
/// <param name="sourcePos">源位置</param>
/// <param name="shaft">目标轴</param>
/// <returns>可用距离</returns>
public static float CalcShaftAvailableDis(Vector3 sourcePos, Shaft shaft)
{
if (!shaft.HasChildGear())
{
return (sourcePos - shaft.transform.position).magnitude;
}
else
{
return (sourcePos - shaft.transform.position).magnitude - shaft.GearRadius;
}
}
/// <summary>
/// 求两个轴角速度之比
/// </summary>
/// <param name="shaft1">轴1</param>
/// <param name="shaft2">轴2</param>
/// <returns>角速度之比</returns>
public static float CalcAngularVelocityRatio(Shaft shaft1, Shaft shaft2)
{
return shaft1.GearRadius / shaft2.GearRadius;
}
public void OnDestroy()
{
if (childGear != null)
{
childGear.transform.DOKill();
}
Destroy(childGear);
Destroy(gameObject);
}
public void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, initRadius);
}
#region 保存与加载
public void Load(ShaftLevelData levelData)
{
// 加载数据
gameObject.name = levelData.shaftName;
transform.localPosition = levelData.ShaftPos;
initSprite = levelData.GearPic;
shaftType = levelData.shaftType;
hasGear = levelData.hasChildGear;
gearProp = levelData.gearProp;
isInitGearBroken = levelData.isGearBroken;
isInitGearDisc = levelData.isDisc;
discIdx = levelData.discIdx;
targetSpeed = levelData.targetSpeed;
initRadius = levelData.radius;
}
public ShaftLevelData Save()
{
return new ShaftLevelData
{
shaftName = gameObject.name,
ShaftPos = transform.localPosition,
GearPic = initSprite,
shaftType = shaftType,
hasChildGear = hasGear,
gearProp = gearProp,
isGearBroken = isInitGearBroken,
isDisc = isInitGearDisc,
discIdx = discIdx,
targetSpeed = targetSpeed,
radius = initRadius
};
}
#endregion
}
public enum ShaftType
{
Driver, // 拥有初始速度,没有目标速度,全局仅有一个
Target, // 没有初始速度,有目标速度,全局有多个
Pluggable, // 没有初始速度,没有目标速度,可拔插
Constant // 固定齿轮不可插拔
}
[Serializable]
public struct ShaftLevelData
{
public string shaftName;
// 关卡数据
public ShaftType shaftType;
public float targetSpeed;
public bool hasChildGear;
public float radius;
public string gearProp;
public bool isGearBroken;
public bool isDisc;
public int discIdx;
// 外形数据
public SerializableVector3 shaftPos;
public string gearPicPath;
// 类型转换
[JsonIgnore]
public Sprite GearPic
{
get => !string.IsNullOrEmpty(gearPicPath) ? ResourceKit.LoadSpriteFromPsd(gearPicPath) : null;
set => gearPicPath = ResourceKit.SaveSprite(value);
}
[JsonIgnore]
public Vector3 ShaftPos
{
get => shaftPos.ToVector3();
set => shaftPos = new SerializableVector3(value);
}
}
}