Files
back_cantanBuilding/Assets/Scripts/UI/PartnerGather/Mining/EventPartnerTrainController.cs
2026-05-26 16:15:54 +08:00

294 lines
9.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<GameObject> collectedOres = new List<GameObject>();
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();
}
}
/// <summary>
/// 事件合作伙伴火车控制器
/// 管理火车车厢系统,包括矿石收集、车厢管理、矿石飞行动画等
/// 建议挂载在Train容器对象上确保包含所有车厢的Transform
///
/// 场景结构建议:
/// Train (挂载此脚本)
/// ├── TrainCar1 (第一节车厢)
/// │ └── OreContainer (矿石容器)
/// ├── TrainCar2 (第二节车厢)
/// │ └── OreContainer (矿石容器)
/// └── ... (更多车厢)
/// </summary>
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($"<Color=cyan> EventPartnerMiningSceneController {t} </color>");
}
}
}