using System; using AibisDream.Framework; using AibisDream.Utility; using DG.Tweening; using Newtonsoft.Json; using UnityEngine; namespace AibisDream { public class Shaft : MonoBehaviour { [SerializeField] private int id; [SerializeField] public ShaftType shaftType; // 初始齿轮 [SerializeField] private float initRadius; [SerializeField] private Sprite initSprite; [SerializeField] private bool hasGear; [SerializeField] private GameObject childGear; // 初始角速度 [SerializeField] private float initialSpeed; // 目标角速度 [SerializeField] private float targetSpeed; // 当前角速度 public float speed; public bool IsPluggable => shaftType is ShaftType.Pluggable or ShaftType.Driver or ShaftType.Target; /// /// 当前齿轮半径 /// public float GearRadius { get { if (!childGear) { return 0; } if (IsPluggable) { Gear gear = childGear.GetComponent(); return gear.radius; } return initRadius; } } private GearSystem _gearSystem; private void Awake() { _gearSystem = transform.parent.parent.GetComponent(); } /// /// 初始化当前轴位置 /// public void InitShaft() { // 如果不带齿轮 if (!hasGear) return; // 如果带齿轮,要根据齿轮类型生成 childGear = IsPluggable ? InitPluggableGear() : InitStaticGear(); speed = initialSpeed; UpdateSpeed(); } private GameObject InitStaticGear() { GameObject staticGear = transform.GetChild(0).gameObject; // 添加齿轮图片 staticGear.SetActive(true); var staticGearRenderer = staticGear.GetComponent(); staticGearRenderer.sprite = initSprite; staticGearRenderer.size = new Vector2(initRadius * 2, initRadius * 2); // 如果有初速,就要开始转动了 if (!CommonUtil.IsZero(initialSpeed)) { staticGear.transform.DORotate(new Vector3(0, 0, 360), 1 / initialSpeed, RotateMode.LocalAxisAdd) .SetEase(Ease.Linear).SetLoops(-1, LoopType.Incremental); } return staticGear; } private GameObject InitPluggableGear() { var gear = _gearSystem.InitGear(transform.position, initRadius, initSprite); gear.GetComponent().targetShaft = this; return gear; } public void PlugInGear(Gear gear) { childGear = gear.gameObject; _gearSystem.ChangeGraphVertex(GetInstanceID()); } public void PlugOutGear() { childGear = null; _gearSystem.ChangeGraphVertex(GetInstanceID()); } public void UpdateSpeed() { UpdateSpeedAnima(); CheckGameState(); } /// /// 速度修改后改变动画 /// private void UpdateSpeedAnima() { // 没有齿轮的不需要旋转 if (!HasChildGear()) { return; } if (CommonUtil.IsZero(speed)) { childGear.transform.DOPause(); return; } // 更新动画 childGear.transform.DOKill(); if (speed > 0) { childGear.transform.DORotate(new Vector3(0, 0, 360), 1 / speed, RotateMode.LocalAxisAdd) .SetEase(Ease.Linear).SetLoops(-1, LoopType.Incremental); } else { childGear.transform.DORotate(new Vector3(0, 0, -360), 1 / -speed, RotateMode.LocalAxisAdd) .SetEase(Ease.Linear).SetLoops(-1, LoopType.Incremental); } } private void CheckGameState() { if (shaftType == ShaftType.Target) { if (targetSpeed <= Mathf.Abs(speed)) { _gearSystem.Succeed(); } } } /// /// 判断是否带齿轮 /// /// 是否带齿轮 public bool HasChildGear() { return childGear; } /// /// 判断两个轴是否齿轮相接 /// /// 轴1 /// 轴2 /// 是否相接 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; } /// /// 获取可以安装齿轮的最大尺寸 /// /// 源位置 /// 目标轴 /// 可用距离 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; } } /// /// 求两个轴角速度之比 /// /// 轴1 /// 轴2 /// 角速度之比 public static float CalcAngularVelocityRatio(Shaft shaft1, Shaft shaft2) { return shaft1.GearRadius / shaft2.GearRadius; } 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; initialSpeed = levelData.initialSpeed; targetSpeed = levelData.targetSpeed; initRadius = levelData.radius; } public ShaftLevelData Save() { return new ShaftLevelData { shaftName = gameObject.name, ShaftPos = transform.localPosition, GearPic = initSprite, shaftType = shaftType, hasChildGear = hasGear, initialSpeed = initialSpeed, targetSpeed = targetSpeed, radius = initRadius }; } #endregion } public enum ShaftType { Driver, // 拥有初始速度,没有目标速度,全局仅有一个 Target, // 没有初始速度,有目标速度,全局有多个 Constant, // 没有初始速度,没有目标速度,不可拖动 Pluggable // 没有初始速度,没有目标速度,可拔插 } [Serializable] public struct ShaftLevelData { public string shaftName; // 关卡数据 public ShaftType shaftType; public float initialSpeed; public float targetSpeed; public bool hasChildGear; public float radius; // 外形数据 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); } } }