AK056/Assets/script/device/stacker/StackerDevice.cs
2025-05-07 11:20:40 +08:00

557 lines
17 KiB
C#

using EasyInject.Attributes;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
[GameObjectBean(ENameType.GameObjectName)]
public class StackerDevice : AbstractDevice
{
[SerializeField]
private StackerData stackerData;
private DeviceData deviceData;
[Header("前叉货叉光电描述")]
[SerializeField]
private string frontHasGoodsDesc;
[Autowired]
private LocationStorageManage storageManage;
[Autowired]
private ContainersManage containersManage;
[Autowired]
private StackerPopUI stackerPopUI;
[SerializeField]
private List<StackerForkActionBinding> forkActionBinding;
/// <summary>
/// 深浅伸叉动作映射
/// </summary>
[Header("深浅伸叉动作映射")]
[SerializeField]
private ForkActionMap forkActionMap;
/// <summary>
/// 上一次动作
/// </summary>
[SerializeField]
private StackerForkActionEnum lastforkActionEnum;
/// <summary>
/// 堆垛机移动的方向
/// </summary>
[SerializeField]
private Direction moveDirection = Direction.X;
[SerializeField]
private GameObject forkCargo;
[SerializeField]
private GameObject fork;
[SerializeField]
private Vector3 forkCargoOffset = Vector3.zero;
[Header("行走巷道内载货台高度偏移")]
[SerializeField]
private float isStorageforkCargoYOffset = 0.8f;
[Header("站台列载货台高度偏移")]
[SerializeField]
private float isDeviceforkCargoYOffset = -0.15f;
[SerializeField]
private float speed = 0.3f;
[SerializeField]
private float forkCargoUpOrDownSpeed = 0.3f;
[Header("载货台起升下降距离")]
[SerializeField]
private float LiftingAndLoweringDistance = 0.3f;
public override Transform Transform => forkCargo.transform;
public override string DeviceType => "STACKER";
public override string DeviceCode => name;
public override DeviceData DeviceData => deviceData;
private bool allowUpOrDown;
private float upOrDownSpeed;
private bool isOpenPop;
public enum Direction
{
Z,X
}
private PlayableDirector playableDirector;
/// <summary>
/// 所有动画轨道
/// </summary>
private List<TrackAsset> trackAssets = new();
private void Start()
{
playableDirector = transform.GetComponent<PlayableDirector>();
if(storageManage == null)
{
storageManage = ApplicationBoot.Instance.GetBean<LocationStorageManage>();
}
playableDirector.Stop();
StopActionClip();
var graph = playableDirector.playableAsset as TimelineAsset;
if (graph == null)
{
throw new Exception(name + ":未找到 TimelineAsset 资源");
}
trackAssets = new List<TrackAsset>(graph.GetRootTracks().ToArray());
}
private void Update()
{
//堆垛机本体移动
StackerBodyMove();
//载货台移动
ForkCargoVerticalMove();
//伸叉后起升或下降一段距离
ForkCargoUpOrDown();
//货叉动作执行
ExtendForkActionHandle();
}
private void ForkCargoUpOrDown()
{
if (!allowUpOrDown)
{
return;
}
forkCargo.transform.Translate(Vector3.up * upOrDownSpeed * forkCargoUpOrDownSpeed * Time.deltaTime);
}
/// <summary>
/// 堆垛机主体移动
/// </summary>
private void StackerBodyMove()
{
//排列成层 有其一值为0则不处理
if(stackerData.frontRow == 0 || stackerData.special1 == 0 || stackerData.frontLayer == 0)
{
return;
}
//获取库位坐标
string row = stackerData.frontRow.ToString("D2");
string column = stackerData.special1.ToString("D2");
string layer = stackerData.frontLayer.ToString("D2");
//当取货或方法是站台列,直接目的地就是站台列
if(stackerData.toColumn >= 200)
{
column = stackerData.toColumn.ToString();
layer = stackerData.toLayer.ToString("D2");
}
string storageName = string.Format("{0}-{1}-{2}", row, column, layer);
GameObject storageObject = storageManage.GetStorageByName(storageName);
if (storageObject == null)
{
throw new System.Exception(string.Format("【{1}】没有找到库位【{0}】坐标",storageName,name));
}
//解析堆垛机可用坐标
Vector3 target = Vector3.zero;
if (moveDirection == Direction.X)
{
target = new Vector3(storageObject.transform.position.x + forkCargoOffset.x,transform.position.y,transform.position.z);
}
if (moveDirection == Direction.Z)
{
target = new Vector3(transform.position.x, transform.position.y, storageObject.transform.position.z+ forkCargoOffset.z);
}
if(target == Vector3.zero)
{
return;
}
//往目标点移动
transform.position = Vector3.MoveTowards(transform.position,target, speed * Time.deltaTime);
}
/// <summary>
/// 载货台垂直移动
/// </summary>
private void ForkCargoVerticalMove()
{
//货叉动作是静止的才允许提升
if(StackerForkActionEnum.ForkRest == stackerData.frontForkAction )
{
//排列层 有其一值为0则不处理
//if (stackerData.frontRow == 0 || stackerData.special1 == 0 || stackerData.frontLayer == 0)
//{
// return;
//}
if (stackerData.toRow == 0 || stackerData.toColumn == 0 || stackerData.toLayer == 0)
{
return;
}
Vector3 target = ForkCargoTarget();
//往目标点移动
forkCargo.transform.position = Vector3.MoveTowards(forkCargo.transform.position, target, speed * Time.deltaTime);
}
}
private Vector3 ForkCargoTarget()
{
//获取库位坐标
string row = stackerData.toRow.ToString("D2");
string column = stackerData.toColumn.ToString("D2");
string layer = stackerData.toLayer.ToString("D2");
//当取货或方法是站台列,直接目的地就是站台列
//if (stackerData.toColumn >= 200)
//{
// column = stackerData.toColumn.ToString();
// layer = stackerData.toLayer.ToString("D2");
//}
string storageName = string.Format("{0}-{1}-{2}", row, column, layer);
GameObject storageObject = storageManage.GetStorageByName(storageName);
if (storageObject == null)
{
throw new System.Exception(string.Format("【{1}】没有找到库位【{0}】坐标", storageName, name));
}
//这里因为取货或者放货要保持抬起跟下降动作,增加额外值
float targetY = stackerData.frontForkHasGoods == true ? forkCargoOffset.y : 0;
float forkCargoBodyY = int.Parse(column) >= 200 ? isDeviceforkCargoYOffset : isStorageforkCargoYOffset;
//解析货叉可用坐标
Vector3 target = new Vector3(forkCargo.transform.position.x, storageObject.transform.position.y + forkCargoBodyY + targetY, forkCargo.transform.position.z);
return target;
}
/// <summary>
/// 货叉伸叉动作处理
/// </summary>
private void ExtendForkActionHandle()
{
//向左伸叉
if(stackerData.frontForkAction == StackerForkActionEnum.LeftExtendFork)
{
if(lastforkActionEnum != StackerForkActionEnum.LeftExtendFork)
{
//播放动画
PlayTrackGroup(GetForkActionName(StackerForkActionEnum.LeftExtendFork));
lastforkActionEnum = StackerForkActionEnum.LeftExtendFork;
}
}
//向右伸叉
if (stackerData.frontForkAction == StackerForkActionEnum.RightExtendFork)
{
if (lastforkActionEnum != StackerForkActionEnum.RightExtendFork)
{
//播放动画
string name = GetForkActionName(StackerForkActionEnum.RightExtendFork);
PlayTrackGroup(GetForkActionName(StackerForkActionEnum.RightExtendFork));
lastforkActionEnum = StackerForkActionEnum.RightExtendFork;
}
}
//向右缩叉
if (stackerData.frontForkAction == StackerForkActionEnum.RightRetractFork)
{
if (lastforkActionEnum != StackerForkActionEnum.RightRetractFork)
{
//缩动画播放之前,绑定容器
CheckAndBindContainer();
//继续播放
string name = GetForkActionName(StackerForkActionEnum.RightRetractFork);
PlayTrackGroup(name,false);
lastforkActionEnum = StackerForkActionEnum.RightRetractFork;
allowUpOrDown = true;
}
}
//向左缩叉
if (stackerData.frontForkAction == StackerForkActionEnum.LeftRetractFork)
{
if (lastforkActionEnum != StackerForkActionEnum.LeftRetractFork)
{
CheckAndBindContainer();
//继续播放
PlayTrackGroup(GetForkActionName(StackerForkActionEnum.LeftRetractFork), false);
lastforkActionEnum = StackerForkActionEnum.LeftRetractFork;
allowUpOrDown = true;
}
}
//清空货叉状态
if (stackerData.frontForkAction == StackerForkActionEnum.ForkRest)
{
if(lastforkActionEnum != StackerForkActionEnum.ForkRest)
{
lastforkActionEnum = StackerForkActionEnum.ForkRest;
//StopActionClip();
}
}
}
/// <summary>
/// 货叉缩叉动作完成处理(缩叉完成后自动触发)
/// </summary>
public void RetractForkActionFinishHandle()
{
//清空状态
//StopActionClip();
Debug.LogWarning("清理货叉状态");
}
/// <summary>
/// 货叉缩叉动作处理(当伸叉到位后会自动触发)
/// </summary>
public void ForkActionStopHandle(float speed)
{
//劫持动画,让其暂停
upOrDownSpeed = stackerData.frontForkHasGoods ? -speed*2 : speed;
playableDirector.Pause();
}
public void ForkActionStartHandle()
{
//开始动画
allowUpOrDown = false;
//针对放货
if (stackerData.frontForkHasGoods)
{
ForkBindContainer();
}
}
public void StopActionClip()
{
playableDirector.time = 0;
playableDirector.Stop();
foreach (var track in trackAssets)
{
track.muted = true;
}
}
/// <summary>
/// 绑定容器到货叉
/// </summary>
private void CheckAndBindContainer()
{
if (!allowUpOrDown && stackerData.frontForkHasGoods)
{
return;
}
ForkBindContainer();
}
private void ForkBindContainer()
{
//直接获取容器
Container container = containersManage.GetContainerByCode(stackerData.frontContainerCode);
Debug.Log(string.Format("容器号 【{0},场景实例 【{1}】】", stackerData.frontContainerCode, container));
if (container != null)
{
if (stackerData.frontForkHasGoods == true)
{
//绑定库位
string storageName = string.Format("{0}-{1}-{2}", stackerData.toRow.ToString("D2"), stackerData.toColumn.ToString("D2"), stackerData.toLayer.ToString("D2"));
GameObject storage = storageManage.GetStorageByName(storageName);
if (storage == null)
{
throw new Exception(string.Format("设备【{1}】未找到库位【{0}】",storageName,name));
}
if(stackerData.toColumn >= 200)
{
//暂停代理
container.Agent.isStopped = false;
//启用
container.Agent.enabled = true;
}
container.transform.parent = storage.transform;
}
else
{
//暂停代理
container.Agent.isStopped = true;
//清空身上代理路径
container.Agent.ResetPath();
//关闭唤醒状态
container.isAwke = false;
container.Agent.enabled = false;
//绑定到货叉
container.transform.parent = fork.transform;
Debug.LogWarning(name + ":绑定容器 =" + container);
}
}
}
private string GetForkActionName(StackerForkActionEnum forkActionEnum)
{
string row = stackerData.toRow.ToString("D2");
//左伸
if (StackerForkActionEnum.LeftExtendFork == forkActionEnum || StackerForkActionEnum.RightRetractFork == forkActionEnum)
{
//左浅
if (string.Equals(forkActionMap.leftShaollow, row))
{
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.leftPutShaollw : ForkActionNameConstant.leftTakeShaollw;
}
//左深
if (string.Equals(forkActionMap.leftDeeps, row))
{
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.leftPutDeep : ForkActionNameConstant.leftTakeDeep;
}
}
//右伸
if (StackerForkActionEnum.RightExtendFork == forkActionEnum || StackerForkActionEnum.LeftRetractFork == forkActionEnum)
{
//右浅
if (string.Equals(forkActionMap.rightShaollow, row))
{
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.RightPutShaollw : ForkActionNameConstant.RightTakeShaollw;
}
//右深
if (string.Equals(forkActionMap.rightDeeps, row))
{
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.RightPutDeep : ForkActionNameConstant.RightTakeDeep;
}
}
throw new Exception(name + ":未配置伸叉映射");
}
public override void MouseSingleClick()
{
base.MouseSingleClick();
isOpenPop = !isOpenPop;
stackerPopUI.Open(this, isOpenPop);
}
/// <summary>
/// 获取要播放动画名称
/// </summary>
/// <param name="actionEnum"></param>
/// <returns></returns>
private string GetActionAnimationName(StackerForkActionEnum actionEnum)
{
return forkActionBinding.Find(v => v.forkActionEnum == actionEnum).actionClipName;
}
public override void DataHandle(object data, object other = null)
{
//接收数据
stackerData = JsonConvert.DeserializeObject<StackerData>(JsonConvert.SerializeObject(data));
frontHasGoodsDesc = stackerData.frontForkHasGoods == true ? "前叉有货" : "无货";
deviceData = JsonConvert.DeserializeObject<DeviceData>(JsonConvert.SerializeObject(other));
}
public override void ProcessCompleted()
{
}
[System.Serializable]
public class StackerForkActionBinding
{
public StackerForkActionEnum forkActionEnum;
public string actionClipName;
}
/// <summary>
/// 播放分组
/// </summary>
private void PlayTrackGroup(string groupName, bool isRest = true)
{
var graph = playableDirector.playableAsset as TimelineAsset;
if (graph == null)
{
throw new Exception(name+":未找到 TimelineAsset 资源");
}
if (isRest)
{
List<TrackAsset> others = new List<TrackAsset>();
foreach (var track in trackAssets)
{
if (string.Equals(track.name, groupName))
{
track.muted = false;
foreach (var clip in track.GetClips())
{
}
}
else
{
others.Add(track);
}
}
//关闭其他动画
others.ForEach(v => v.muted = true);
playableDirector.Stop();
}
playableDirector.Play();
}
public override T DynamicData<T>()
{
return (T)(object)stackerData;
}
[System.Serializable]
public class ForkActionMap
{
public string leftShaollow;
public string leftDeeps;
public string rightShaollow;
public string rightDeeps;
}
/// <summary>
/// 堆垛机动作动画名称常量
/// </summary>
private class ForkActionNameConstant
{
/// <summary>
/// 左浅取货
/// </summary>
public static string leftTakeShaollw = "Lef_take_shallow";
/// <summary>
/// 左深取货
/// </summary>
public static string leftTakeDeep = "Lef_take_deep";
/// <summary>
/// 左浅放货
/// </summary>
public static string leftPutShaollw = "Left_put_shallow";
/// <summary>
/// 左深放货
/// </summary>
public static string leftPutDeep = "Left_put_deep";
/// <summary>
/// 右浅取货
/// </summary>
public static string RightTakeShaollw = "Right_take_shallow";
/// <summary>
/// 右深取货
/// </summary>
public static string RightTakeDeep = "Right_take_deep";
/// <summary>
/// 右浅放货
/// </summary>
public static string RightPutShaollw = "Right_put_shallow";
/// <summary>
/// 右深放货
/// </summary>
public static string RightPutDeep = "Right_put_deep";
public static string ForkCargoUp = "载货台上升";
public static string ForkCargoDown = "载货台下降";
}
}