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 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; /// /// 当前齿轮半径 /// public float GearRadius { get { if (!childGear) { return 0; } return childGear.radius; } } private GearSystem _gearSystem; private void Awake() { _gearSystem = transform.parent.parent.GetComponent(); } /// /// 初始化当前轴位置 /// public void InitShaft() { _gearSystem = transform.parent.parent.GetComponent(); // 如果不带齿轮 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.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 (transform.parent.name == "Shafts") { 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(); } /// /// 速度修改后改变动画(可能改变方向) /// 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(); } } /// /// 判断是否带齿轮 /// /// 是否带齿轮 public bool HasChildGear() { return childGear; } public void PopupGear() { // Constant无法弹出 // if (shaftType != ShaftType.Pluggable) return; // 没有齿轮无法弹出 if (!childGear) return; // 播放齿轮移除动画并更新速度 var gear = childGear; PlugOutGear(); gear.Popup(); } /// /// 判断两个轴是否齿轮相接 /// /// 轴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 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); } } }