using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using asap.core; using PlayFab.Internal; using Object = UnityEngine.Object; namespace UI.PartnerGather.Mining { [System.Serializable] public class TrainCar { public Transform carTransform; public Transform oreContainer; // 矿石收集容器 public Transform collectPoint; // 收集点 // public int pointsRange; // 对应的点数范围 (如 0-10, 10-20, 20-30, 30-40, 40+) public List collectedOres = new List(); public int maxCapacity = 10; public bool CanCollect(int points) { return collectedOres.Count < maxCapacity; } public void AddOre(GameObject ore) { if (oreContainer != null && ore != null) { ore.transform.SetParent(oreContainer); // 简单的堆叠布局 var count = collectedOres.Count; ore.transform.localPosition = new Vector3( (count % 3 - 1) * 0.5f, (count / 3) * 0.3f, 0f ); ore.transform.localScale = Vector3.one * 0.8f; collectedOres.Add(ore); } } public void ClearOres() { foreach (var ore in collectedOres) { if (ore != null) { Object.DestroyImmediate(ore); } } collectedOres.Clear(); } } /// /// 事件合作伙伴火车控制器 /// 管理火车车厢系统,包括矿石收集、车厢管理、矿石飞行动画等 /// 建议挂载在:Train容器对象上,确保包含所有车厢的Transform /// /// 场景结构建议: /// Train (挂载此脚本) /// ├── TrainCar1 (第一节车厢) /// │ └── OreContainer (矿石容器) /// ├── TrainCar2 (第二节车厢) /// │ └── OreContainer (矿石容器) /// └── ... (更多车厢) /// public class EventPartnerTrainController : MonoBehaviour { [Header("火车车厢配置")] public TrainCar[] trainCars = new TrainCar[5]; // 5节车厢 [Header("动画配置")] public float oreFlightDuration = 1f; public AnimationCurve oreFlightCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); [Header("移动目标(两种方式二选一)")] public Transform target; // 目标点(可选) public Vector3 targetWorldPos; // 备用的世界坐标目标点(当 target 为空时使用) public bool useTargetTransform = true; [Header("移动参数")] [Min(0.01f)] public float duration = 1f; // 总时长(秒) [Tooltip("位移归一化曲线:X=时间(0~1), Y=位移进度(0~1)。建议是S形:起点0,终点1,中间变快,末尾变慢。")] public AnimationCurve positionCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); [Header("调试/外观")] public bool autoStartOnPlay = false; // 勾选后在 Start 自动移动到目标 public Color gizmoColor = new Color(0.2f, 0.8f, 1f, 0.8f); // 运行时 private Vector3 _startPos; private Vector3 _endPos; private float _t; // 0~1 private bool _isMoving; private void Start() { InitializeTrainCars(); // 设一个合理的默认曲线(Slow -> Fast -> Stop),确保末尾Y=1停住 if (positionCurve == null || positionCurve.length < 2) { positionCurve = new AnimationCurve( new Keyframe(0f, 0f, 0f, 2f), // 起步慢 new Keyframe(0.5f, 0.8f, 1.5f, 1.5f), // 中段加速 new Keyframe(1f, 1f, 0f, 0f) // 末尾速度收敛到0 ); } // if (autoStartOnPlay) // { // Vector3 end = useTargetTransform && target != null ? target.position : targetWorldPos; // StartMoveTo(end); // } } private void Update() { if (!_isMoving) return; _t += Time.deltaTime / Mathf.Max(0.0001f, duration); float t01 = Mathf.Clamp01(_t); float p = positionCurve.Evaluate(t01); transform.position = Vector3.LerpUnclamped(_startPos, _endPos, p); if (_t >= 1f) { // 确保精确落点 transform.position = _endPos; _isMoving = false; } } // 开始从当前位置移动到目标世界坐标 public void StartMoveTo(Vector3 worldTarget) { _startPos = transform.position; _endPos = worldTarget; _t = 0f; _isMoving = true; } // public void StartMoveBy(Vector3 delta) { StartMoveTo(transform.position + delta); } // 重新设置目标(例如在运行时切换目标物体后调用) public void SetTarget(Transform newTarget) { target = newTarget; useTargetTransform = true; } // public async void MoveToDest(Vector3 targetPosition) // { // StartMoveTo(targetPosition); // } // 示例:在检视面板点击按钮的替代做法(可用ContextMenu手动触发) [ContextMenu("Move To Target Once")] private void Context_MoveToTarget() { Vector3 end = useTargetTransform && target != null ? target.position : targetWorldPos; StartMoveTo(end); } void OnDrawGizmosSelected() { Vector3 end = useTargetTransform && target != null ? target.position : targetWorldPos; Gizmos.color = gizmoColor; // 预览当前配置下的终点 Gizmos.DrawWireSphere(end, 0.15f); // 路径线 Gizmos.DrawLine(Application.isPlaying ? _startPos : transform.position, end); } private void InitializeTrainCars() { // 设置每节车厢对应的点数范围 for (var i = 0; i < trainCars.Length; i++) { if (trainCars[i] != null) { trainCars[i].pointsRange = (i + 1) * 100; } } } public async Task CollectOre(GameObject ore, int points) { Log("CollectOre"); if (ore == null) return; // 选择对应的车厢 var targetCar = SelectTargetCar(points); if (targetCar == null) return; // 矿石飞行动画 await AnimateOreFlight(ore, targetCar); // 添加到车厢 targetCar.AddOre(ore); } private TrainCar SelectTargetCar(int points) { // 根据点数选择对应的车厢 for (int i = 0; i < trainCars.Length; i++) { var car = trainCars[i]; if (car != null && car.CanCollect(points)) { // 简单的分配逻辑:按点数范围分配 if (points <= car.pointsRange) { return car; } } } // 如果没有合适的车厢,返回第一个有空间的车厢 foreach (var car in trainCars) { if (car != null && car.CanCollect(points)) { return car; } } return null; } private async Task AnimateOreFlight(GameObject ore, TrainCar targetCar) { if (ore == null || targetCar?.oreContainer == null) return; var startPos = ore.transform.position; var endPos = targetCar.collectPoint.position; // 添加抛物线轨迹 var midPos = (startPos + endPos) * 0.5f; midPos.y += 2f; // 抛物线高度 float t = 0f; while (t < oreFlightDuration) { t += Time.deltaTime / oreFlightDuration; var curveT = oreFlightCurve.Evaluate(t); // 贝塞尔曲线插值 var pos = CalculateBezierPoint(curveT, startPos, midPos, endPos); ore.transform.position = pos; // 旋转效果 ore.transform.Rotate(0, 0, 180 * Time.deltaTime / oreFlightDuration); await Awaiters.NextFrame; } ore.transform.position = endPos; } private static Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2) { var u = 1 - t; var tt = t * t; float uu = u * u; return uu * p0 + 2 * u * t * p1 + tt * p2; } public void ResetTrain() { foreach (var car in trainCars) { car?.ClearOres(); } } public int GetTotalCollectedOres() { int total = 0; foreach (var car in trainCars) { if (car != null) { total += car.collectedOres.Count; } } return total; } // private void Log(object t) { Debug.Log($" EventPartnerMiningSceneController {t} "); } } }